Изменить вывод 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;
}