Make SHIFT+3 produce `#` not `£` on OSX by code

前端 未结 1 1621
天涯浪人
天涯浪人 2021-01-26 06:16

On my UK MacBook Air, # can be typed using OPT+3. SHIFT+3 currently produces £. How can I rewire so that SHIFT+3 produces #?

This

相关标签:
1条回答
  • 2021-01-26 06:27

    This answer come straight from Modify keyDown output with very minor adaptation:

    // compile and run from the commandline with:
    //    clang -fobjc-arc -framework Cocoa  ./foo.m  -o foo
    //    sudo ./foo 
    
    #import <Foundation/Foundation.h>
    #import <AppKit/NSEvent.h>
    
    typedef CFMachPortRef EventTap;
    
    // - - - - - - - - - - - - - - - - - - - - -
    
    @interface KeyChanger : NSObject
    {
    @private
        EventTap            _eventTap;
        CFRunLoopSourceRef  _runLoopSource;
        CGEventRef          _lastEvent;
    }
    @end
    
    // - - - - - - - - - - - - - - - - - - - - -
    
    CGEventRef _tapCallback(
                            CGEventTapProxy proxy,
                            CGEventType     type,
                            CGEventRef      event,
                            KeyChanger*     listener
                            );
    
    // - - - - - - - - - - - - - - - - - - - - -
    
    @implementation KeyChanger
    
    - (BOOL)tapEvents
    {
        if (!_eventTap) {
            NSLog(@"Initializing an event tap.");
    
            _eventTap = CGEventTapCreate(kCGSessionEventTap,
                                         kCGTailAppendEventTap,
                                         kCGEventTapOptionDefault,
                                         CGEventMaskBit( kCGEventKeyDown ),
                                         (CGEventTapCallBack)_tapCallback,
                                         (__bridge void *)(self));
            if (!_eventTap) {
                NSLog(@"unable to create event tap. must run as root or "
                        "add privlidges for assistive devices to this app.");
                return NO;
            }
        }
        CGEventTapEnable(_eventTap, TRUE);
    
        return [self isTapActive];
    }
    
    - (BOOL)isTapActive
    {
        return CGEventTapIsEnabled(_eventTap);
    }
    
    - (void)listen
    {
        if( ! _runLoopSource ) {
            if( _eventTap ) { //dont use [self tapActive]
                _runLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault,
                                                                _eventTap, 0);
                // Add to the current run loop.
                CFRunLoopAddSource( CFRunLoopGetCurrent(), _runLoopSource,
                                    kCFRunLoopCommonModes);
    
                NSLog(@"Registering event tap as run loop source.");
                CFRunLoopRun();
            }else{
                NSLog(@"No Event tap in place! You will need to call "
                        "listen after tapEvents to get events.");
            }
        }
    }
    
    - (CGEventRef)processEvent:(CGEventRef)cgEvent
    {
        NSEvent* event = [NSEvent eventWithCGEvent:cgEvent];
    
        NSUInteger modifiers = [event modifierFlags] &
            (NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask);
    
        enum {
           kVK_ANSI_3 = 0x14,
        };
    
        // TODO: add other cases and do proper handling of case
        if (
            //[event.characters caseInsensitiveCompare:@"3"] == NSOrderedSame
            event.keyCode == kVK_ANSI_3
            && modifiers == NSShiftKeyMask
            ) 
        {
            NSLog(@"Got SHIFT+3");
    
            event = [NSEvent keyEventWithType: event.type
                                     location: NSZeroPoint
                                modifierFlags: event.modifierFlags & ! NSShiftKeyMask
                                    timestamp: event.timestamp
                                 windowNumber: event.windowNumber
                                      context: event.context
                                   characters: @"#"
                  charactersIgnoringModifiers: @"#"
                                    isARepeat: event.isARepeat
                                      keyCode: event.keyCode];
        }
        _lastEvent = [event CGEvent];
        CFRetain(_lastEvent); // must retain the event. will be released by the system
        return _lastEvent;
    }
    
    - (void)dealloc
    {
        if( _runLoopSource ) {
            CFRunLoopRemoveSource( CFRunLoopGetCurrent(), _runLoopSource, kCFRunLoopCommonModes );
            CFRelease( _runLoopSource );
        }
        if( _eventTap ) {
            //kill the event tap
            CGEventTapEnable( _eventTap, FALSE );
            CFRelease( _eventTap );
        }
    }
    
    @end
    
    // - - - - - - - - - - - - - - - - - - - - -
    
    CGEventRef _tapCallback(
                            CGEventTapProxy proxy,
                            CGEventType     type,
                            CGEventRef      event,
                            KeyChanger*     listener
                            )
    {
        //Do not make the NSEvent here.
        //NSEvent will throw an exception if we try to make an event from the tap timout type
        @autoreleasepool {
            if( type == kCGEventTapDisabledByTimeout ) {
                NSLog(@"event tap has timed out, re-enabling tap");
                [listener tapEvents];
                return nil;
            }
            if( type != kCGEventTapDisabledByUserInput ) {
                return [listener processEvent:event];
            }
        }
        return event;
    }
    
    // - - - - - - - - - - - - - - - - - - - - -
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            KeyChanger* keyChanger = [KeyChanger new];
            [keyChanger tapEvents];
            [keyChanger listen];//blocking call.
        }
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题