VirtualBox

Changeset 89935 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 29, 2021 6:38:48 AM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
145393
Message:

Keyboard: Reworked the release-all-keys mechanism, made sure it's used before switching active keyboard, avoided potential mix-ups when tracking depressed keys (see bugref:10045).

Location:
trunk/src/VBox
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Input/DevPS2.h

    r83443 r89935  
    8989/** The size of an array needed to store all USB usage codes */
    9090#define VBOX_USB_USAGE_ARRAY_SIZE   (VBOX_USB_MAX_USAGE_CODE + 1)
    91 /** USB HID Keyboard Usage Page. */
    92 #define USB_HID_KB_PAGE             7
    93 /** USB HID Consumer Control Usage Page. */
    94 #define USB_HID_CC_PAGE             12
    9591/** @} */
    9692
  • trunk/src/VBox/Devices/Input/DevPS2K.cpp

    r89812 r89935  
    373373};
    374374
     375/* USB to PS/2 conversion table for Generic Desktop Control keys (HID Usage Page 1). */
     376/* This usage page is tiny. */
     377static const   ext_key_def  aPS2DCKeys[] = {
     378    {0x81,   {0x5E, 0x37, UNKN, KF_E0, T_U}},   /* System Power */
     379    {0x82,   {0x5F, 0x3F, UNKN, KF_E0, T_U}},   /* System Sleep */
     380    {0x83,   {0x63, 0x5E, UNKN, KF_E0, T_U}},   /* System Wake */
     381};
     382
     383/* We somehow need to keep track of depressed keys. To keep the array size
     384 * under control, and because the number of defined keys isn't massive, we'd
     385 * like to use an 8-bit index into the array.
     386 * For the main USB HID usage page 7 (keyboard), we deal with 8-bit HID codes
     387 * in the range from 0 to 0xE7, and use the HID codes directly.
     388 * There's a convenient gap in the 0xA5-0xDF range. We use that to stuff the
     389 * USB HID usage page 12 (consumer control) into the gap starting at 0xC0;
     390 * the consumer control codes are from 0xB5 to 0x22A, but very sparse, with
     391 * only 24 codes defined. We use the aPS2CCKeys array to generate our own
     392 * code in the 0xC0-0xD7 range.
     393 * For the tiny USB HID usage page 1 (generic desktop system) we use a similar
     394 * approach, translating these to codes 0xB0 to 0xB2.
     395 */
     396
     397#define PS2K_PAGE_DC_START      0xb0
     398#define PS2K_PAGE_DC_END        (PS2K_PAGE_DC_START + RT_ELEMENTS(aPS2DCKeys))
     399#define PS2K_PAGE_CC_START      0xc0
     400#define PS2K_PAGE_CC_END        (PS2K_PAGE_CC_START + RT_ELEMENTS(aPS2CCKeys))
     401
     402AssertCompile(RT_ELEMENTS(aPS2CCKeys) <= 0x20); /* Must fit between 0xC0-0xDF. */
     403AssertCompile(RT_ELEMENTS(aPS2DCKeys) <= 0x10); /* Must fit between 0xB0-0xBF. */
     404
    375405#endif /* IN_RING3 */
    376406
     
    681711#ifdef IN_RING3
    682712
     713static int ps2kR3HidToInternalCode(uint32_t u32HidCode, key_def const **ppKeyDef)
     714{
     715    uint8_t         u8HidPage;
     716    uint16_t        u16HidUsage;
     717    int             iKeyIndex = -1;
     718    key_def const   *pKeyDef = &aPS2Keys[0];    /* Dummy no-event key. */;
     719
     720    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
     721    u16HidUsage = RT_LOWORD(u32HidCode);
     722
     723    if (u8HidPage == USB_HID_KB_PAGE)
     724    {
     725        if (u16HidUsage <= VBOX_USB_MAX_USAGE_CODE)
     726        {
     727            iKeyIndex = u16HidUsage;    /* Direct mapping. */
     728            pKeyDef   = iKeyIndex >= HID_MODIFIER_FIRST ? &aPS2ModKeys[iKeyIndex - HID_MODIFIER_FIRST] : &aPS2Keys[iKeyIndex];
     729        }
     730        else
     731            AssertMsgFailed(("u16HidUsage out of range! (%04X)\n", u16HidUsage));
     732    }
     733    else if (u8HidPage == USB_HID_CC_PAGE)
     734    {
     735        for (int i = 0; i < RT_ELEMENTS(aPS2CCKeys); ++i)
     736            if (aPS2CCKeys[i].usageId == u16HidUsage)
     737            {
     738                pKeyDef   = &aPS2CCKeys[i].kdef;
     739                iKeyIndex = PS2K_PAGE_CC_START + i;
     740                break;
     741            }
     742        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_CC_PAGE! (%04X)\n", u16HidUsage));
     743    }
     744    else if (u8HidPage == USB_HID_DC_PAGE)
     745    {
     746        for (int i = 0; i < RT_ELEMENTS(aPS2DCKeys); ++i)
     747            if (aPS2CCKeys[i].usageId == u16HidUsage)
     748            {
     749                pKeyDef   = &aPS2DCKeys[i].kdef;
     750                iKeyIndex = PS2K_PAGE_DC_START + i;
     751                break;
     752            }
     753        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_DC_PAGE! (%04X)\n", u16HidUsage));
     754    }
     755    else
     756    {
     757        AssertMsgFailed(("Unsupported u8HidPage! (%02X)\n", u8HidPage));
     758    }
     759
     760    if (ppKeyDef)
     761        *ppKeyDef = pKeyDef;
     762
     763    return iKeyIndex;
     764}
     765
     766static uint32_t ps2kR3InternalCodeToHid(int iKeyCode)
     767{
     768    uint16_t    u16HidUsage;
     769    uint32_t    u32HidCode = 0;
     770
     771    if ((iKeyCode >= PS2K_PAGE_DC_START) && (iKeyCode <= PS2K_PAGE_DC_END))
     772    {
     773        u16HidUsage = aPS2DCKeys[iKeyCode - PS2K_PAGE_DC_START].usageId;
     774        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_DC_PAGE);
     775    }
     776    else if ((iKeyCode >= PS2K_PAGE_CC_START) && (iKeyCode <= PS2K_PAGE_CC_END))
     777    {
     778        u16HidUsage = aPS2CCKeys[iKeyCode - PS2K_PAGE_CC_START].usageId;
     779        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_CC_PAGE);
     780    }
     781    else    /* Must be the keyboard usage page. */
     782    {
     783        if (iKeyCode <= VBOX_USB_MAX_USAGE_CODE)
     784            u32HidCode = RT_MAKE_U32(iKeyCode, USB_HID_KB_PAGE);
     785        else
     786            AssertMsgFailed(("iKeyCode out of range! (%d)\n", iKeyCode));
     787    }
     788
     789    return u32HidCode;
     790}
     791
    683792static int ps2kR3ProcessKeyEvent(PPDMDEVINS pDevIns, PPS2K pThis, uint32_t u32HidCode, bool fKeyDown)
    684793{
     
    689798    uint8_t         abScan[2];
    690799    uint8_t         u8HidPage;
    691     uint8_t         u8HidCode;
    692800    uint16_t        u16HidUsage;
    693801
    694802    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
    695803    u16HidUsage = RT_LOWORD(u32HidCode);
    696     /* For the keyboard usage page (7) we use a 8-bit code. For other pages we use the full 16-bit ID. */
    697     u8HidCode   = (u8HidPage == USB_HID_KB_PAGE) ? RT_LOBYTE(u32HidCode) : 0;
    698804
    699805    LogFlowFunc(("key %s: page 0x%02x ID 0x%04x (set %d)\n", fKeyDown ? "down" : "up", u8HidPage, u16HidUsage, pThis->u8ScanSet));
    700806
    701     /* Find the key definition in somewhat sparse storage. */
    702     if (u8HidPage == USB_HID_KB_PAGE)
    703         /* For the standard keyboard usage page, thre are just two arrays. */
    704         pKeyDef = u8HidCode >= HID_MODIFIER_FIRST ? &aPS2ModKeys[u8HidCode - HID_MODIFIER_FIRST] : &aPS2Keys[u8HidCode];
    705     else if (u8HidPage == USB_HID_CC_PAGE)
    706     {
    707         /* For the consumer control usage page, we need to search. */
    708         unsigned    i;
    709 
    710         pKeyDef = &aPS2Keys[0]; /* Dummy no-event key. */
    711         for (i = 0; i < RT_ELEMENTS(aPS2CCKeys); ++i)
    712         {
    713             if (aPS2CCKeys[i].usageId == u16HidUsage)
    714             {
    715                 pKeyDef = &aPS2CCKeys[i].kdef;
    716                 break;
    717             }
    718         }
    719     }
    720     else
    721     {
    722         LogFlow(("Unsupported HID usage page, ignoring key.\n"));
    723         return VINF_SUCCESS;
    724     }
     807    ps2kR3HidToInternalCode(u32HidCode, &pKeyDef);
    725808
    726809    /* Some keys are not processed at all; early return. */
     
    734817     * of their state in addition to sending the scan code.
    735818     */
    736     if (u8HidCode >= HID_MODIFIER_FIRST)
    737     {
    738         unsigned    mod_bit = 1 << (u8HidCode - HID_MODIFIER_FIRST);
    739 
    740         Assert((u8HidPage == USB_HID_KB_PAGE));
    741         Assert((u8HidCode <= HID_MODIFIER_LAST));
     819    if ((u8HidPage == USB_HID_KB_PAGE) && (u16HidUsage >= HID_MODIFIER_FIRST))
     820    {
     821        unsigned    mod_bit = 1 << (u16HidUsage - HID_MODIFIER_FIRST);
     822
     823        Assert((u16HidUsage <= HID_MODIFIER_LAST));
    742824        if (fKeyDown)
    743825            pThis->u8Modifiers |= mod_bit;
     
    10381120    LogFlowFunc(("Releasing keys...\n"));
    10391121
    1040     for (unsigned uKey = 0; uKey < sizeof(pThis->abDepressedKeys); ++uKey)
    1041         if (pThis->abDepressedKeys[uKey])
     1122    for (int iKey = 0; iKey < sizeof(pThis->abDepressedKeys); ++iKey)
     1123        if (pThis->abDepressedKeys[iKey])
    10421124        {
    1043             ps2kR3ProcessKeyEvent(pDevIns, pThis, RT_MAKE_U32(USB_HID_KB_PAGE, uKey), false /* key up */);
    1044             pThis->abDepressedKeys[uKey] = 0;
     1125            ps2kR3ProcessKeyEvent(pDevIns, pThis, ps2kR3InternalCodeToHid(iKey), false /* key up */);
     1126            pThis->abDepressedKeys[iKey] = 0;
    10451127        }
    10461128    LogFlowFunc(("Done releasing keys\n"));
     
    10921174{
    10931175    uint32_t        u32HidCode;
    1094     uint8_t         u8KeyCode;
    1095     uint8_t         u8HidPage;
    10961176    bool            fKeyDown;
    10971177    bool            fHaveEvent = true;
     1178    int             iKeyCode;
    10981179    int             rc = VINF_SUCCESS;
    10991180
    11001181    /* Extract the usage page and ID and ensure it's valid. */
    1101     fKeyDown   = !(idUsage & UINT32_C(0x80000000));
     1182    fKeyDown   = !(idUsage & PDMIKBDPORT_KEY_UP);
    11021183    u32HidCode = idUsage & 0xFFFFFF;
    1103     u8HidPage  = RT_LOBYTE(RT_HIWORD(idUsage));
    1104     u8KeyCode  = RT_LOBYTE(idUsage);
    1105     if (u8HidPage == USB_HID_KB_PAGE)
    1106         AssertReturn(u8KeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
    1107     else
    1108         AssertReturn(u8HidPage == USB_HID_CC_PAGE, VERR_INTERNAL_ERROR);
     1184
     1185    iKeyCode = ps2kR3HidToInternalCode(u32HidCode, NULL);
     1186    AssertReturn(iKeyCode > 0 && iKeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
    11091187
    11101188    if (fKeyDown)
     
    11121190        /* Due to host key repeat, we can get key events for keys which are
    11131191         * already depressed. We need to ignore those. */
    1114         if (pThis->abDepressedKeys[u8KeyCode])
     1192        if (pThis->abDepressedKeys[iKeyCode])
    11151193            fHaveEvent = false;
    1116         pThis->abDepressedKeys[u8KeyCode] = 1;
     1194        pThis->abDepressedKeys[iKeyCode] = 1;
    11171195    }
    11181196    else
     
    11211199         * That is unlikely to happen and should not cause trouble.
    11221200         */
    1123         pThis->abDepressedKeys[u8KeyCode] = 0;
     1201        pThis->abDepressedKeys[iKeyCode] = 0;
    11241202    }
    11251203
     
    11531231     * key is allowed to use this scancode.
    11541232     */
    1155     if (RT_LIKELY(idUsage != KRSP_BAT_FAIL))
     1233    if (RT_LIKELY(!(idUsage & PDMIKBDPORT_RELEASE_KEYS)))
    11561234        ps2kR3PutEventWorker(pDevIns, pThis, idUsage);
    11571235    else
     
    12911369    pHlp->pfnSSMGetU8(pSSM, &u8);
    12921370    /* Reconstruct the 32-bit code from the 8-bit value in saved state. */
    1293     pThis->u32TypematicKey = u8 ? RT_MAKE_U32(USB_HID_KB_PAGE, u8) : 0;
     1371    pThis->u32TypematicKey = u8 ? ps2kR3InternalCodeToHid(u8) : 0;
    12941372    pHlp->pfnSSMGetU8(pSSM, &pThis->u8Modifiers);
    12951373    pHlp->pfnSSMGetU8(pSSM, &pThis->u8ScanSet);
  • trunk/src/VBox/Devices/Input/DrvKeyboardQueue.cpp

    r89831 r89935  
    3232*********************************************************************************************************************************/
    3333/** Keyboard usage page bits to be OR-ed into the code. */
    34 #define HID_PG_KB_BITS  0x070000
    35 
     34#define HID_PG_KB_BITS  RT_MAKE_U32(0, USB_HID_KB_PAGE)
    3635
    3736/*********************************************************************************************************************************
     
    152151
    153152    /* Isolate the scan code and key break flag. */
    154     keyUp = (scanCode & 0x80) << 24;
     153    keyUp = (scanCode & 0x80) ? PDMIKBDPORT_KEY_UP : 0;
    155154
    156155    switch (state) {
     
    237236             * key up into a key up/key down sequence.
    238237             */
    239             if (idUsage == UINT32_C(0x80000090) || idUsage == UINT32_C(0x80000091))
     238            if (idUsage == UINT32_C(PDMIKBDPORT_KEY_UP | 0x90) || idUsage == UINT32_C(PDMIKBDPORT_KEY_UP & 0x91))
    240239            {
    241240                PDRVKBDQUEUEITEM pItem2 = (PDRVKBDQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
     
    247246                {
    248247                    /* Manufacture a key down event. */
    249                     pItem2->idUsage = idUsage & ~UINT32_C(0x80000000);
     248                    pItem2->idUsage = idUsage & ~PDMIKBDPORT_KEY_UP;
    250249                    PDMQueueInsert(pDrv->pQueue, &pItem2->Core);
    251250                }
     
    289288    if (!pDrv->fSuspended)
    290289        AssertMsgFailed(("drvKbdQueuePutEventHid: Queue is full!!!!\n"));
     290    return VERR_PDM_NO_QUEUE_ITEMS;
     291}
     292
     293
     294/**
     295 * @interface_method_impl{PDMIKEYBOARDPORT,pfnReleaseKeys}
     296 *
     297 * Because of the event queueing the EMT context requirement is lifted.
     298 * @thread  Any thread.
     299 */
     300static DECLCALLBACK(int) drvKbdQueueReleaseKeys(PPDMIKEYBOARDPORT pInterface)
     301{
     302    PDRVKBDQUEUE pDrv = IKEYBOARDPORT_2_DRVKBDQUEUE(pInterface);
     303
     304    /* Ignore any attempt to send events if queue is inactive. */
     305    if (pDrv->fInactive)
     306        return VINF_SUCCESS;
     307
     308    PDRVKBDQUEUEITEM pItem = (PDRVKBDQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
     309    if (pItem)
     310    {
     311        /* Send a special key event that forces all keys to be released.
     312         * Goes through the queue so that it would take effect only after
     313         * any key events that might already be queued up.
     314         */
     315        pItem->idUsage = PDMIKBDPORT_RELEASE_KEYS | HID_PG_KB_BITS;
     316        PDMQueueInsert(pDrv->pQueue, &pItem->Core);
     317
     318        return VINF_SUCCESS;
     319    }
     320    if (!pDrv->fSuspended)
     321        AssertMsgFailed(("drvKbdQueueReleaseKeys: Queue is full!!!!\n"));
    291322    return VERR_PDM_NO_QUEUE_ITEMS;
    292323}
     
    457488    pDrv->IPort.pfnPutEventScan             = drvKbdQueuePutEventScan;
    458489    pDrv->IPort.pfnPutEventHid              = drvKbdQueuePutEventHid;
     490    pDrv->IPort.pfnReleaseKeys              = drvKbdQueueReleaseKeys;
    459491
    460492    /*
  • trunk/src/VBox/Devices/Input/UsbKbd.cpp

    r82968 r89935  
    381381
    382382
     383/**
     384 * Conversion table for consumer control keys (HID Usage Page 12).
     385 * Used to 'compress' the USB HID usage code into a single 8-bit
     386 * value. See also PS2CCKeys in the PS/2 keyboard emulation.
     387 */
     388static const    uint16_t aHidCCKeys[] = {
     389    0x00B5, /* Scan Next Track */
     390    0x00B6, /* Scan Previous Track */
     391    0x00B7, /* Stop */
     392    0x00CD, /* Play/Pause */
     393    0x00E2, /* Mute */
     394    0x00E5, /* Bass Boost */
     395    0x00E7, /* Loudness */
     396    0x00E9, /* Volume Up */
     397    0x00EA, /* Volume Down */
     398    0x0152, /* Bass Up */
     399    0x0153, /* Bass Down */
     400    0x0154, /* Treble Up */
     401    0x0155, /* Treble Down */
     402    0x0183, /* Media Select  */
     403    0x018A, /* Mail */
     404    0x0192, /* Calculator */
     405    0x0194, /* My Computer */
     406    0x0221, /* WWW Search */
     407    0x0223, /* WWW Home */
     408    0x0224, /* WWW Back */
     409    0x0225, /* WWW Forward */
     410    0x0226, /* WWW Stop */
     411    0x0227, /* WWW Refresh */
     412    0x022A, /* WWW Favorites */
     413};
     414
     415/**
     416 * Conversion table for generic desktop control keys (HID Usage Page 1).
     417 * Used to 'compress' the USB HID usage code into a single 8-bit
     418 * value. See also PS2DCKeys in the PS/2 keyboard emulation.
     419 */
     420static const    uint16_t aHidDCKeys[] = {
     421    0x81,   /* System Power */
     422    0x82,   /* System Sleep */
     423    0x83,   /* System Wake */
     424};
     425
     426#define USBHID_PAGE_DC_START    0xb0
     427#define USBHID_PAGE_DC_END      (USBHID_PAGE_DC_START + RT_ELEMENTS(aHidDCKeys))
     428#define USBHID_PAGE_CC_START    0xc0
     429#define USBHID_PAGE_CC_END      (USBHID_PAGE_CC_START + RT_ELEMENTS(aHidCCKeys))
     430
     431AssertCompile(RT_ELEMENTS(aHidCCKeys) <= 0x20); /* Must fit between 0xC0-0xDF. */
     432AssertCompile(RT_ELEMENTS(aHidDCKeys) <= 0x10); /* Must fit between 0xB0-0xBF. */
     433
     434
    383435/*********************************************************************************************************************************
    384436*   Internal Functions                                                                                                           *
    385437*********************************************************************************************************************************/
     438
     439
     440/**
     441 * Converts a 32-bit USB HID code to an internal 8-bit value.
     442 *
     443 * @returns 8-bit internal key code/index. -1 if not found.
     444 * @param   u32HidCode          32-bit USB HID code.
     445 */
     446static int usbHidToInternalCode(uint32_t u32HidCode)
     447{
     448    uint8_t         u8HidPage;
     449    uint16_t        u16HidUsage;
     450    int             iKeyIndex = -1;
     451
     452    u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
     453    u16HidUsage = RT_LOWORD(u32HidCode);
     454
     455    if (u8HidPage == USB_HID_KB_PAGE)
     456    {
     457        if (u16HidUsage <= VBOX_USB_MAX_USAGE_CODE)
     458            iKeyIndex = u16HidUsage;    /* Direct mapping. */
     459        else
     460            AssertMsgFailed(("u16HidUsage out of range! (%04X)\n", u16HidUsage));
     461    }
     462    else if (u8HidPage == USB_HID_CC_PAGE)
     463    {
     464        for (int i = 0; i < RT_ELEMENTS(aHidCCKeys); ++i)
     465            if (aHidCCKeys[i] == u16HidUsage)
     466            {
     467                iKeyIndex = USBHID_PAGE_CC_START + i;
     468                break;
     469            }
     470        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_CC_PAGE! (%04X)\n", u16HidUsage));
     471    }
     472    else if (u8HidPage == USB_HID_DC_PAGE)
     473    {
     474        for (int i = 0; i < RT_ELEMENTS(aHidDCKeys); ++i)
     475            if (aHidCCKeys[i] == u16HidUsage)
     476            {
     477                iKeyIndex = USBHID_PAGE_DC_START + i;
     478                break;
     479            }
     480        AssertMsg(iKeyIndex > -1, ("Unsupported code in USB_HID_DC_PAGE! (%04X)\n", u16HidUsage));
     481    }
     482    else
     483    {
     484        AssertMsgFailed(("Unsupported u8HidPage! (%02X)\n", u8HidPage));
     485    }
     486
     487    /** @todo: We can currently only report the standard HID keyboard page.*/
     488    if (u8HidPage != USB_HID_KB_PAGE)
     489        return -1;
     490
     491    return iKeyIndex;
     492}
     493
     494
     495/**
     496 * Converts an internal 8-bit key index back to a 32-bit USB HID code.
     497 *
     498 * @returns 32-bit USB HID code. Zero if not found.
     499 * @param   u32HidCode          32-bit USB HID code.
     500 */
     501static uint32_t usbInternalCodeToHid(int iKeyCode)
     502{
     503    uint16_t    u16HidUsage;
     504    uint32_t    u32HidCode = 0;
     505
     506    if ((iKeyCode >= USBHID_PAGE_DC_START) && (iKeyCode <= USBHID_PAGE_DC_END))
     507    {
     508        u16HidUsage = aHidDCKeys[iKeyCode - USBHID_PAGE_DC_START];
     509        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_DC_PAGE);
     510    }
     511    else if ((iKeyCode >= USBHID_PAGE_CC_START) && (iKeyCode <= USBHID_PAGE_CC_END))
     512    {
     513        u16HidUsage = aHidCCKeys[iKeyCode - USBHID_PAGE_CC_START];
     514        u32HidCode  = RT_MAKE_U32(u16HidUsage, USB_HID_CC_PAGE);
     515    }
     516    else    /* Must be the keyboard usage page. */
     517    {
     518        if (iKeyCode <= VBOX_USB_MAX_USAGE_CODE)
     519            u32HidCode = RT_MAKE_U32(iKeyCode, USB_HID_KB_PAGE);
     520        else
     521            AssertMsgFailed(("iKeyCode out of range! (%d)\n", iKeyCode));
     522    }
     523
     524    return u32HidCode;
     525}
    386526
    387527
     
    629769            else
    630770            {
    631                 pReport->aKeys[iBuf] = iKey;
    632                 ++iBuf;
     771                /* Key index back to 32-bit HID code. */
     772                uint32_t    u32HidCode  = usbInternalCodeToHid(iKey);
     773                uint8_t     u8HidPage   = RT_LOBYTE(RT_HIWORD(u32HidCode));
     774                uint8_t     u16HidUsage = RT_LOWORD(u32HidCode);
     775
     776                if (u8HidPage == USB_HID_KB_PAGE)
     777                {
     778                    pReport->aKeys[iBuf] = (uint8_t)u16HidUsage;
     779                    ++iBuf;
     780                }
    633781            }
    634782        }
     
    696844}
    697845
    698 /* See the PS2K device. */
    699 #define KRSP_BAT_FAIL       0xFC    /* Also a 'release keys' signal. */
    700 
    701846/**
    702847 * @interface_method_impl{PDMIKEYBOARDPORT,pfnPutEventHid}
     
    705850{
    706851    PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
    707     uint8_t     u8HidCode;
    708852    bool        fKeyDown;
    709853    bool        fHaveEvent = true;
    710854    int         rc = VINF_SUCCESS;
     855    int         iKeyCode;
    711856
    712857    /* Let's see what we got... */
    713     fKeyDown  = !(idUsage & UINT32_C(0x80000000));
    714     u8HidCode = idUsage & 0xFF;
    715     AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
     858    fKeyDown  = !(idUsage & PDMIKBDPORT_KEY_UP);
     859
     860    iKeyCode = usbHidToInternalCode(idUsage);
     861    AssertReturn(iKeyCode > 0 && iKeyCode <= VBOX_USB_MAX_USAGE_CODE, VERR_INTERNAL_ERROR);
    716862
    717863    RTCritSectEnter(&pThis->CritSect);
    718864
    719     LogFlowFunc(("key %s: 0x%x\n", fKeyDown ? "down" : "up", u8HidCode));
     865    LogFlowFunc(("key %s: %08X (iKeyCode 0x%x)\n", fKeyDown ? "down" : "up", idUsage, iKeyCode));
    720866
    721867    /*
     
    723869     * already depressed. Drop those right here.
    724870     */
    725     if (fKeyDown && pThis->abDepressedKeys[u8HidCode])
     871    if (fKeyDown && pThis->abDepressedKeys[iKeyCode])
    726872        fHaveEvent = false;
    727873
     
    733879    else if (fHaveEvent)
    734880    {
    735         if (RT_LIKELY(idUsage != KRSP_BAT_FAIL))
     881        if (RT_LIKELY(!(idUsage & PDMIKBDPORT_RELEASE_KEYS)))
    736882        {
    737883            /* Regular key event - update keyboard state. */
    738884            if (fKeyDown)
    739                 pThis->abDepressedKeys[u8HidCode] = 1;
     885                pThis->abDepressedKeys[iKeyCode] = 1;
    740886            else
    741                 pThis->abDepressedKeys[u8HidCode] = 0;
     887                pThis->abDepressedKeys[iKeyCode] = 0;
    742888        }
    743889        else
  • trunk/src/VBox/Main/src-client/KeyboardImpl.cpp

    r85300 r89935  
    296296HRESULT Keyboard::releaseKeys()
    297297{
    298     std::vector<LONG> scancodes;
    299     scancodes.resize(1);
    300     scancodes[0] = 0xFC;    /* Magic scancode, see PS/2 and USB keyboard devices. */
    301     return putScancodes(scancodes, NULL);
     298    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     299
     300    /* Release all keys on the active keyboard in order to start with a clean slate.
     301     * Note that this should mirror the logic in Keyboard::putScancodes() when choosing
     302     * which keyboard to send the release event to.
     303     */
     304    PPDMIKEYBOARDPORT pUpPort = NULL;
     305    for (int i = KEYBOARD_MAX_DEVICES - 1; i >= 0 ; --i)
     306    {
     307        if (mpDrv[i] && (mpDrv[i]->u32DevCaps & KEYBOARD_DEVCAP_ENABLED))
     308        {
     309            pUpPort = mpDrv[i]->pUpPort;
     310            break;
     311        }
     312    }
     313
     314    if (pUpPort)
     315    {
     316        int rc = pUpPort->pfnReleaseKeys(pUpPort);
     317        if (RT_FAILURE(rc))
     318            AssertMsgFailed(("Failed to release keys on all keyboards! rc=%Rrc\n", rc));
     319    }
     320
     321    return S_OK;
    302322}
    303323
     
    352372{
    353373    PDRVMAINKEYBOARD pDrv = RT_FROM_MEMBER(pInterface, DRVMAINKEYBOARD, IConnector);
     374
     375    // Before activating a different keyboard, release all keys on the currently active one.
     376    if (fActive)
     377        pDrv->pKeyboard->releaseKeys();
     378
    354379    if (fActive)
    355380        pDrv->u32DevCaps |= KEYBOARD_DEVCAP_ENABLED;
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette