2010-06-03 4 views
6

CGEventTapCreate을 사용하여 앱이 실행 중일 때 iTunes의 미디어 키를 "도용"합니다. CGEventTapCreate에 전달하는 콜백 내부의 코드는 이벤트를 검사하고 미디어 키 중 하나임을 발견하면 적절한 알림을 기본 알림 센터에 게시합니다.CGEventTapCreate가 "키 다운"이벤트로 신비하게 깨졌습니다.

"키 업"이벤트에 대한 알림을 게시하면 올바르게 작동합니다. "키 다운"이벤트를 위해이를 수행하면 결국 앱에서 미디어 키 이벤트가 중지되고 iTunes가 작동합니다. 이 문제를 일으킬 수있는 아이디어가 있습니까? 코드의 관련 부분은, 왜 첫 번째 "경우"키 다운과 키 업 이벤트가 통과 할 수 있도록 모두의

enum { 
... 
    PlayPauseKeyDown = 0x100A00, 
    PlayPauseKeyUp = 0x100B00, 
... 
}; 

static CGEventRef event_tap_callback(CGEventTapProxy proxy, 
            CGEventType type, 
            CGEventRef event, 
            void *refcon) 
{ 
    if (!(type == NX_SYSDEFINED) || (type == NX_KEYUP) || (type == NX_KEYDOWN)) 
     return event; 

    NSEvent* keyEvent = [NSEvent eventWithCGEvent: event]; 
    if (keyEvent.type != NSSystemDefined) return event; 

    switch(keyEvent.data1) 
    { 
    case PlayPauseKeyUp: // <--- this works reliably 
    //case PlayPauseKeyDown: // <--- this will break eventually 
     post_notification(@"PlayPauseMediaKeyPressed", nil, nil); 
     return NULL; 

    ... and so on ... 
+0

타이밍 문제인 것으로 보입니다. post_notification 대신 sleep (1)을 사용합니다. 몇 번의 키를 입력하면 PlayPauseKeyDown을 사용하는 경우 iTunes가 미디어 키를 훔칩니다. PlayPauseKeyUp을 사용하는 경우에도 작동합니다. – svintus

답변

9

콜백에 너무 오래 걸리면 뭔가 내 이벤트 탭을 죽일 수 있습니까?

어떤 사람들은 스노우 레오파드 (Snow Leopard)는 때때로 너무 오래하지 않는 경우에도 이벤트 탭 비활성화 버그가 있다고 생각한다. 이를 처리하기 위해 이벤트 유형 kCGEventTapDisabledByTimeout을보고 CGEventTapEnable으로 다시 활성화하여 응답 할 수 있습니다.

+1

그래, 그랬어. kCGEventTapDisabledByTimeout이 트릭을 수행합니다. – svintus

+0

고맙습니다! –

3

먼저 아래? 두 번째 "if"는 시스템 이벤트 만 통과시킵니다. 따라서 모든 키 다운/업 이벤트에 대해 NSEvent를 작성하면 이벤트를 한 줄 아래로 더 떨어 뜨릴 수 있습니다. 그것은 거의 의미가 없습니다. 이벤트 탭은 가능한 한 빨리해야합니다. 그렇지 않으면 전체 시스템의 모든 이벤트 처리 속도가 느려집니다. 시스템 이벤트는 키 다운/업 이벤트가 아니기 때문에 콜백은 키 다운/업 이벤트에 대해 호출되어서는 안됩니다. 시스템 이벤트입니다. 키 이벤트의 경우 data1에 액세스하지 말고 대신 "type"및 "keyCode"메서드를 사용하여 관련 정보를 가져옵니다.

if ([sysEvent subtype] != 8) return event; 

:

또한
static CGEventRef event_tap_callback(CGEventTapProxy proxy, 
            CGEventType type, 
            CGEventRef event, 
            void *refcon) 
{ 
    NSEvent * sysEvent; 

    // No event we care for? return ASAP 
    if (type != NX_SYSDEFINED) return event; 

    sysEvent = [NSEvent eventWithCGEvent:event]; 
    // No need to test event type, we know it is NSSystemDefined, 
    // becuase that is the same as NX_SYSDEFINED 

그 데이터 만보고하여 이벤트의 오른쪽 종류인지를 확인할 수없는, 당신은 또한 하위 유형을 확인해야합니다, 그 이벤트 이런 종류의 8이어야합니다 다음 논리적 단계는 그 구성 요소들로 데이터를 분할하는 것입니다

int data = [sysEvent data1]; 
    int keyCode = (data & 0xFFFF0000) >> 16; 
    int keyFlags = (data & 0xFFFF); 
    int keyState = (keyFlags & 0xFF00) >> 8; 
    BOOL keyIsRepeat = (keyFlags & 0x1) > 0; 

그리고 당신은 아마 내가 키를 누를 지킬 때 즉 그것은 같은 이벤트를 보내는 유지 (키 이벤트의 반복에 대한 상관 없어 다시 반복하여).

// You probably won't care for repeating events 
    if (keyIsRepeat) return event; 

마지막으로 당신이 어떤 자신의 상수를 정의해서는 안, 시스템은 그 키에 대한 상수를 사용할 준비가 있습니다

// Analyze the key 
    switch (keyCode) { 
    case NX_KEYTYPE_PLAY: 
     // Play/Pause key 
     if (keyState == 0x0A) { 
     // Key down 
     // ...do your stuff here... 
     return NULL; 
     } else if (keyState == 0x0B) { 
     // Key Up 
     // ...do your stuff here... 
     return NULL; 
     } 
     // If neither down nor up, we don't know 
     // what it is and better ignore it 
     break; 


    case NX_KEYTYPE_FAST: 
     // (Fast) Forward 
     break; 

    case NX_KEYTYPE_REWIND: 
     // Rewind key 
     break; 
    } 

    // If we get here, we have not handled 
    // the event and want system to handle it 
    return event; 
} 

그리고이 아직도 작품, 내 다음 질문은 무엇을 당신의 post_notification 기능이 될 경우 그리고 거기에 post_notification을 호출하지 않고 방금 본 이벤트에 대한 NSLog 호출을하면 설명 된 문제가 나타납니다.

+0

감사합니다, Mecki! 코드를 수정했지만 문제는 계속 발생합니다. post_notification을 "if (keyState == 0x0A) ..."아래에 넣으면", iTunes는"if (keyState == 0x0B) "아래에 넣으면 결국 미디어 키를 인계받습니다. 모든 것이 제대로 작동하는 것 같습니다 .post_notification은 단순히 기본 NSNotificationCenter의 postNotificationName : ...을 호출합니다. 이제, post_notification을 sleep (1)로 대체하면 문제가 훨씬 빨리 발생합니다. 콜백에 너무 오래 걸리면 무언가 내 이벤트 탭을 죽일 수 있습니까? 콜백에서 너무 느리게 알림이 전송되고 있습니까? – svintus

0

처리기에서 다음 유형을 확인한 다음 수신기를 다시 사용 설정하기 만하면됩니다.

if (type == kCGEventTapDisabledByTimeout) { 
    NSLog(@"Event Taps Disabled! Re-enabling"); 
      CGEventTapEnable(eventTap, true); 
    return event; 
} 
관련 문제