- Timestamp:
- Oct 25, 2013 1:28:04 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/platform/darwin/DarwinKeyboard.cpp
r49090 r49289 313 313 void *pParentContainer; /** A pointer to a VBoxHidsState_t instance where VBoxKbdState_t instance is stored */ 314 314 CFIndex idxPosition; /** Position in global storage (used to simplify CFArray navigation when removing detached device) */ 315 uint64_t cCapsLockTimeout; /** KBD CAPS LOCK key hold timeout (some Apple keyboards only) */ 315 316 } VBoxKbdState_t; 316 317 … … 321 322 VBoxLedState_t guestState; /** LED states that were stored during last broadcast and reflect a guest LED states */ 322 323 324 CFMutableArrayRef pFifoEventQueue; /** This queue will be appended in IOKit input callback. Carbon input callback will extract data from it */ 325 RTSEMMUTEX fifoEventQueueLock; /** Lock for pFifoEventQueue */ 326 323 327 /* Carbon events data */ 324 328 CFMachPortRef pTapRef; 325 329 CFRunLoopSourceRef pLoopSourceRef; 326 330 } VBoxHidsState_t; 327 328 /* A *sync* between IOKit and Carbon callbacks. */329 static VBoxKbdState_t *g_LastTouchedState;330 331 #endif /* !VBOX_WITH_KBD_LEDS_SYNC */ 331 332 … … 1397 1398 } 1398 1399 1400 /** Get HID Vendor ID */ 1401 static uint32_t darwinHidVendorId(IOHIDDeviceRef pHidDeviceRef) 1402 { 1403 CFTypeRef pNumberRef; 1404 uint32_t vendorId = 0; 1405 1406 AssertReturn(pHidDeviceRef, 0); 1407 1408 pNumberRef = IOHIDDeviceGetProperty(pHidDeviceRef, CFSTR(kIOHIDVendorIDKey)); 1409 if (pNumberRef) 1410 { 1411 if (CFGetTypeID(pNumberRef) == CFNumberGetTypeID()) 1412 { 1413 if (CFNumberGetValue((CFNumberRef)pNumberRef, kCFNumberSInt32Type, &vendorId)) 1414 return vendorId; 1415 } 1416 } 1417 1418 return 0; 1419 } 1420 1399 1421 /** Some keyboard devices might freeze after LEDs manipulation. We filter out such devices here. 1400 1422 * In the list below, devices that known to have such issues. If you want to add new device, … … 1404 1426 { 1405 1427 #ifndef VBOX_WITHOUT_KBD_LEDS_SYNC_FILTERING 1406 bool fSupported = true; 1407 CFTypeRef pNumberRef; 1408 uint32_t vendorId = 0; 1409 1410 AssertReturn(pHidDeviceRef, false); 1411 1412 pNumberRef = IOHIDDeviceGetProperty(pHidDeviceRef, CFSTR(kIOHIDVendorIDKey)); 1413 if (pNumberRef) 1414 { 1415 if (CFGetTypeID(pNumberRef) == CFNumberGetTypeID()) 1416 { 1417 if (CFNumberGetValue((CFNumberRef)pNumberRef, kCFNumberSInt32Type, &vendorId)) 1418 { 1419 switch (vendorId) 1420 { 1421 case 0x05D5: /** Genius (detected with GK-04008/C keyboard) */ 1422 fSupported = false; 1423 break; 1424 } 1425 1426 Log2(("HID device Vendor ID 0x%X %s in the list of supported devices.\n", vendorId, (fSupported ? "is" : "is not"))); 1427 } 1428 } 1429 } 1428 bool fSupported = true; 1429 uint32_t vendorId = darwinHidVendorId(pHidDeviceRef); 1430 1431 switch (vendorId) 1432 { 1433 case 0x05D5: /** Genius (detected with GK-04008/C keyboard) */ 1434 fSupported = false; 1435 break; 1436 } 1437 1438 Log2(("HID device Vendor ID 0x%X %s in the list of supported devices.\n", vendorId, (fSupported ? "is" : "is not"))); 1430 1439 1431 1440 return fSupported; … … 1435 1444 } 1436 1445 1446 typedef struct VBoxKbdEvent_t { 1447 VBoxKbdState_t *pKbd; 1448 uint32_t iKeyCode; 1449 uint64_t tsKeyDown; 1450 uint64_t tsKeyUp; 1451 } VBoxKbdEvent_t; 1452 1437 1453 /** IOKit key press callback. Triggered before Carbon callback. We remember which keyboard produced a keypress here. */ 1438 1454 static void darwinHidInputCallback(void *pData, IOReturn unused, void *unused1, IOHIDValueRef pValueRef) … … 1446 1462 AssertReturnVoid(pElementRef); 1447 1463 1448 if (IOHIDElementGetUsagePage(pElementRef) == kHIDPage_KeyboardOrKeypad) /* Keyboard or keypad event */ 1449 if (IOHIDValueGetIntegerValue(pValueRef) == 1) /* key has been pressed down */ 1450 if (IOHIDElementGetUsage(pElementRef) == kHIDUsage_KeyboardCapsLock || /* CapsLock key has been pressed */ 1451 IOHIDElementGetUsage(pElementRef) == kHIDUsage_KeypadNumLock) /* ... or NumLock key has been pressed */ 1464 uint32_t usage = IOHIDElementGetUsage(pElementRef); 1465 1466 if (IOHIDElementGetUsagePage(pElementRef) == kHIDPage_KeyboardOrKeypad) /* Keyboard or keypad event */ 1467 if (usage == kHIDUsage_KeyboardCapsLock || /* CapsLock key has been pressed */ 1468 usage == kHIDUsage_KeypadNumLock) /* ... or NumLock key has been pressed */ 1469 { 1470 VBoxKbdState_t *pKbd = (VBoxKbdState_t *)pData; 1471 1472 if (pKbd && pKbd->pParentContainer) 1452 1473 { 1453 Log2(("A modifier key has been pressed\n")); 1454 g_LastTouchedState = (VBoxKbdState_t *)pData; 1474 bool fKeyDown = (IOHIDValueGetIntegerValue(pValueRef) == 1); 1475 1476 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pKbd->pParentContainer; 1477 VBoxKbdEvent_t *pEvent = NULL;; 1478 CFIndex iQueue = 0; 1479 1480 AssertReturnVoid(pHidState); 1481 1482 if (RT_FAILURE(RTSemMutexRequest(pHidState->fifoEventQueueLock, RT_INDEFINITE_WAIT))) 1483 return ; 1484 1485 /* Allocate new event data on Key-Down, find a cached one on Key-Up */ 1486 if (fKeyDown) 1487 pEvent = (VBoxKbdEvent_t *)malloc(sizeof(VBoxKbdEvent_t)); 1488 else 1489 { 1490 for (CFIndex i = 0; i < CFArrayGetCount(pHidState->pFifoEventQueue); i++) 1491 { 1492 VBoxKbdEvent_t *pCachedEvent = (VBoxKbdEvent_t *)CFArrayGetValueAtIndex(pHidState->pFifoEventQueue, i); 1493 if (pCachedEvent && pCachedEvent->pKbd == pKbd && pCachedEvent->iKeyCode == usage) 1494 { 1495 pEvent = pCachedEvent; 1496 iQueue = i; 1497 break; 1498 } 1499 } 1500 } 1501 1502 if (pEvent) 1503 { 1504 if (usage == kHIDUsage_KeyboardCapsLock && pKbd->cCapsLockTimeout) 1505 { 1506 if (fKeyDown) 1507 pEvent->tsKeyDown = RTTimeSystemMilliTS(); 1508 else 1509 pEvent->tsKeyUp = RTTimeSystemMilliTS(); 1510 } 1511 1512 if (fKeyDown) 1513 { 1514 Log2(("IOHID: KBD %d: Modifier Key-Down\n", (int)pKbd->idxPosition)); 1515 1516 pEvent->pKbd = pKbd; 1517 pEvent->iKeyCode = usage; 1518 pEvent->tsKeyUp = 0; 1519 1520 /* Append FIFO event queue */ 1521 CFArrayAppendValue(pHidState->pFifoEventQueue, (void *)pEvent); 1522 } 1523 else 1524 { 1525 uint64_t tsDiff = pEvent->tsKeyUp - pEvent->tsKeyDown; 1526 if (tsDiff < pKbd->cCapsLockTimeout) 1527 { 1528 free(pEvent); 1529 CFArrayRemoveValueAtIndex(pHidState->pFifoEventQueue, iQueue); 1530 Log2(("IOHID: KBD %d: Modifier Key-Up (Key-Down %llu ms ago). Apple keyboard, removed from queue\n", (int)pKbd->idxPosition, tsDiff)); 1531 } 1532 else 1533 Log2(("IOHID: KBD %d: Modifier Key-Up (Key-Down %llu ms ago)\n", (int)pKbd->idxPosition, tsDiff)); 1534 } 1535 } 1536 else 1537 { 1538 if (fKeyDown) 1539 Log2(("IOHID: unable to find memory to queue KBD %d event\n", (int)pKbd->idxPosition)); 1540 else 1541 Log2(("IOHID: unable to find KBD %d event in queue\n", (int)pKbd->idxPosition)); 1542 } 1543 1544 RTSemMutexRelease(pHidState->fifoEventQueueLock); 1455 1545 } 1456 1546 else 1547 Log2(("IOHID: No KBD: A modifier key has been pressed\n")); 1548 } 1457 1549 } 1458 1550 1459 1551 /** Carbon key press callback. Triggered after IOKit callback. We update keyboard (catched in darwinHidInputCallback()) internal state here. */ 1460 static CGEventRef darwinCarbonGlobalKeyPressCallback(CGEventTapProxy unused, CGEventType type, CGEventRef pEventRef, void *unused1)1552 static CGEventRef darwinCarbonGlobalKeyPressCallback(CGEventTapProxy unused, CGEventType unused1, CGEventRef pEventRef, void *pData) 1461 1553 { 1462 1554 (void)unused; 1463 1555 (void)unused1; 1464 1465 /* Skip events we are not interested in. */1466 if (type != kCGEventKeyDown && type != kCGEventFlagsChanged)1467 return pEventRef;1468 1556 1469 1557 CGEventFlags fMask = CGEventGetFlags(pEventRef); … … 1472 1560 CGKeyCode key = CGEventGetIntegerValueField(pEventRef, kCGKeyboardEventKeycode); 1473 1561 1562 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pData; AssertReturn(pHidState, pEventRef); 1563 AssertReturn(pHidState, pEventRef); 1564 1565 if (RT_FAILURE(RTSemMutexRequest(pHidState->fifoEventQueueLock, RT_INDEFINITE_WAIT))) 1566 return pEventRef; 1567 1474 1568 if (key == kHIDUsage_KeyboardCapsLock || 1475 1569 key == kHIDUsage_KeypadNumLock) 1476 1570 { 1477 Log2(("carbon event: caps=%s, num=%s\n", VBOX_BOOL_TO_STR_STATE(fCaps), VBOX_BOOL_TO_STR_STATE(fNum))); 1478 1479 VBoxKbdState_t *pKbd = g_LastTouchedState; 1480 if (pKbd) 1481 { 1571 /* Extract last touched state from FIFO event queue */ 1572 VBoxKbdEvent_t *pEvent = NULL; 1573 CFIndex iEvent = 0; 1574 1575 /* Find last occured KBD event in queue (ignoring those events which not match CAPS LOCK timeout criteria). */ 1576 for (CFIndex i = 0; i < CFArrayGetCount(pHidState->pFifoEventQueue); i++) 1577 { 1578 pEvent = (VBoxKbdEvent_t *)CFArrayGetValueAtIndex(pHidState->pFifoEventQueue, i); 1579 if (!pEvent) continue; 1580 if (!pEvent->pKbd) continue; 1581 1582 if (pEvent->iKeyCode == kHIDUsage_KeypadNumLock 1583 || (pEvent->iKeyCode == kHIDUsage_KeyboardCapsLock && 1584 (RTTimeSystemMilliTS() - pEvent->tsKeyDown) > pEvent->pKbd->cCapsLockTimeout)) 1585 { 1586 /* Found one. Keep its index in queue in order to remove it later. */ 1587 iEvent = i; 1588 Log2(("CARBON: Found event in queue: %d (KBD %d, tsKeyDown=%llu, pressed %llu ms ago)\n", (int)i, (int)pEvent->pKbd->idxPosition, pEvent->tsKeyDown, RTTimeSystemMilliTS() - pEvent->tsKeyDown)); 1589 break; 1590 } 1591 else 1592 Log2(("CARBON: skip CAPS LOCK event %d (KBD %d) (tsKeyDown=%llu, pressed %llu ms ago)\n", (int)i, (int)pEvent->pKbd->idxPosition, pEvent->tsKeyDown, RTTimeSystemMilliTS() - pEvent->tsKeyDown)); 1593 1594 pEvent = NULL; 1595 } 1596 1597 if (pEvent) 1598 { 1599 VBoxKbdState_t *pKbd = pEvent->pKbd; 1600 1601 Log2(("CARBON: KBD %d: caps=%s, num=%s. tsKeyDown=%llu, tsKeyUp=%llu [tsDiff=%llu ms]. %d events in queue.\n", 1602 (int)pKbd->idxPosition, VBOX_BOOL_TO_STR_STATE(fCaps), VBOX_BOOL_TO_STR_STATE(fNum), 1603 pEvent->tsKeyDown, pEvent->tsKeyUp, pEvent->tsKeyUp - pEvent->tsKeyDown, 1604 CFArrayGetCount(pHidState->pFifoEventQueue))); 1605 1482 1606 pKbd->LED.fCapsLockOn = fCaps; 1483 1607 pKbd->LED.fNumLockOn = fNum; 1484 1608 1485 1609 /* Silently resync last touched KBD device */ 1486 VBoxHidsState_t *pHidState = (VBoxHidsState_t *)pKbd->pParentContainer;1487 1610 if (pHidState) 1488 1611 { … … 1497 1620 } 1498 1621 1499 /* Forget device */ 1500 g_LastTouchedState = NULL; 1501 } 1502 } 1622 /* Forget event */ 1623 CFArrayRemoveValueAtIndex(pHidState->pFifoEventQueue, iEvent); 1624 free(pEvent); 1625 } 1626 else 1627 Log2(("CARBON: No KBD to take care when modifier key has been pressed: caps=%s, num=%s\n", VBOX_BOOL_TO_STR_STATE(fCaps), VBOX_BOOL_TO_STR_STATE(fNum))); 1628 } 1629 1630 RTSemMutexRelease(pHidState->fifoEventQueueLock); 1503 1631 1504 1632 return pEventRef; … … 1517 1645 1518 1646 Log2(("Forget KBD %d\n", (int)pKbd->idxPosition)); 1647 1648 //if (RT_FAILURE(RTSemMutexRequest(pHidState->fifoEventQueueLock, RT_INDEFINITE_WAIT))) 1649 // return ; 1650 1519 1651 CFArrayRemoveValueAtIndex(pHidState->pDeviceCollection, pKbd->idxPosition); 1520 1652 free(pKbd); 1653 1654 //RTSemMutexRelease(pHidState->fifoEventQueueLock); 1521 1655 } 1522 1656 … … 1553 1687 pKbd->pParentContainer = (void *)pHidState; 1554 1688 pKbd->idxPosition = CFArrayGetCount(pHidState->pDeviceCollection); 1689 1690 /* Some Apple keyboards have CAPS LOCK key timeout. According to corresponding 1691 * kext plist files, it is equals to 75 ms. For such devices we only add info into our FIFO event 1692 * queue if the time between Key-Down and Key-Up events >= 75 ms. */ 1693 pKbd->cCapsLockTimeout = (darwinHidVendorId(pKbd->pDevice) == kIOUSBVendorIDAppleComputer) ? 75 : 0; 1555 1694 1556 1695 CFDictionaryRef elementMatchingDict = darwinQueryLedElementMatchingDictionary(); … … 1624 1763 CGEventMask fMask = CGEventMaskBit(kCGEventFlagsChanged); 1625 1764 1626 g_LastTouchedState = NULL; 1627 1628 pTapRef = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, fMask, darwinCarbonGlobalKeyPressCallback, NULL); 1765 AssertReturn(pHidState, kIOReturnError); 1766 1767 /* Create FIFO event queue for keyboard events */ 1768 pHidState->pFifoEventQueue = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL); 1769 AssertReturn(pHidState->pFifoEventQueue, kIOReturnError); 1770 1771 /* Create Lock for FIFO event queue */ 1772 if (RT_FAILURE(RTSemMutexCreate(&pHidState->fifoEventQueueLock))) 1773 { 1774 Log2(("Unable to create Lock for FIFO event queue\n")); 1775 CFRelease(pHidState->pFifoEventQueue); 1776 pHidState->pFifoEventQueue = NULL; 1777 return kIOReturnError; 1778 } 1779 1780 pTapRef = CGEventTapCreate(kCGSessionEventTap, kCGTailAppendEventTap, 0, fMask, darwinCarbonGlobalKeyPressCallback, (void *)pHidState); 1629 1781 if (pTapRef) 1630 1782 { … … 1658 1810 AssertReturnVoid(pHidState->pTapRef); 1659 1811 AssertReturnVoid(pHidState->pLoopSourceRef); 1660 1661 g_LastTouchedState = NULL; 1812 AssertReturnVoid(pHidState->pFifoEventQueue); 1662 1813 1663 1814 CGEventTapEnable(pHidState->pTapRef, false); … … 1665 1816 CFRelease(pHidState->pLoopSourceRef); 1666 1817 CFRelease(pHidState->pTapRef); 1818 1819 RTSemMutexRequest(pHidState->fifoEventQueueLock, RT_INDEFINITE_WAIT); 1820 CFRelease(pHidState->pFifoEventQueue); 1821 pHidState->pFifoEventQueue = NULL; 1822 RTSemMutexRelease(pHidState->fifoEventQueueLock); 1823 1824 RTSemMutexDestroy(pHidState->fifoEventQueueLock); 1667 1825 } 1668 1826 #endif /* !VBOX_WITH_KBD_LEDS_SYNC */
Note:
See TracChangeset
for help on using the changeset viewer.