macOS:使用 CGEventTap 覆盖修改键

macOS: Override Modifier Key with CGEventTap

所以我最近在我的 macbook pro 键盘上洒了一些水,我的左命令和选项键不再起作用。 Apple 要我邮寄维修,但我现在没时间。所以我想我应该覆盖右命令键作为左控件,因为左命令键仍然有效。

我根据发现的键盘记录器要点改编了以下内容:

#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;
}

现在事件点击工作正常,它确实拦截了键盘事件(我可以看到 TEST 12 54 打印到控制台),但按键仍然作为命令而不是控制。根据documentation for CGEventTapCallback,回调可能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.

传入 kCGHeadInsertEventTap 作为点击位置应该确保我的事件点击被插入到处理程序列表的头部。我是不是做错了什么,还是无法像这样修改事件?

@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 他们提供:

hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x7000000E7,"HIDKeyboardModifierMappingDst":0x7000000E0}]}'