Index: trunk/src/VBox/Devices/Input/DevPS2.h
===================================================================
--- trunk/src/VBox/Devices/Input/DevPS2.h	(revision 89934)
+++ trunk/src/VBox/Devices/Input/DevPS2.h	(revision 89935)
@@ -89,8 +89,4 @@
 /** 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
 /** @} */
 
Index: trunk/src/VBox/Devices/Input/DevPS2K.cpp
===================================================================
--- trunk/src/VBox/Devices/Input/DevPS2K.cpp	(revision 89934)
+++ trunk/src/VBox/Devices/Input/DevPS2K.cpp	(revision 89935)
@@ -373,4 +373,34 @@
 };
 
+/* USB to PS/2 conversion table for Generic Desktop Control keys (HID Usage Page 1). */
+/* This usage page is tiny. */
+static const   ext_key_def  aPS2DCKeys[] = {
+    {0x81,   {0x5E, 0x37, UNKN, KF_E0, T_U}},   /* System Power */
+    {0x82,   {0x5F, 0x3F, UNKN, KF_E0, T_U}},   /* System Sleep */
+    {0x83,   {0x63, 0x5E, UNKN, KF_E0, T_U}},   /* System Wake */
+};
+
+/* We somehow need to keep track of depressed keys. To keep the array size
+ * under control, and because the number of defined keys isn't massive, we'd
+ * like to use an 8-bit index into the array.
+ * For the main USB HID usage page 7 (keyboard), we deal with 8-bit HID codes
+ * in the range from 0 to 0xE7, and use the HID codes directly.
+ * There's a convenient gap in the 0xA5-0xDF range. We use that to stuff the
+ * USB HID usage page 12 (consumer control) into the gap starting at 0xC0;
+ * the consumer control codes are from 0xB5 to 0x22A, but very sparse, with
+ * only 24 codes defined. We use the aPS2CCKeys array to generate our own
+ * code in the 0xC0-0xD7 range.
+ * For the tiny USB HID usage page 1 (generic desktop system) we use a similar
+ * approach, translating these to codes 0xB0 to 0xB2.
+ */
+
+#define PS2K_PAGE_DC_START      0xb0
+#define PS2K_PAGE_DC_END        (PS2K_PAGE_DC_START + RT_ELEMENTS(aPS2DCKeys))
+#define PS2K_PAGE_CC_START      0xc0
+#define PS2K_PAGE_CC_END        (PS2K_PAGE_CC_START + RT_ELEMENTS(aPS2CCKeys))
+
+AssertCompile(RT_ELEMENTS(aPS2CCKeys) <= 0x20); /* Must fit between 0xC0-0xDF. */
+AssertCompile(RT_ELEMENTS(aPS2DCKeys) <= 0x10); /* Must fit between 0xB0-0xBF. */
+
 #endif /* IN_RING3 */
 
@@ -681,4 +711,83 @@
 #ifdef IN_RING3
 
