通过代码使 SHIFT+3 在 OSX 上生成 `#` 而不是 `£`

Posted

技术标签:

【中文标题】通过代码使 SHIFT+3 在 OSX 上生成 `#` 而不是 `£`【英文标题】:Make SHIFT+3 produce `#` not `£` on OSX by code 【发布时间】:2015-07-31 21:34:06 【问题描述】:

在我的英国 MacBook Air 上,# 可以使用 OPT+3 键入。 SHIFT+3 当前生成£。如何重新连线以便 SHIFT+3 产生#

这个问题的动机是https://apple.stackexchange.com/questions/156154/use-option-as-meta-key-with-ability-to-type-the-symbol

我认为 OSX 终端应用程序的默认设置没有注册 OPT(例如 nano 编辑器中的键盘快捷键需要)是一个失败,并且如果您切换设置以启用它,您现在无法输入#,一般通过OPT+3完成。

在使用 nano 的终端会话中编辑远程服务器上的配置文件时,我经常需要 #

我相信可以使用Ukelele,但我更喜欢代码级解决方案。

如果我可以通过代码完成此操作,我将学到一些东西!

我试过询问a more generic question,但 OSX 有一个复杂的机制来处理击键。这个问题属于第一!如果我能理解这一点,它将阐明更一般情况的一个组成部分。

【问题讨论】:

【参考方案1】:

这个答案直接来自Modify keyDown output,做了非常小的改编:

// 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;

【讨论】:

以上是关于通过代码使 SHIFT+3 在 OSX 上生成 `#` 而不是 `£`的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CentOS 上生成 Node.js 火焰图?

Beanstalk:如何将服务器上生成的文件同步回 beanstalk 存储库?

如何在不同的数据帧上生成交叉验证以进行监督分类?

如何在 Swift 3 中的 mapview 上生成不同的图钉?

在CCS上生成.bin .hex .txt文件并烧录到MSP430 使LCD灯亮

STM32 使用 DMA 在 GPIO PIN 上生成位模式