VirtualBox

Changeset 30507 in vbox for trunk/src/VBox/Devices/Input


Ignore:
Timestamp:
Jun 29, 2010 2:40:48 PM (15 years ago)
Author:
vboxsync
Message:

Devices/Input/UsbKbd: rewrite of the event processing code to make it handle shift states more correctly

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Input/UsbKbd.cpp

    r30224 r30507  
    6060/** @} */
    6161
     62/** @name USB HID additional constants
     63 * @{ */
     64/** The highest USB usage code reported by the VBox emulated keyboard */
     65#define VBOX_USB_MAX_USAGE_KBD      231
     66#define USBHID_USAGE_ROLL_OVER      1
     67/** @} */
     68
    6269/*******************************************************************************
    6370*   Structures and Typedefs                                                    *
     
    150157    scan_state_t        XlatState;
    151158
    152     /** HID report reflecting the current keyboard state. */
    153     USBHIDK_REPORT      Report;
    154 
    155159    /** Pending to-host queue.
    156160     * The URBs waiting here are waiting for data to become available.
     
    166170    /** Someone is waiting on the done queue. */
    167171    bool                fHaveDoneQueueWaiter;
    168     /** If no URB since last key press. */
    169     bool                fNoUrbSinceLastPress;
    170172    /** If device has pending changes. */
    171173    bool                fHasPendingChanges;
    172     /** Keys released since last URB. */
    173     uint8_t             abReleasedKeys[6];
     174    /** Keypresses which have not yet been reported.  A workaround for the
     175     * problem of keys being released before the keypress could be reported. */
     176    uint8_t             abUnreportedKeys[VBOX_USB_MAX_USAGE_KBD];
     177    /** Currently depressed keys */
     178    uint8_t             abDepressedKeys[VBOX_USB_MAX_USAGE_KBD];
    174179
    175180    /**
     
    619624    pThis->enmState = USBHIDREQSTATE_READY;
    620625    pThis->bIdle = 0;
    621     memset(&pThis->Report, 0, sizeof(pThis->Report));
    622     pThis->fNoUrbSinceLastPress = false;
    623626    pThis->fHasPendingChanges = false;
    624     memset(&pThis->abReleasedKeys[0], 0, sizeof(pThis->abReleasedKeys));
    625627
    626628    for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++)
     
    643645        return usbHidCompleteOk(pThis, pUrb, 0);
    644646    return VINF_SUCCESS;
    645 }
    646 
    647 static void usbHidUpdateReportReleased(PUSBHID pThis, uint8_t u8HidCode)
    648 {
    649     unsigned i;
    650 
    651     for (i = 0; i < RT_ELEMENTS(pThis->Report.aKeys); ++i)
    652     {
    653         if (pThis->Report.aKeys[i] == u8HidCode)
    654         {
    655             /* Remove key down. */
    656             pThis->Report.aKeys[i] = 0;
    657         }
    658     }
    659 
    660 #if 0
    661     if (i == RT_ELEMENTS(pThis->Report.aKeys))
    662     {
    663         Log(("Key 0x%x is up but was never down!?", u8HidCode));
    664     }
    665 #endif
    666 }
    667 
    668 static void usbHidCommitReportReleased(PUSBHID pThis)
    669 {
    670     unsigned i;
    671     for (i = 0; i < RT_ELEMENTS(pThis->abReleasedKeys); ++i)
    672     {
    673         if (pThis->abReleasedKeys[i] != 0)
    674         {
    675             usbHidUpdateReportReleased(pThis, pThis->abReleasedKeys[i]);
    676             pThis->abReleasedKeys[i] = 0;
    677         }
    678     }
    679647}
    680648
     
    703671
    704672/**
     673 * Returns true if the usage code corresponds to a keyboard modifier key
     674 * (left or right ctrl, shift, alt or GUI).  The usage codes for these keys
     675 * are the range 0xe0 to 0xe7.
     676 */
     677static bool usbHidUsageCodeIsModifier(uint8_t u8Usage)
     678{
     679    return u8Usage >= 0xe0 && u8Usage <= 0xe7;
     680}
     681
     682/**
     683 * Convert a USB HID usage code to a keyboard modifier flag.  The arithmetic
     684 * is simple: the modifier keys have usage codes from 0xe0 to 0xe7, and the
     685 * lower nibble is the bit number of the flag.
     686 */
     687static uint8_t usbHidModifierToFlag(uint8_t u8Usage)
     688{
     689    Assert(usbHidUsageCodeIsModifier(u8Usage));
     690    return RT_BIT(u8Usage & 0xf);
     691}
     692
     693/**
     694 * Create a USB HID keyboard report based on a vector of keys which have been
     695 * pressed since the last report was created (so that we don't miss keys that
     696 * are only pressed briefly) and a vector of currently depressed keys.
     697 * The keys in the report aKeys array are in increasing order (important for
     698 * the test case).
     699 */
     700static int usbHidFillReport(PUSBHIDK_REPORT pReport,
     701                            uint8_t *pabUnreportedKeys,
     702                            uint8_t *pabDepressedKeys)
     703{
     704    unsigned iBuf = 0;
     705    RT_ZERO(*pReport);
     706    for (unsigned iKey = 0; iKey < VBOX_USB_MAX_USAGE_KBD; ++iKey)
     707    {
     708        AssertReturn(iBuf <= RT_ELEMENTS(pReport->aKeys),
     709                     VERR_INTERNAL_ERROR);
     710        if (pabUnreportedKeys[iKey] || pabDepressedKeys[iKey])
     711        {
     712            if (usbHidUsageCodeIsModifier(iKey))
     713                pReport->ShiftState |= usbHidModifierToFlag(iKey);
     714            else if (iBuf == RT_ELEMENTS(pReport->aKeys))
     715            {
     716                /* The USB HID spec says that the entire vector should be
     717                 * set to ErrorRollOver on overflow.  We don't mind if this
     718                 * path is taken several times for one report. */
     719                for (unsigned iBuf2 = 0;
     720                     iBuf2 < RT_ELEMENTS(pReport->aKeys); ++iBuf2)
     721                    pReport->aKeys[iBuf2] = USBHID_USAGE_ROLL_OVER;
     722            }
     723            else
     724            {
     725                pReport->aKeys[iBuf] = iKey;
     726                ++iBuf;
     727            }
     728            pabUnreportedKeys[iKey] = 0;
     729        }
     730    }
     731    return VINF_SUCCESS;
     732}
     733
     734#ifdef DEBUG
     735/** Test data for testing usbHidFillReport().  The format is:
     736 *   - Unreported keys (zero terminated array)
     737 *   - Depressed keys (zero terminated array)
     738 *   - Expected shift state in the report (single byte inside array)
     739 *   - Expected keys buffer contents (array of six bytes)
     740 */
     741static const uint8_t testUsbHidFillReportData[][4][10] = {
     742    /* Just unreported, no modifiers */
     743    {{4, 9, 0}, {0}, {0}, {4, 9, 0, 0, 0, 0}},
     744    /* Just unreported, one modifier */
     745    {{4, 9, 0xe2, 0}, {0}, {4}, {4, 9, 0, 0, 0, 0}},
     746    /* Just unreported, two modifiers */
     747    {{4, 9, 0xe2, 0xe4, 0}, {0}, {20}, {4, 9, 0, 0, 0, 0}},
     748    /* Just depressed, no modifiers */
     749    {{0}, {7, 20, 0}, {0}, {7, 20, 0, 0, 0, 0}},
     750    /* Just depressed, one modifier */
     751    {{0}, {7, 20, 0xe3, 0}, {8}, {7, 20, 0, 0, 0, 0}},
     752    /* Just depressed, two modifiers */
     753    {{0}, {7, 20, 0xe3, 0xe6, 0}, {72}, {7, 20, 0, 0, 0, 0}},
     754    /* Unreported and depressed, no overlap, no modifiers */
     755    {{5, 10, 0}, {8, 21, 0}, {0}, {5, 8, 10, 21, 0, 0}},
     756    /* Unreported and depressed, one overlap, no modifiers */
     757    {{5, 10, 0}, {8, 10, 21, 0}, {0}, {5, 8, 10, 21, 0, 0}},
     758    /* Unreported and depressed, no overlap, non-overlapping modifiers */
     759    {{5, 10, 0xe2, 0xe4, 0}, {8, 21, 0xe3, 0xe6, 0}, {92},
     760           {5, 8, 10, 21, 0, 0}},
     761    /* Unreported and depressed, one overlap, non-overlapping modifiers */
     762    {{5, 10, 21, 0xe2, 0xe4, 0}, {8, 21, 0xe3, 0xe6, 0}, {92},
     763           {5, 8, 10, 21, 0, 0}},
     764    /* Unreported and depressed, no overlap, overlapping modifiers */
     765    {{5, 10, 0xe2, 0xe4, 0}, {8, 21, 0xe3, 0xe4, 0}, {28},
     766           {5, 8, 10, 21, 0, 0}},
     767    /* Unreported and depressed, one overlap, overlapping modifiers */
     768    {{5, 10, 0xe2, 0xe4, 0}, {5, 8, 21, 0xe3, 0xe4, 0}, {28},
     769           {5, 8, 10, 21, 0, 0}},
     770    /* Just too many unreported, no modifiers */
     771    {{4, 9, 11, 12, 16, 18, 20, 0}, {0}, {0}, {1, 1, 1, 1, 1, 1}},
     772    /* Just too many unreported, two modifiers */
     773    {{4, 9, 11, 12, 16, 18, 20, 0xe2, 0xe4, 0}, {0}, {20},
     774           {1, 1, 1, 1, 1, 1}},
     775    /* Just too many depressed, no modifiers */
     776    {{0}, {7, 20, 22, 25, 27, 29, 34, 0}, {0}, {1, 1, 1, 1, 1, 1}},
     777    /* Just too many depressed, two modifiers */
     778    {{0}, {7, 20, 22, 25, 27, 29, 34, 0xe3, 0xe5, 0}, {40},
     779           {1, 1, 1, 1, 1, 1}},
     780    /* Too many unreported and depressed, no overlap, no modifiers */
     781    {{5, 10, 12, 13, 0}, {8, 9, 21, 0}, {0}, {1, 1, 1, 1, 1, 1}},
     782    /* Eight unreported and depressed total, one overlap, no modifiers */
     783    {{5, 10, 12, 13, 0}, {8, 10, 21, 22, 0}, {0}, {1, 1, 1, 1, 1, 1}},
     784    /* Seven unreported and depressed total, one overlap, no modifiers */
     785    {{5, 10, 12, 13, 0}, {8, 10, 21, 0}, {0}, {5, 8, 10, 12, 13, 21}},
     786    /* Too many unreported and depressed, no overlap, two modifiers */
     787    {{5, 10, 12, 13, 0xe2, 0}, {8, 9, 21, 0xe4, 0}, {20},
     788           {1, 1, 1, 1, 1, 1}},
     789    /* Eight unreported and depressed total, one overlap, two modifiers */
     790    {{5, 10, 12, 13, 0xe1, 0}, {8, 10, 21, 22, 0xe2, 0}, {6},
     791           {1, 1, 1, 1, 1, 1}},
     792    /* Seven unreported and depressed total, one overlap, two modifiers */
     793    {{5, 10, 12, 13, 0xe2, 0}, {8, 10, 21, 0xe3, 0}, {12},
     794           {5, 8, 10, 12, 13, 21}}
     795};
     796
     797/** Test case for usbHidFillReport() */
     798class testUsbHidFillReport
     799{
     800    USBHIDK_REPORT mReport;
     801    uint8_t mabUnreportedKeys[VBOX_USB_MAX_USAGE_KBD];
     802    uint8_t mabDepressedKeys[VBOX_USB_MAX_USAGE_KBD];
     803    const uint8_t (*mTests)[4][10];
     804
     805    void doTest(unsigned cTest, const uint8_t *paiUnreportedKeys,
     806                const uint8_t *paiDepressedKeys, uint8_t aExpShiftState,
     807                const uint8_t *pabExpKeys)
     808    {
     809        RT_ZERO(mReport);
     810        RT_ZERO(mabUnreportedKeys);
     811        RT_ZERO(mabDepressedKeys);
     812        for (unsigned i = 0; paiUnreportedKeys[i] != 0; ++i)
     813            mabUnreportedKeys[paiUnreportedKeys[i]] = 1;
     814        for (unsigned i = 0; paiDepressedKeys[i] != 0; ++i)
     815            mabUnreportedKeys[paiDepressedKeys[i]] = 1;
     816        int rc = usbHidFillReport(&mReport, mabUnreportedKeys, mabDepressedKeys);
     817        AssertMsgRC(rc, ("test %u\n", cTest));
     818        AssertMsg(mReport.ShiftState == aExpShiftState, ("test %u\n", cTest));
     819        for (unsigned i = 0; i < RT_ELEMENTS(mReport.aKeys); ++i)
     820            AssertMsg(mReport.aKeys[i] == pabExpKeys[i], ("test %u\n", cTest));
     821    }
     822
     823public:
     824    testUsbHidFillReport(void) : mTests(&testUsbHidFillReportData[0])
     825    {
     826        for (unsigned i = 0; i < RT_ELEMENTS(testUsbHidFillReportData); ++i)
     827            doTest(i, mTests[i][0], mTests[i][1], mTests[i][2][0],
     828                   mTests[i][3]);
     829    }
     830};
     831
     832static testUsbHidFillReport gsTestUsbHidFillReport;
     833#endif
     834
     835/**
    705836 * Sends a state report to the host if there is a pending URB.
    706837 */
     
    710841    if (pUrb)
    711842    {
    712         PUSBHIDK_REPORT pReport = &pThis->Report;
    713         size_t          cbCopy;
    714 
    715 #ifdef DEBUG
    716         char            szActiveBuf[128];
    717         usbHidComputePressed(pReport, szActiveBuf, sizeof szActiveBuf);
    718         Log2(("Sending report with pressed keys: %s\n", szActiveBuf));
    719 #endif
    720         cbCopy = sizeof(*pReport);
    721         memcpy(&pUrb->abData[0], pReport, cbCopy);
    722         pThis->fNoUrbSinceLastPress = false;
    723         pThis->fHasPendingChanges = false;
    724         usbHidCommitReportReleased(pThis);
    725 #ifdef DEBUG
    726         usbHidComputePressed(pReport, szActiveBuf, sizeof szActiveBuf);
    727         Log2(("New state: %s\n", szActiveBuf));
    728 #endif
    729 //        LogRel(("Sent report: %x : %x %x, size %d\n", pReport->ShiftState, pReport->aKeys[0], pReport->aKeys[1], cbCopy));
    730         return usbHidCompleteOk(pThis, pUrb, cbCopy);
     843        PUSBHIDK_REPORT pReport = (PUSBHIDK_REPORT)&pUrb->abData[0];
     844
     845        int rc = usbHidFillReport(pReport, pThis->abUnreportedKeys,
     846                                  pThis->abDepressedKeys);
     847        AssertRCReturn(rc, rc);
     848        return usbHidCompleteOk(pThis, pUrb, sizeof(*pReport));
    731849    }
    732850    else
     
    759877{
    760878    PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort);
    761     PUSBHIDK_REPORT pReport = &pThis->Report;
    762879    uint32_t    u32Usage = 0;
    763880    uint8_t     u8HidCode;
     
    775892        fKeyDown = !(u32Usage & 0x80000000);
    776893        u8HidCode = u32Usage & 0xFF;
    777 
    778         Log(("key %s: 0x%x->0x%x\n",
    779              fKeyDown ? "down" : "up", u8KeyCode, u8HidCode));
     894        AssertReturn(u8HidCode <= VBOX_USB_MAX_USAGE_KBD, VERR_INTERNAL_ERROR);
     895
     896        LogRelFlowFunc(("key %s: 0x%x->0x%x\n",
     897                        fKeyDown ? "down" : "up", u8KeyCode, u8HidCode));
    780898
    781899        if (fKeyDown)
    782900        {
    783             for (i = 0; i < RT_ELEMENTS(pReport->aKeys); ++i)
    784             {
    785                 if (pReport->aKeys[i] == u8HidCode)
    786                 {
    787                     /* Skip repeat events. */
    788                     fHaveEvent = false;
    789                     break;
    790                 }
    791             }
    792 
    793             if (fHaveEvent)
    794             {
    795                 for (i = 0; i < RT_ELEMENTS(pReport->aKeys); ++i)
    796                 {
    797                     if (pReport->aKeys[i] == 0)
    798                     {
    799                         pReport->aKeys[i] = u8HidCode;      /* Report key down. */
    800                         break;
    801                     }
    802                 }
    803 
    804                 pThis->fNoUrbSinceLastPress = true;
    805 
    806                 if (i == RT_ELEMENTS(pReport->aKeys))
    807                 {
    808                     /* We ran out of room. Report error. */
    809                     Log(("no more room in usbHidKeyboardPutEvent\n"));
    810                     /// @todo!!
    811                 }
    812             }
     901            /* Due to host key repeat, we can get key events for keys which are
     902             * already depressed. */
     903            if (!pThis->abDepressedKeys[u8HidCode])
     904                pThis->abUnreportedKeys[u8HidCode] = 1;
     905            else
     906                fHaveEvent = false;
     907            pThis->abDepressedKeys[u8HidCode] = 1;
    813908        }
    814909        else
    815         {
    816             /*
    817              * We have to avoid coalescing key presses and releases,
    818              * so put all releases somewhere else if press wasn't seen
    819              * by the guest.
    820              */
    821             if (pThis->fNoUrbSinceLastPress)
    822             {
    823                 for (i = 0; i < RT_ELEMENTS(pThis->abReleasedKeys); ++i)
    824                 {
    825                     if (pThis->abReleasedKeys[i] == u8HidCode)
    826                         break;
    827 
    828                     if (pThis->abReleasedKeys[i] == 0)
    829                     {
    830                         pThis->abReleasedKeys[i] = u8HidCode;
    831                         break;
    832                     }
    833                 }
    834             }
    835             else
    836                 usbHidUpdateReportReleased(pThis, u8HidCode);
    837         }
     910            pThis->abDepressedKeys[u8HidCode] = 0;
    838911
    839912        /* Send a report if the host is already waiting for it. */
Note: See TracChangeset for help on using the changeset viewer.

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