Reputation: 3241
So I recently spilled some water on my macbook pro keyboard, and my left command and option keys no longer function. Apple wants me to mail it in for repairs, which I don't have time for right now. So I thought I'd override the right command key to serve as left control seeing as the left command key still works.
I adapted the following from a keylogger gist I found:
#include <stdio.h>
#import <Carbon/Carbon.h>
#import <ApplicationServices/ApplicationServices.h>
CGEventRef loggerCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* context)
{
if (type == kCGEventFlagsChanged && CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 54 /* right cmd key */) {
printf(
"TEST: %d %llu\n",
type,
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)
);
CGKeyCode virtualKey = 0x3B; // kVK_Control (left control);
CGEventRef override = CGEventCreateCopy(event);
CGEventSetIntegerValueField(override, kCGKeyboardEventKeycode, virtualKey);
return override;
}
return event;
}
int main(int argc, const char * argv[])
{
CFMachPortRef tap;
if ((tap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
0, kCGEventMaskForAllEvents,
loggerCallback, NULL)) == NULL) {
printf("Failed ot create event tap\n");
exit(1);
}
CFRunLoopSourceRef runLoopSource;
if ((runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)) == NULL) {
printf("Failed to create run loop source\n");
exit(1);
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(tap, true);
CFRunLoopRun();
return 0;
}
Now the event tap works correctly, and it does intercept keyboard events ( I can see TEST 12 54
printed to the console), but the key is still behaving as command and not control. According to the documentation for CGEventTapCallback
, the callback may return:
A newly-constructed event. After the new event has been passed back to the event system, the new event will be released along with the original event.
Passing in kCGHeadInsertEventTap
as the tap location should ensure my event tap is inserted at the head of the handler list. Am I doing something wrong here or is it just not possible to modify events like this?
Upvotes: 1
Views: 372
Reputation: 3241
@Willeke was correct in their comment. Although I was correctly overriding the event, what I really needed to do was use the keydown/keyup events to keep track of when the right command key is pressed. I could then use that flag to intercept other keypress events, remove the command modifier, and insert the control modifier flag use bitwise operators. However, the simple solution here to this problem comes from the documentation link they provided:
hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x7000000E7,"HIDKeyboardModifierMappingDst":0x7000000E0}]}'
Upvotes: 1