+static int ps2kR3HidToInternalCode(uint32_t u32HidCode, key_def const **ppKeyDef)
+{
+    uint8_t         u8HidPage;
+    uint16_t        u16HidUsage;
+    int             iKeyIndex = -1;
+    key_def const   *pKeyDef = &aPS2Keys[0];    /* Dummy no-event key. */;
+
+    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
+    u16HidUsage = RT_LOWORD(u32HidCode);
+
+    if (u8HidPage == USB_HID_KB_PAGE)
+    {
+        if (u16HidUsage <= VBOX_USB_MAX_USAGE_CODE)
+        {
+            iKeyIndex = u16HidUsage;    /* Direct mapping. */
+            pKeyDef   = iKeyIndex >= HID_MODIFIER_FIRST ? &aPS2ModKeys[iKeyIndex - HID_MODIFIER_FIRST] : &aPS2Keys[iKeyIndex];
+        }
+        else
+            AssertMsgFailed(("u16HidUsage out of range! (%04X)\n", u16HidUsage));
+    }
+    else if (u8HidPage == USB_HID_CC_PAGE)
+    {
+        for (int i = 0; i < RT_ELEMENTS(aPS2CCKeys); ++i)
+            if (aPS2CCKeys[i].usageId == u16HidUsage)
+            {
+                pKeyDef   = &aPS2CCKeys[i].kdef;
+                iKeyIndex = PS2K_PAGE_CC_START + i;
+                break;
+            }
+        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_CC_PAGE! (%04X)\n", u16HidUsage));
+    }
+    else if (u8HidPage == USB_HID_DC_PAGE)
+    {
+        for (int i = 0; i < RT_ELEMENTS(aPS2DCKeys); ++i)
+            if (aPS2CCKeys[i].usageId == u16HidUsage)
+            {
+                pKeyDef   = &aPS2DCKeys[i].kdef;
+                iKeyIndex = PS2K_PAGE_DC_START + i;
+                break;
+            }
+        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_DC_PAGE! (%04X)\n", u16HidUsage));
+    }
+    else
+    {
+        AssertMsgFailed(("Unsupported u8HidPage! (%02X)\n", u8HidPage));
+    }
+
+    if (ppKeyDef)
+        *ppKeyDef = pKeyDef;
+
+    return iKeyIndex;
+}
+
+static uint32_t ps2kR3InternalCodeToHid(int iKeyCode)
+{
+    uint16_t    u16HidUsage;
+    uint32_t    u32HidCode = 0;
+
+    if ((iKeyCode >= PS2K_PAGE_DC_START) && (iKeyCode <= PS2K_PAGE_DC_END))
+    {
+        u16HidUsage = aPS2DCKeys[iKeyCode - PS2K_PAGE_DC_START].usageId;
+        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_DC_PAGE);
+    }
+    else if ((iKeyCode >= PS2K_PAGE_CC_START) && (iKeyCode <= PS2K_PAGE_CC_END))
+    {
+        u16HidUsage = aPS2CCKeys[iKeyCode - PS2K_PAGE_CC_START].usageId;
+        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_CC_PAGE);
+    }
+    else    /* Must be the keyboard usage page. */
+    {
+        if (iKeyCode <= VBOX_USB_MAX_USAGE_CODE)
+            u32HidCode = RT_MAKE_U32(iKeyCode, USB_HID_KB_PAGE);
+        else
+            AssertMsgFailed(("iKeyCode out of range! (%d)\n", iKeyCode));
+    }
+
+    return u32HidCode;
+}
+
 static int ps2kR3ProcessKeyEvent(PPDMDEVINS pDevIns, PPS2K pThis, uint32_t u32HidCode, bool fKeyDown)
 {
@@ -689,38 +798,12 @@
     uint8_t         abScan[2];
     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. */
-    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. */
-        unsigned    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;
-    }
+    ps2kR3HidToInternalCode(u32HidCode, &pKeyDef);
 
     /* Some keys are not processed at all; early return. */
@@ -734,10 +817,9 @@
      * of their state in addition to sending the scan code.
      */
-    if (u8HidCode >= HID_MODIFIER_FIRST)
-    {
-        unsigned    mod_bit = 1 << (u8HidCode - HID_MODIFIER_FIRST);
-
-        Assert((u8HidPage == USB_HID_KB_PAGE));
-        Assert((u8HidCode <= HID_MODIFIER_LAST));
+    if ((u8HidPage == USB_HID_KB_PAGE) && (u16HidUsage >= HID_MODIFIER_FIRST))
+    {
+        unsigned    mod_bit = 1 << (u16HidUsage - HID_MODIFIER_FIRST);
+
+        Assert((u16HidUsage <= HID_MODIFIER_LAST));
         if (fKeyDown)
             pThis->u8Modifiers |= mod_bit;
@@ -1038,9 +1120,9 @@
     LogFlowFunc(("Releasing keys...\n"));
 
-    for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey)
-        if (pThis->abDepressedKeys[uKey])
+    for (int iKey = 0; iKey < sizeof(pThis->abDepressedKeys); ++iKey)
+        if (pThis->abDepressedKeys[iKey])
         {
-            ps2kR3ProcessKeyEvent(pDevIns, pThis, RT_MAKE_U32(USB_HID_KB_PAGE, uKey), false /* key up */);
-            pThis->abDepressedKeys[uKey] = 0;
+            ps2kR3ProcessKeyEvent(pDevIns, pThis, ps2kR3InternalCodeToHid(iKey), false /* key up */);
+            pThis->abDepressedKeys[iKey] = 0;
         }
     LogFlowFunc(("Done releasing keys\n"));
@@ -1092,19 +1174,15 @@
 {
     uint32_t        u32HidCode;
-    uint8_t         u8KeyCode;
-    uint8_t         u8HidPage;
     bool            fKeyDown;
     bool            fHaveEvent = true;
+    int             iKeyCode;
     int             rc = VINF_SUCCESS;
 
     /* Extract the usage page and ID and ensure it's valid. */
-    fKeyDown   = !(idUsage & UINT32_C(0x80000000));
+    fKeyDown   = !(idUsage & PDMIKBDPORT_KEY_UP);
     u32HidCode = idUsage & 0xFFFFFF;
-    u8HidPage  = RT_LOBYTE(RT_HIWORD(idUsage));
-    u8KeyCode  = RT_LOBYTE(idUsage);
-    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);
+
+    iKeyCode = ps2kR3HidToInternalCode(u32HidCode, NULL);
+    AssertReturn(iKeyCode > 0 && iKeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
 
     if (fKeyDown)
@@ -1112,7 +1190,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[u8KeyCode])
+        if (pThis->abDepressedKeys[iKeyCode])
             fHaveEvent = false;
-        pThis->abDepressedKeys[u8KeyCode] = 1;
+        pThis->abDepressedKeys[iKeyCode] = 1;
     }
     else
@@ -1121,5 +1199,5 @@
          * That is unlikely to happen and should not cause trouble.
          */
-        pThis->abDepressedKeys[u8KeyCode] = 0;
+        pThis->abDepressedKeys[iKeyCode] = 0;
     }
 
@@ -1153,5 +1231,5 @@
      * key is allowed to use this scancode.
      */
-    if (RT_LIKELY(idUsage != KRSP_BAT_FAIL))
+    if (RT_LIKELY(!(idUsage & PDMIKBDPORT_RELEASE_KEYS)))
         ps2kR3PutEventWorker(pDevIns, pThis, idUsage);
     else
@@ -1291,5 +1369,5 @@
     pHlp->pfnSSMGetU8(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;
+    pThis->u32TypematicKey = u8 ? ps2kR3InternalCodeToHid(u8) : 0;
     pHlp->pfnSSMGetU8(pSSM, &pThis->u8Modifiers);
     pHlp->pfnSSMGetU8(pSSM, &pThis->u8ScanSet);
Index: trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp
===================================================================
--- trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp	(revision 89934)
+++ trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp	(revision 89935)
@@ -32,6 +32,5 @@
 *********************************************************************************************************************************/
 /** Keyboard usage page bits to be OR-ed into the code. */
-#define HID_PG_KB_BITS  0x070000
-
+#define HID_PG_KB_BITS  RT_MAKE_U32(0, USB_HID_KB_PAGE)
 
 /*********************************************************************************************************************************
@@ -152,5 +151,5 @@
 
     /* Isolate the scan code and key break flag. */
-    keyUp = (scanCode & 0x80) << 24;
+    keyUp = (scanCode & 0x80) ? PDMIKBDPORT_KEY_UP : 0;
 
     switch (state) {
@@ -237,5 +236,5 @@
              * key up into a key up/key down sequence.
              */
-            if (idUsage == UINT32_C(0x80000090) || idUsage == UINT32_C(0x80000091))
+            if (idUsage == UINT32_C(PDMIKBDPORT_KEY_UP | 0x90) || idUsage == UINT32_C(PDMIKBDPORT_KEY_UP & 0x91))
             {
                 PDRVKBDQUEUEITEM pItem2 = (PDRVKBDQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
@@ -247,5 +246,5 @@
                 {
                     /* Manufacture a key down event. */
-                    pItem2->idUsage = idUsage & ~UINT32_C(0x80000000);
+                    pItem2->idUsage = idUsage & ~PDMIKBDPORT_KEY_UP;
                     PDMQueueInsert(pDrv->pQueue, &pItem2->Core);
                 }
@@ -289,4 +288,36 @@
     if (!pDrv->fSuspended)
         AssertMsgFailed(("drvKbdQueuePutEventHid: Queue is full!!!!\n"));
+    return VERR_PDM_NO_QUEUE_ITEMS;
+}
+
+
+/**
+ * @interface_method_impl{PDMIKEYBOARDPORT,pfnReleaseKeys}
+ *
+ * Because of the event queueing the EMT context requirement is lifted.
+ * @thread  Any thread.
+ */
+static DECLCALLBACK(int) drvKbdQueueReleaseKeys(PPDMIKEYBOARDPORT pInterface)
+{
+    PDRVKBDQUEUE pDrv = IKEYBOARDPORT_2_DRVKBDQUEUE(pInterface);
+
+    /* Ignore any attempt to send events if queue is inactive. */
+    if (pDrv->fInactive)
+        return VINF_SUCCESS;
+
+    PDRVKBDQUEUEITEM pItem = (PDRVKBDQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
+    if (pItem)
+    {
+        /* Send a special key event that forces all keys to be released.
+         * Goes through the queue so that it would take effect only after
+         * any key events that might already be queued up.
+         */
+        pItem->idUsage = PDMIKBDPORT_RELEASE_KEYS | HID_PG_KB_BITS;
+        PDMQueueInsert(pDrv->pQueue, &pItem->Core);
+
+        return VINF_SUCCESS;
+    }
+    if (!pDrv->fSuspended)
+        AssertMsgFailed(("drvKbdQueueReleaseKeys: Queue is full!!!!\n"));
     return VERR_PDM_NO_QUEUE_ITEMS;
 }
@@ -457,4 +488,5 @@
     pDrv->IPort.pfnPutEventScan             = drvKbdQueuePutEventScan;
     pDrv->IPort.pfnPutEventHid              = drvKbdQueuePutEventHid;
+    pDrv->IPort.pfnReleaseKeys              = drvKbdQueueReleaseKeys;
 
     /*
Index: trunk/src/VBox/Devices/Input/UsbKbd.cpp
===================================================================
--- trunk/src/VBox/Devices/Input/UsbKbd.cpp	(revision 89934)
+++ trunk/src/VBox/Devices/Input/UsbKbd.cpp	(revision 89935)
@@ -381,7 +381,147 @@
 
 
+/**
+ * Conversion table for consumer control keys (HID Usage Page 12).
+ * Used to 'compress' the USB HID usage code into a single 8-bit
+ * value. See also PS2CCKeys in the PS/2 keyboard emulation.
+ */
+static const    uint16_t aHidCCKeys[] = {
+    0x00B5, /* Scan Next Track */
+    0x00B6, /* Scan Previous Track */
+    0x00B7, /* Stop */
+    0x00CD, /* Play/Pause */
+    0x00E2, /* Mute */
+    0x00E5, /* Bass Boost */
+    0x00E7, /* Loudness */
+    0x00E9, /* Volume Up */
+    0x00EA, /* Volume Down */
+    0x0152, /* Bass Up */
+    0x0153, /* Bass Down */
+    0x0154, /* Treble Up */
+    0x0155, /* Treble Down */
+    0x0183, /* Media Select  */
+    0x018A, /* Mail */
+    0x0192, /* Calculator */
+    0x0194, /* My Computer */
+    0x0221, /* WWW Search */
+    0x0223, /* WWW Home */
+    0x0224, /* WWW Back */
+    0x0225, /* WWW Forward */
+    0x0226, /* WWW Stop */
+    0x0227, /* WWW Refresh */
+    0x022A, /* WWW Favorites */
+};
+
+/**
+ * Conversion table for generic desktop control keys (HID Usage Page 1).
+ * Used to 'compress' the USB HID usage code into a single 8-bit
+ * value. See also PS2DCKeys in the PS/2 keyboard emulation.
+ */
+static const    uint16_t aHidDCKeys[] = {
+    0x81,   /* System Power */
+    0x82,   /* System Sleep */
+    0x83,   /* System Wake */
+};
+
+#define USBHID_PAGE_DC_START    0xb0
+#define USBHID_PAGE_DC_END      (USBHID_PAGE_DC_START + RT_ELEMENTS(aHidDCKeys))
+#define USBHID_PAGE_CC_START    0xc0
+#define USBHID_PAGE_CC_END      (USBHID_PAGE_CC_START + RT_ELEMENTS(aHidCCKeys))
+
+AssertCompile(RT_ELEMENTS(aHidCCKeys) <= 0x20); /* Must fit between 0xC0-0xDF. */
+AssertCompile(RT_ELEMENTS(aHidDCKeys) <= 0x10); /* Must fit between 0xB0-0xBF. */
+
+
 /*********************************************************************************************************************************
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
+
+
+/**
+ * Converts a 32-bit USB HID code to an internal 8-bit value.
+ *
+ * @returns 8-bit internal key code/index. -1 if not found.
+ * @param   u32HidCode          32-bit USB HID code.
+ */
+static int usbHidToInternalCode(uint32_t u32HidCode)
+{
+    uint8_t         u8HidPage;
+    uint16_t        u16HidUsage;
+    int             iKeyIndex = -1;
+
+    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
+    u16HidUsage = RT_LOWORD(u32HidCode);
+
+    if (u8HidPage == USB_HID_KB_PAGE)
+    {
+        if (u16HidUsage <= VBOX_USB_MAX_USAGE_CODE)
+            iKeyIndex = u16HidUsage;    /* Direct mapping. */
+        else
+            AssertMsgFailed(("u16HidUsage out of range! (%04X)\n", u16HidUsage));
+    }
+    else if (u8HidPage == USB_HID_CC_PAGE)
+    {
+        for (int i = 0; i < RT_ELEMENTS(aHidCCKeys); ++i)
+            if (aHidCCKeys[i] == u16HidUsage)
+            {
+                iKeyIndex = USBHID_PAGE_CC_START + i;
+                break;
+            }
+        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_CC_PAGE! (%04X)\n", u16HidUsage));
+    }
+    else if (u8HidPage == USB_HID_DC_PAGE)
+    {
+        for (int i = 0; i < RT_ELEMENTS(aHidDCKeys); ++i)
+            if (aHidCCKeys[i] == u16HidUsage)
+            {
+                iKeyIndex = USBHID_PAGE_DC_START + i;
+                break;
+            }
+        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_DC_PAGE! (%04X)\n", u16HidUsage));
+    }
+    else
+    {
+        AssertMsgFailed(("Unsupported u8HidPage! (%02X)\n", u8HidPage));
+    }
+
+    /** @todo: We can currently only report the standard HID keyboard page.*/
+    if (u8HidPage != USB_HID_KB_PAGE)
+        return -1;
+
+    return iKeyIndex;
+}
+
+
+/**
+ * Converts an internal 8-bit key index back to a 32-bit USB HID code.
+ *
+ * @returns 32-bit USB HID code. Zero if not found.
+ * @param   u32HidCode          32-bit USB HID code.
+ */
+static uint32_t usbInternalCodeToHid(int iKeyCode)
+{
+    uint16_t    u16HidUsage;
+    uint32_t    u32HidCode = 0;
+
+    if ((iKeyCode >= USBHID_PAGE_DC_START) && (iKeyCode <= USBHID_PAGE_DC_END))
+    {
+        u16HidUsage = aHidDCKeys[iKeyCode - USBHID_PAGE_DC_START];
+        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_DC_PAGE);
+    }
+    else if ((iKeyCode >= USBHID_PAGE_CC_START) && (iKeyCode <= USBHID_PAGE_CC_END))
+    {
+        u16HidUsage = aHidCCKeys[iKeyCode - USBHID_PAGE_CC_START];
+        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_CC_PAGE);
+    }
+    else    /* Must be the keyboard usage page. */
+    {
+        if (iKeyCode <= VBOX_USB_MAX_USAGE_CODE)
+            u32HidCode = RT_MAKE_U32(iKeyCode, USB_HID_KB_PAGE);
+        else
+            AssertMsgFailed(("iKeyCode out of range! (%d)\n", iKeyCode));
+    }
+
+    return u32HidCode;
+}
 
 
@@ -629,6 +769,14 @@
             else
             {
-                pReport->aKeys[iBuf] = iKey;
-                ++iBuf;
+                /* Key index back to 32-bit HID code. */
+                uint32_t    u32HidCode  = usbInternalCodeToHid(iKey);
+                uint8_t     u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
+                uint8_t     u16HidUsage = RT_LOWORD(u32HidCode);
+
+                if (u8HidPage == USB_HID_KB_PAGE)
+                {
+                    pReport->aKeys[iBuf] = (uint8_t)u16HidUsage;
+                    ++iBuf;
+                }
             }
         }
@@ -696,7 +844,4 @@
 }
 
