Last active
February 27, 2019 08:42
-
-
Save ghazel/e2e0f2644f816cb4167021a2e0566357 to your computer and use it in GitHub Desktop.
touchbar IOHID watcher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// compile and run from the commandline with: | |
// clang -framework CoreFoundation -framework CoreGraphics -framework IOKit ./HID.c -o hid | |
// ./hid | |
#include <IOKit/hid/IOHIDValue.h> | |
#include <IOKit/hid/IOHIDManager.h> | |
#include <ApplicationServices/ApplicationServices.h> | |
CFMutableDictionaryRef myCreateDeviceMatchingDictionary(UInt32 pUsagePage, UInt32 pUsage) | |
{ | |
CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
CFNumberRef usagePage = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pUsagePage); | |
CFNumberRef usage = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pUsage); | |
if (matchDict && usagePage && usage) { | |
CFDictionarySetValue(matchDict, CFSTR(kIOHIDDeviceUsagePageKey), usagePage); | |
CFDictionarySetValue(matchDict, CFSTR(kIOHIDDeviceUsageKey), usage); | |
CFRelease(usagePage); | |
CFRelease(usage); | |
return matchDict; | |
} | |
return 0; | |
} | |
CFMachPortRef eventTap; | |
CFRunLoopTimerRef disableTimer; | |
static void TimerCallback(CFRunLoopTimerRef timer, void *info) | |
{ | |
printf("disabling CGEventTap\n"); | |
CGEventTapEnable(eventTap, false); | |
CFRelease(disableTimer); | |
disableTimer = NULL; | |
} | |
static CGEventRef EventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, void *_Nullable userInfo) | |
{ | |
printf("EventTapCallback type:%d\n", type); | |
if (type != -1) { | |
if (disableTimer) { | |
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), disableTimer, kCFRunLoopDefaultMode); | |
CFRelease(disableTimer); | |
disableTimer = NULL; | |
} | |
CFRunLoopTimerContext timerContext = {0, NULL, NULL, NULL, NULL}; | |
disableTimer = CFRunLoopTimerCreate(kCFAllocatorDefault, | |
// 50ms is just a guess. One iteration with CFRunLoopPerformBlock was not enough | |
CFAbsoluteTimeGetCurrent() + 0.050, | |
0, 0, 0, | |
TimerCallback, | |
&timerContext); | |
CFRunLoopAddTimer(CFRunLoopGetCurrent(), disableTimer, kCFRunLoopDefaultMode); | |
} | |
return eventRef; | |
} | |
static void hidInputReportCallback(void *context, IOReturn result, void *sender, IOHIDReportType type, | |
uint32_t reportID, uint8_t *reportValue, CFIndex reportLength) | |
{ | |
IOHIDDeviceRef device = (IOHIDDeviceRef)sender; | |
CFTypeRef name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); | |
printf("Device `%s`: ", CFStringGetCStringPtr(name, kCFStringEncodingUTF8)); | |
for (int i = 0 ; i < reportLength; i++) { | |
printf("%3d ", (char)reportValue[i]); | |
} | |
printf("\nEnabling CGEventTap\n"); | |
CGEventTapEnable(eventTap, true); | |
} | |
int main(void) | |
{ | |
IOHIDManagerRef hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); | |
// found from: ioreg -irc IOHIDDevice -w 0 | |
CFMutableDictionaryRef touchbar = myCreateDeviceMatchingDictionary(13, 5); | |
CFMutableDictionaryRef touchbar2 = myCreateDeviceMatchingDictionary(65280, 35); | |
CFMutableDictionaryRef touchbar3 = myCreateDeviceMatchingDictionary(65280, 22); | |
CFMutableDictionaryRef matchesList[] = {touchbar3}; | |
CFArrayRef matches = CFArrayCreate(kCFAllocatorDefault, (const void **)matchesList, sizeof(matchesList)/sizeof(matchesList[0]), NULL); | |
IOHIDManagerSetDeviceMatchingMultiple(hidManager, matches); | |
IOHIDManagerRegisterInputReportCallback(hidManager, hidInputReportCallback, NULL); | |
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode); | |
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone); | |
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, EventTapCallback, NULL); | |
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); | |
if (runLoopSource) { | |
CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopDefaultMode); | |
CGEventTapEnable(eventTap, false); | |
} | |
CFRunLoopRun(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment