Изменить вывод keyDown

Я пытаюсь написать свой собственный брелок для ключей.

Так что, если я напишу "к", я получу русский "к"

[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
        NSMutableString *buffer = [event.characters mutableCopy];
        CFMutableStringRef bufferRef = (__bridge CFMutableStringRef)buffer;
        CFStringTransform(bufferRef, NULL, kCFStringTransformLatinCyrillic, false);
        NSLog(@"%@", buffer);
    }];

Как изменить вывод события keyDown в других приложениях.

Например, я набираю письмо в chrome, gmail... моя клавиатура настроена на английский, но я получаю русские символы.

как это: translit.ru

Есть ли способ изменить вывод?

1 ответ

Решение

Я быстро собрал этот код вместе, поэтому обязательно проверьте его на утечки памяти и т. Д. Вы увидите, что вам нужно добавить другие символы, которые вы хотите обработать, а также регистр (я добавил только k -> к).

Этот пример был построен как утилита "командной строки", поэтому он не имеет пользовательского интерфейса и подходит для работы в фоновом режиме через launchd, Обратите внимание, что вам нужно либо запустить его как root, либо включить поддержку вспомогательных устройств в системных настройках и добавить разрешение для этого приложения.

Обратите внимание, что вы можете запускать с правами root при разработке в Xcode, перейдя в Product -> Scheme -> Edit и в разделе "run" измените радио на "процесс отладки" на "root".

Редактировать: Обновление пула автоматического выпуска, чтобы освободить временные объекты.

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

    // TODO: add other cases and do proper handling of case
    if ([event.characters caseInsensitiveCompare:@"k"] == NSOrderedSame) {
        event = [NSEvent keyEventWithType:event.type
                                 location:NSZeroPoint
                            modifierFlags:event.modifierFlags
                                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;
}
Другие вопросы по тегам