-/* See the PS2K device. */
-#define KRSP_BAT_FAIL       0xFC    /* Also a 'release keys' signal. */
-
 /**
  * @interface_method_impl{PDMIKEYBOARDPORT,pfnPutEventHid}
@@ -705,17 +850,18 @@
 {
     PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
-    uint8_t     u8HidCode;
     bool        fKeyDown;
     bool        fHaveEvent = true;
     int         rc = VINF_SUCCESS;
+    int         iKeyCode;
 
     /* Let's see what we got... */
-    fKeyDown  = !(idUsage & UINT32_C(0x80000000));
-    u8HidCode = idUsage & 0xFF;
-    AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
+    fKeyDown  = !(idUsage & PDMIKBDPORT_KEY_UP);
+
+    iKeyCode = usbHidToInternalCode(idUsage);
+    AssertReturn(iKeyCode > 0 && iKeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
 
     RTCritSectEnter(&pThis->CritSect);
 
-    LogFlowFunc(("key %s: 0x%x\n", fKeyDown ? "down" : "up", u8HidCode));
+    LogFlowFunc(("key %s: %08X (iKeyCode 0x%x)\n", fKeyDown ? "down" : "up", idUsage, iKeyCode));
 
     /*
@@ -723,5 +869,5 @@
      * already depressed. Drop those right here.
      */
-    if (fKeyDown && pThis->abDepressedKeys[u8HidCode])
+    if (fKeyDown && pThis->abDepressedKeys[iKeyCode])
         fHaveEvent = false;
 
@@ -733,11 +879,11 @@
     else if (fHaveEvent)
     {
-        if (RT_LIKELY(idUsage != KRSP_BAT_FAIL))
+        if (RT_LIKELY(!(idUsage & PDMIKBDPORT_RELEASE_KEYS)))
         {
             /* Regular key event - update keyboard state. */
             if (fKeyDown)
-                pThis->abDepressedKeys[u8HidCode] = 1;
+                pThis->abDepressedKeys[iKeyCode] = 1;
             else
-                pThis->abDepressedKeys[u8HidCode] = 0;
+                pThis->abDepressedKeys[iKeyCode] = 0;
         }
         else
Index: trunk/src/VBox/Main/src-client/KeyboardImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/KeyboardImpl.cpp	(revision 89934)
+++ trunk/src/VBox/Main/src-client/KeyboardImpl.cpp	(revision 89935)
@@ -296,8 +296,28 @@
 HRESULT Keyboard::releaseKeys()
 {
-    std::vector<LONG> scancodes;
-    scancodes.resize(1);
-    scancodes[0] = 0xFC;    /* Magic scancode, see PS/2 and USB keyboard devices. */
-    return putScancodes(scancodes, NULL);
+    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+    /* Release all keys on the active keyboard in order to start with a clean slate.
+     * Note that this should mirror the logic in Keyboard::putScancodes() when choosing
+     * which keyboard to send the release event to.
+     */
+    PPDMIKEYBOARDPORT pUpPort = NULL;
+    for (int i = KEYBOARD_MAX_DEVICES - 1; i >= 0 ; --i)
+    {
+        if (mpDrv[i] && (mpDrv[i]->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
+        {
+            pUpPort = mpDrv[i]->pUpPort;
+            break;
+        }
+    }
+
+    if (pUpPort)
+    {
+        int rc = pUpPort->pfnReleaseKeys(pUpPort);
+        if (RT_FAILURE(rc))
+            AssertMsgFailed(("Failed to release keys on all keyboards! rc=%Rrc\n", rc));
+    }
+
+    return S_OK;
 }
 
@@ -352,4 +372,9 @@
 {
     PDRVMAINKEYBOARD pDrv = RT_FROM_MEMBER(pInterface, DRVMAINKEYBOARD, IConnector);
+
+    // Before activating a different keyboard, release all keys on the currently active one.
+    if (fActive)
+        pDrv->pKeyboard->releaseKeys();
+
     if (fActive)
         pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED;
