2013-10-28 67 views
2

我嘗試寫我自己的keychanger。修改keyDown輸出

所以,如果我寫的「K」我得到了俄羅斯的「к」

[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中鍵入電子郵件...我的鍵盤設置爲英語,但我得到俄語字符。

這樣的:tr​​anslit.ru

是否有修改輸出的方法嗎?

+0

我不清楚你在問什麼 - 也許你可以提供一些更多的上下文,或者一個例子顯示你在找什麼?請務必檢查[問題清單](http://meta.stackexchange.com/questions/156810/stack-overflow-question-checklist)。謝謝! –

+0

@ChristianTernus我需要的是一個像這樣的本地應用程序:http://translit.ru/,但在後臺工作。每次我寫和應用程序正在運行,我得到我的所有應用俄語輸出(野生動物園,鉻等) –

+1

看起來這個問題的答案將幫助您: http://stackoverflow.com/questions/6421718/how- to-trap-global-keydown-keyup-events-in-cocoa –

回答

3

我很快把這段代碼扔到了一起,所以一定要審查它的內存泄漏等。你會看到你需要添加你想處理的其他字符以及案例(我只加k - >к) 。

本示例構建爲「命令行」實用程序,因此它沒有UI,適合通過launchd在後臺運行。請注意,您需要以root用戶身份運行此操作,或者在系統偏好設置中啓用輔助設備支持,併爲此應用添加權限。

請注意,在開發Xcode時,您可以轉到Product -> Scheme -> Edit並在「運行」部分將「調試過程as」的收音機更改爲「root」。

編輯:使用autorelease池更新以釋放臨時對象。

// 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; 
} 
+0

嗨,感謝您發佈代碼,我不太適合目標C.我創建了一個命令行工具,並將此代碼粘貼到main.m.試圖建立一個獲得一系列錯誤。 爲架構x86_64的ndefined符號: 「_CGEventGetType」,從引用: - [KeyChanger的processEvent:]在main.o中 「_CGEventTapCreate」,從引用: - [KeyChanger tapEvents]在main.o中 「_CGEventTapEnable」,引用自: –

+0

@Fincha您爲命令行工具選擇了什麼設置?你應該選擇「基金」的類型,你也將需要在了AppKit框架「與圖書館聯繫」「建階段」 –

+0

thanкs很多部分添加到目標中,Appкit不翼而飛 –