Index: /trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp
===================================================================
--- /trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp	(revision 81213)
+++ /trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp	(revision 81214)
@@ -27,4 +27,10 @@
 #include "VBoxDD.h"
 
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** Keyboard usage page bits to be OR-ed into the code. */
+#define HID_PG_KB_BITS  0x070000
 
 
@@ -156,5 +162,5 @@
         } else {
             usage = aScancode2Hid[scanCode & 0x7F];
-            *pUsage = usage | keyUp;
+            *pUsage = usage | keyUp | HID_PG_KB_BITS;
             /* Remain in SS_IDLE state. */
         }
@@ -162,5 +168,5 @@
     case SS_EXT:
         usage = aExtScan2Hid[scanCode & 0x7F];
-        *pUsage = usage | keyUp;
+        *pUsage = usage | keyUp | HID_PG_KB_BITS;
         state = SS_IDLE;
         break;
@@ -170,5 +176,5 @@
          */
         if ((scanCode & 0x7F) == 0x45) {
-            *pUsage = 0x48;
+            *pUsage = 0x48 | HID_PG_KB_BITS;
             if (scanCode == 0xC5)
                 *pUsage |= keyUp;
Index: /trunk/src/VBox/Devices/Input/PS2K.cpp
===================================================================
--- /trunk/src/VBox/Devices/Input/PS2K.cpp	(revision 81213)
+++ /trunk/src/VBox/Devices/Input/PS2K.cpp	(revision 81214)
@@ -98,4 +98,8 @@
 /** The size of an array needed to store all USB usage codes */
 #define VBOX_USB_USAGE_ARRAY_SIZE   (VBOX_USB_MAX_USAGE_CODE + 1)
+/** USB HID Keyboard Usage Page. */
+#define USB_HID_KB_PAGE             7
+/** USB HID Consumer Control Usage Page. */
+#define USB_HID_CC_PAGE             12
 /** @} */
 
@@ -158,5 +162,5 @@
 {
     /** Pointer to parent device (keyboard controller). */
-    R3PTRTYPE(void *)     pParent;
+    R3PTRTYPE(void *)   pParent;
     /** Set if keyboard is enabled ('scans' for input). */
     bool                fScanning;
@@ -174,5 +178,5 @@
     uint8_t             u8TypematicCfg;
     /** Usage code of current typematic key, if any. */
-    uint8_t             u8TypematicKey;
+    uint32_t            u32TypematicKey;
     /** Current typematic repeat state. */
     tmatic_state_t      enmTypematicState;
@@ -277,5 +281,5 @@
 *********************************************************************************************************************************/
 #ifdef IN_RING3
-/* USB to PS/2 conversion table for regular keys. */
+/* USB to PS/2 conversion table for regular keys (HID Usage Page 7). */
 static const   key_def   aPS2Keys[] = {
     /* 00 */ {NONE, NONE, NONE, KF_NB, T_U }, /* Key N/A: No Event */
@@ -459,5 +463,5 @@
  */
 
-/* USB to PS/2 conversion table for modifier keys. */
+/* USB to PS/2 conversion table for modifier keys (HID Usage Page 7). */
 static const   key_def   aPS2ModKeys[] = {
     /* E0 */ {0x1D, 0x14, 0x11,     0, T_B }, /* Key  58: Left Control */
@@ -471,4 +475,40 @@
 };
 
+/* Extended key definition for sparse mapping. */
+typedef struct {
+    uint16_t    usageId;
+    key_def     kdef;
+} ext_key_def;
+
+
+/* USB to PS/2 conversion table for consumer control keys (HID Usage Page 12). */
+/* This usage page is very sparse so we'll just search through it. */
+static const   ext_key_def  aPS2CCKeys[] = {
+    0x00B5, {0x19, 0x4D, UNKN, KF_E0, T_U }, /* Scan Next Track */
+    0x00B6, {0x10, 0x15, UNKN, KF_E0, T_U }, /* Scan Previous Track */
+    0x00B7, {0x24, 0x3B, UNKN, KF_E0, T_U }, /* Stop */
+    0x00CD, {0x22, 0x34, UNKN, KF_E0, T_U }, /* Play/Pause */
+    0x00E2, {0x20, 0x23, UNKN, KF_E0, T_U }, /* Mute */
+    0x00E5, {UNAS, UNAS, UNAS,     0, T_U }, /* Bass Boost */
+    0x00E7, {UNAS, UNAS, UNAS,     0, T_U }, /* Loudness */
+    0x00E9, {0x30, 0x32, UNKN, KF_E0, T_U }, /* Volume Up */
+    0x00EA, {0x2E, 0x21, UNKN, KF_E0, T_U }, /* Volume Down */
+    0x0152, {UNAS, UNAS, UNAS,     0, T_U }, /* Bass Up */
+    0x0153, {UNAS, UNAS, UNAS,     0, T_U }, /* Bass Down */
+    0x0154, {UNAS, UNAS, UNAS,     0, T_U }, /* Treble Up */
+    0x0155, {UNAS, UNAS, UNAS,     0, T_U }, /* Treble Down */
+    0x0183, {0x6D, 0x50, UNKN, KF_E0, T_U }, /* Media Select  */
+    0x018A, {0x6C, 0x48, UNKN, KF_E0, T_U }, /* Mail */
+    0x0192, {0x21, 0x2B, UNKN, KF_E0, T_U }, /* Calculator */
+    0x0194, {0x6B, 0x40, UNKN, KF_E0, T_U }, /* My Computer */
+    0x0221, {0x65, 0x10, UNKN, KF_E0, T_U }, /* WWW Search */
+    0x0223, {0x32, 0x3A, UNKN, KF_E0, T_U }, /* WWW Home */
+    0x0224, {0x6A, 0x38, UNKN, KF_E0, T_U }, /* WWW Back */
+    0x0225, {0x69, 0x30, UNKN, KF_E0, T_U }, /* WWW Forward */
+    0x0226, {0x68, 0x28, UNKN, KF_E0, T_U }, /* WWW Stop */
+    0x0227, {0x67, 0x20, UNKN, KF_E0, T_U }, /* WWW Refresh */
+    0x022A, {0x66, 0x18, UNKN, KF_E0, T_U }, /* WWW Favorites */
+};
+
 #endif /* IN_RING3 */
 
@@ -661,9 +701,9 @@
 static void ps2kStopTypematicRepeat(PPS2K pThis)
 {
-    if (pThis->u8TypematicKey)
-    {
-        LogFunc(("Typematic key %02X\n", pThis->u8TypematicKey));
+    if (pThis->u32TypematicKey)
+    {
+        LogFunc(("Typematic key %08X\n", pThis->u32TypematicKey));
         pThis->enmTypematicState = KBD_TMS_IDLE;
-        pThis->u8TypematicKey = 0;
+        pThis->u32TypematicKey = 0;
         TMTimerStop(pThis->CTX_SUFF(pKbdTypematicTimer));
     }
@@ -866,5 +906,5 @@
 #ifdef IN_RING3
 
-static int ps2kProcessKeyEvent(PPS2K pThis, uint8_t u8HidCode, bool fKeyDown)
+static int ps2kProcessKeyEvent(PPS2K pThis, uint32_t u32HidCode, bool fKeyDown)
 {
     key_def const   *pKeyDef;
@@ -873,9 +913,39 @@
     size_t          cbLeft;
     uint8_t         abScan[2];
-
-    LogFlowFunc(("key %s: 0x%02x (set %d)\n", fKeyDown ? "down" : "up", u8HidCode, pThis->u8ScanSet));
+    uint8_t         u8HidPage;
+    uint8_t         u8HidCode;
+    uint16_t        u16HidUsage;
+
+    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
+    u16HidUsage = RT_LOWORD(u32HidCode);
+    /* For the keyboard usage page (7) we use a 8-bit code. For other pages we use the full 16-bit ID. */
+    u8HidCode   = (u8HidPage == USB_HID_KB_PAGE) ? RT_LOBYTE(u32HidCode) : 0;
+
+    LogFlowFunc(("key %s: page 0x%02x ID 0x%04x (set %d)\n", fKeyDown ? "down" : "up", u8HidPage, u16HidUsage, pThis->u8ScanSet));
 
     /* Find the key definition in somewhat sparse storage. */
-    pKeyDef = u8HidCode >= HID_MODIFIER_FIRST ? &aPS2ModKeys[u8HidCode - HID_MODIFIER_FIRST] : &aPS2Keys[u8HidCode];
+    if (u8HidPage == USB_HID_KB_PAGE)
+        /* For the standard keyboard usage page, thre are just two arrays. */
+        pKeyDef = u8HidCode >= HID_MODIFIER_FIRST ? &aPS2ModKeys[u8HidCode - HID_MODIFIER_FIRST] : &aPS2Keys[u8HidCode];
+    else if (u8HidPage == USB_HID_CC_PAGE)
+    {
+        /* For the consumer control usage page, we need to search. */
+        int     i;
+
+        pKeyDef = &aPS2Keys[0]; /* Dummy no-event key. */
+        for (i = 0; i < RT_ELEMENTS(aPS2CCKeys); ++i)
+        {
+            if (aPS2CCKeys[i].usageId == u16HidUsage)
+            {
+                pKeyDef = &aPS2CCKeys[i].kdef;
+                break;
+            }
+        }
+    }
+    else
+    {
+        LogFlow(("Unsupported HID usage page, ignoring key.\n"));
+        return VINF_SUCCESS;
+    }
 
     /* Some keys are not processed at all; early return. */
@@ -893,4 +963,5 @@
         unsigned    mod_bit = 1 << (u8HidCode - HID_MODIFIER_FIRST);
 
+        Assert((u8HidPage == USB_HID_KB_PAGE));
         Assert((u8HidCode <= HID_MODIFIER_LAST));
         if (fKeyDown)
@@ -1060,29 +1131,32 @@
     }
 
-    /* Set up or cancel typematic key repeat. */
-    if (fKeyDown)
-    {
-        if (pThis->u8TypematicKey != u8HidCode)
+    /* Set up or cancel typematic key repeat. For keyboard usage page only. */
+    if (u8HidPage == USB_HID_KB_PAGE)
+    {
+        if (fKeyDown)
         {
-            pThis->enmTypematicState = KBD_TMS_DELAY;
-            pThis->u8TypematicKey    = u8HidCode;
-            TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicDelay);
-            Log(("Typematic delay %u ms, key %02X\n", pThis->uTypematicDelay, u8HidCode));
+            if (pThis->u32TypematicKey != u32HidCode)
+            {
+                pThis->enmTypematicState = KBD_TMS_DELAY;
+                pThis->u32TypematicKey   = u32HidCode;
+                TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicDelay);
+                Log(("Typematic delay %u ms, key %08X\n", pThis->uTypematicDelay, u32HidCode));
+            }
         }
-    }
-    else
-    {
-        /* "Typematic operation stops when the last key pressed is released, even
-         * if other keys are still held down." (IBM PS/2 Tech Ref). The last key pressed
-         * is the one that's being repeated.
-         */
-        if (pThis->u8TypematicKey == u8HidCode)
+        else
         {
-            /* This disables the typematic repeat. */
-            pThis->u8TypematicKey    = 0;
-            pThis->enmTypematicState = KBD_TMS_IDLE;
-            /* For good measure, we cancel the timer, too. */
-            TMTimerStop(pThis->CTX_SUFF(pKbdTypematicTimer));
-            Log(("Typematic action cleared for key %02X\n", u8HidCode));
+            /* "Typematic operation stops when the last key pressed is released, even
+             * if other keys are still held down." (IBM PS/2 Tech Ref). The last key pressed
+             * is the one that's being repeated.
+             */
+            if (pThis->u32TypematicKey == u32HidCode)
+            {
+                /* This disables the typematic repeat. */
+                pThis->u32TypematicKey   = 0;
+                pThis->enmTypematicState = KBD_TMS_IDLE;
+                /* For good measure, we cancel the timer, too. */
+                TMTimerStop(pThis->CTX_SUFF(pKbdTypematicTimer));
+                Log(("Typematic action cleared for key %08X\n", u32HidCode));
+            }
         }
     }
@@ -1134,10 +1208,10 @@
     RT_NOREF2(pDevIns, pTimer);
     PPS2K pThis = (PS2K *)pvUser;
-    LogFlowFunc(("Typematic state=%d, key %02X\n", pThis->enmTypematicState, pThis->u8TypematicKey));
+    LogFlowFunc(("Typematic state=%d, key %08X\n", pThis->enmTypematicState, pThis->u32TypematicKey));
 
     /* If the current typematic key is zero, the repeat was canceled just when
      * the timer was about to run. In that case, do nothing.
      */
-    if (pThis->u8TypematicKey)
+    if (pThis->u32TypematicKey)
     {
         if (pThis->enmTypematicState == KBD_TMS_DELAY)
@@ -1146,5 +1220,5 @@
         if (pThis->enmTypematicState == KBD_TMS_REPEAT)
         {
-            ps2kProcessKeyEvent(pThis, pThis->u8TypematicKey, true /* Key down */ );
+            ps2kProcessKeyEvent(pThis, pThis->u32TypematicKey, true /* Key down */ );
             TMTimerSetMillies(pThis->CTX_SUFF(pKbdTypematicTimer), pThis->uTypematicRepeat);
         }
@@ -1183,5 +1257,5 @@
         if (pThis->abDepressedKeys[uKey])
         {
-            ps2kProcessKeyEvent(pThis, uKey, false /* key up */);
+            ps2kProcessKeyEvent(pThis, RT_MAKE_U32(USB_HID_KB_PAGE, uKey), false /* key up */);
             pThis->abDepressedKeys[uKey] = 0;
         }
@@ -1214,5 +1288,5 @@
                     pThis->keyQ.cUsed, pThis->keyQ.cSize);
     if (pThis->enmTypematicState != KBD_TMS_IDLE)
-        pHlp->pfnPrintf(pHlp, "Active typematic key %02X (%s)\n", pThis->u8TypematicKey,
+        pHlp->pfnPrintf(pHlp, "Active typematic key %08X (%s)\n", pThis->u32TypematicKey,
                         pThis->enmTypematicState == KBD_TMS_DELAY ? "delay" : "repeat");
 }
@@ -1244,13 +1318,20 @@
 static int ps2kPutEventWorker(PPS2K pThis, uint32_t u32Usage)
 {
-    uint8_t         u8HidCode;
+    uint32_t        u32HidCode;
+    uint8_t         u8KeyCode;
+    uint8_t         u8HidPage;
     bool            fKeyDown;
     bool            fHaveEvent = true;
     int             rc = VINF_SUCCESS;
 
-    /* Extract the usage code and ensure it's valid. */
-    fKeyDown = !(u32Usage & 0x80000000);
-    u8HidCode = u32Usage & 0xFF;
-    AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
+    /* Extract the usage page and ID and ensure it's valid. */
+    fKeyDown   = !(u32Usage & 0x80000000);
+    u32HidCode = u32Usage & 0xFFFFFF;
+    u8HidPage  = RT_LOBYTE(RT_HIWORD(u32Usage));
+    u8KeyCode  = RT_LOBYTE(u32Usage);
+    if (u8HidPage == USB_HID_KB_PAGE)
+        AssertReturn(u8KeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
+    else
+        AssertReturn(u8HidPage == USB_HID_CC_PAGE, VERR_INTERNAL_ERROR);
 
     if (fKeyDown)
@@ -1258,7 +1339,7 @@
         /* Due to host key repeat, we can get key events for keys which are
          * already depressed. We need to ignore those. */
-        if (pThis->abDepressedKeys[u8HidCode])
+        if (pThis->abDepressedKeys[u8KeyCode])
             fHaveEvent = false;
-        pThis->abDepressedKeys[u8HidCode] = 1;
+        pThis->abDepressedKeys[u8KeyCode] = 1;
     }
     else
@@ -1267,5 +1348,5 @@
          * That is unlikely to happen and should not cause trouble.
          */
-        pThis->abDepressedKeys[u8HidCode] = 0;
+        pThis->abDepressedKeys[u8KeyCode] = 0;
     }
 
@@ -1276,5 +1357,5 @@
         AssertReleaseRC(rc);
 
-        rc = ps2kProcessKeyEvent(pThis, u8HidCode, fKeyDown);
+        rc = ps2kProcessKeyEvent(pThis, u32HidCode, fKeyDown);
 
         PDMCritSectLeave(pThis->pCritSectR3);
@@ -1371,5 +1452,5 @@
     SSMR3PutU8(pSSM, pThis->u8LEDs);
     SSMR3PutU8(pSSM, pThis->u8TypematicCfg);
-    SSMR3PutU8(pSSM, pThis->u8TypematicKey);
+    SSMR3PutU8(pSSM, (uint8_t)pThis->u32TypematicKey);
     SSMR3PutU8(pSSM, pThis->u8Modifiers);
     SSMR3PutU8(pSSM, pThis->u8ScanSet);
@@ -1419,5 +1500,7 @@
     SSMR3GetU8(pSSM, &pThis->u8LEDs);
     SSMR3GetU8(pSSM, &pThis->u8TypematicCfg);
-    SSMR3GetU8(pSSM, &pThis->u8TypematicKey);
+    SSMR3GetU8(pSSM, &u8);
+    /* Reconstruct the 32-bit code from the 8-bit value in saved state. */
+    pThis->u32TypematicKey = u8 ? RT_MAKE_U32(USB_HID_KB_PAGE, u8) : 0;
     SSMR3GetU8(pSSM, &pThis->u8Modifiers);
     SSMR3GetU8(pSSM, &pThis->u8ScanSet);
@@ -1489,5 +1572,5 @@
     pThis->u8CurrCmd         = 0;
     pThis->u8Modifiers       = 0;
-    pThis->u8TypematicKey    = 0;
+    pThis->u32TypematicKey   = 0;
     pThis->enmTypematicState = KBD_TMS_IDLE;
 
