program story

OSX : 시스템 전체의 keyDown 이벤트 감지?

inputbox 2020. 12. 13. 09:24
반응형

OSX : 시스템 전체의 keyDown 이벤트 감지?


저는 Mac OSX 용 타이핑 튜터 응용 프로그램을 작업 중입니다.이 응용 프로그램에 포커스가없는 경우에도 키 입력을 전달해야합니다.

NSDistributedNotificationCenter를 통해 시스템이 키 입력을 앱에 전달하도록하는 방법이 있습니까? 나는 나 자신을 어리석게 봤고 답을 찾을 수 없었다 ...

편집 : 아래 샘플 코드 .

@NSGod에게 올바른 방향을 알려 주셔서 감사 합니다. 아름답게 작동 하는 방법을 사용하여 전역 이벤트 모니터추가했습니다 addGlobalMonitorForEventsMatchingMask:handler:. 완전성을 위해 내 구현은 다음과 같습니다.

// register for keys throughout the device...
[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                       handler:^(NSEvent *event){

    NSString *chars = [[event characters] lowercaseString];
    unichar character = [chars characterAtIndex:0];

    NSLog(@"keydown globally! Which key? This key: %c", character);

}];

저에게 까다로운 부분은 블록을 사용하는 것이 었으므로 누구에게나 도움이 될 수 있도록 약간의 설명을 드리겠습니다.

위의 코드에서 주목해야 할 점은 NSEvent에 대한 모든 단일 메서드 호출이라는 것 입니다. 블록 직접 인수로 공급 으로 기능. 인라인 델리게이트 메서드라고 생각할 수 있습니다. 이 작업에 시간이 걸리기 때문에 여기에서 단계적으로 작업하겠습니다.

[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask

이 첫 번째 비트는 문제가되지 않습니다. NSEvent에서 클래스 메서드를 호출하고 모니터링 할 이벤트 (이 경우 NSKeyDownMask)를 알려줍니다. 지원 이벤트 유형에 대한 마스크의 목록을 찾을 수 있습니다 여기에 .

이제 블록을 예상하는 까다로운 부분 인 핸들러로 이동합니다.

handler:^(NSEvent *event){

이 문제를 해결하기 위해 몇 가지 컴파일 오류가 필요했지만 (Apple에게 감사합니다) 매우 건설적인 오류 메시지였습니다. 가장 먼저 눈에 띄는 것은 캐럿 ^입니다. 그것은 블록의 시작을 알립니다. 그 후 괄호 안에

NSEvent *event

이벤트를 캡처하기 위해 블록 내에서 사용할 변수를 선언합니다. 당신은 그것을 부를 수 있습니다

NSEvent *someCustomNameForAnEvent

중요하지 않습니다. 블록 내에서 해당 이름을 사용하게됩니다. 그러면 그게 전부입니다. 중괄호를 닫고 대괄호를 닫아 메서드 호출을 완료해야합니다.

}];

그리고 당신은 끝났습니다! 이것은 정말로 일종의 '원 라이너'입니다. 앱 내에서이 호출을 실행하는 위치는 중요하지 않습니다. AppDelegate의 applicationDidFinishLaunching 메서드에서 수행합니다. 그런 다음 블록 내에서 앱 내에서 다른 메서드를 호출 할 수 있습니다.


OS X 10.6+의 최소 요구 사항에 동의하고 이벤트 스트림에 대한 "읽기 전용"액세스로 충분하다면 Cocoa : Cocoa Event-Handling Guide : Monitoring Events 에서 전역 이벤트 모니터를 설치할 수 있습니다 .

OS X 10.5 및 이전 버전을 지원해야하고 읽기 전용 액세스가 괜찮고 Carbon Event Manager로 작업해도 상관 없다면 기본적으로 GetEventMonitorTarget(). (하지만 해당 방법에 대한 (공식) 문서를 찾기가 어려울 것입니다). 이 API는 OS X 10.3에서 처음 사용 가능했다고 생각합니다.

이벤트 스트림에 대한 읽기-쓰기 액세스가 필요한 경우 ApplicationServices> CoreGraphics : CGEventTapCreate()및 친구의 일부인 약간 낮은 수준의 API를 살펴 봐야 합니다. 이것은 10.4에서 처음 사용 가능했습니다.

세 가지 방법 모두 시스템 환경 설정> 손쉬운 사용 환경 설정 패널 (최소한 주요 이벤트의 경우)에서 "보조 장치에 대한 접근 활성화"를 활성화해야합니다.


제 경우에 효과가있는 코드를 게시하고 있습니다.

앱이 시작된 후 전역 이벤트 처리기를 추가하고 있습니다. 바로 가기로 인해 ctrl + alt + cmd + T가 내 앱을 엽니 다.

- (void) applicationWillFinishLaunching:(NSNotification *)aNotification
{
    // Register global key handler, passing a block as a callback function
    [NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask
                                           handler:^(NSEvent *event){

        // Activate app when pressing cmd+ctrl+alt+T
        if([event modifierFlags] == 1835305 && [[event charactersIgnoringModifiers] compare:@"t"] == 0) {

              [NSApp activateIgnoringOtherApps:YES];
        }
    }];

}

내가 발견 한 문제는 다른 앱에 의해 전 세계적으로 등록 된 모든 키가 수집되지 않는다는 것입니다 ... 또는 적어도 제 경우에는 내가 뭔가 잘못하고있을 수도 있습니다.

예를 들어 프로그램이 "Command-Shift-3"과 같은 모든 키를 표시해야하는 경우 OS에서 차지하기 때문에 표시 할 수 없습니다.

아니면 누군가 알아 냈나요? 알고 싶습니다 ...


NSGod가 이미 지적했듯이 CoreGraphics를 사용할 수도 있습니다.

수업에서 (예 : -init) :

CFRunLoopRef runloop = (CFRunLoopRef)CFRunLoopGetCurrent();

CGEventMask interestedEvents = NSKeyDown;
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 
                                        0, interestedEvents, myCGEventCallback, self);
// by passing self as last argument, you can later send events to this class instance

CFRunLoopSourceRef source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, 
                                                           eventTap, 0);
CFRunLoopAddSource((CFRunLoopRef)runloop, source, kCFRunLoopCommonModes);
CFRunLoopRun();

Outside of the class, but in the same .m file:

CGEventRef myCGEventCallback(CGEventTapProxy proxy, 
                             CGEventType type, 
                             CGEventRef event, 
                             void *refcon)
{

    if(type == NX_KEYDOWN)
    {
       // we convert our event into plain unicode
       UniChar myUnichar[2];
       UniCharCount actualLength;
       UniCharCount outputLength = 1;
       CGEventKeyboardGetUnicodeString(event, outputLength, &actualLength, myUnichar);

       // do something with the key

       NSLog(@"Character: %c", *myUnichar);
       NSLog(@"Int Value: %i", *myUnichar);

       // you can now also call your class instance with refcon
       [(id)refcon sendUniChar:*myUnichar];
   }

   // send event to next application
   return event;
}

참고URL : https://stackoverflow.com/questions/4752427/osx-detect-system-wide-keydown-events

반응형