Changeset 30507 in vbox for trunk/src/VBox/Devices/Input
- Timestamp:
- Jun 29, 2010 2:40:48 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Input/UsbKbd.cpp
r30224 r30507 60 60 /** @} */ 61 61 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 62 69 /******************************************************************************* 63 70 * Structures and Typedefs * … … 150 157 scan_state_t XlatState; 151 158 152 /** HID report reflecting the current keyboard state. */153 USBHIDK_REPORT Report;154 155 159 /** Pending to-host queue. 156 160 * The URBs waiting here are waiting for data to become available. … … 166 170 /** Someone is waiting on the done queue. */ 167 171 bool fHaveDoneQueueWaiter; 168 /** If no URB since last key press. */169 bool fNoUrbSinceLastPress;170 172 /** If device has pending changes. */ 171 173 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]; 174 179 175 180 /** … … 619 624 pThis->enmState = USBHIDREQSTATE_READY; 620 625 pThis->bIdle = 0; 621 memset(&pThis->Report, 0, sizeof(pThis->Report));622 pThis->fNoUrbSinceLastPress = false;623 626 pThis->fHasPendingChanges = false; 624 memset(&pThis->abReleasedKeys[0], 0, sizeof(pThis->abReleasedKeys));625 627 626 628 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aEps); i++) … … 643 645 return usbHidCompleteOk(pThis, pUrb, 0); 644 646 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 0661 if (i == RT_ELEMENTS(pThis->Report.aKeys))662 {663 Log(("Key 0x%x is up but was never down!?", u8HidCode));664 }665 #endif666 }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 }679 647 } 680 648 … … 703 671 704 672 /** 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 */ 677 static 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 */ 687 static 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 */ 700 static 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 */ 741 static 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() */ 798 class 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 823 public: 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 832 static testUsbHidFillReport gsTestUsbHidFillReport; 833 #endif 834 835 /** 705 836 * Sends a state report to the host if there is a pending URB. 706 837 */ … … 710 841 if (pUrb) 711 842 { 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)); 731 849 } 732 850 else … … 759 877 { 760 878 PUSBHID pThis = RT_FROM_MEMBER(pInterface, USBHID, Lun0.IPort); 761 PUSBHIDK_REPORT pReport = &pThis->Report;762 879 uint32_t u32Usage = 0; 763 880 uint8_t u8HidCode; … … 775 892 fKeyDown = !(u32Usage & 0x80000000); 776 893 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)); 780 898 781 899 if (fKeyDown) 782 900 { 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; 813 908 } 814 909 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; 838 911 839 912 /* Send a report if the host is already waiting for it. */
Note:
See TracChangeset
for help on using the changeset viewer.