2009-10-21 15 views
10

Ich verwende etwas Carbon-Code in meinem Cocoa-Projekt, um globale Schlüsselereignisse (Shortcuts) von anderen Anwendungen zu verarbeiten. Derzeit habe ich einen kEventHotKeyReleased Event-Handler eingerichtet und ich kann Hot Keys erfolgreich erhalten, wenn meine Anwendung nicht aktiv ist. Das löst einige Vorgänge in meiner Anwendung aus.Wie kann der globale Modifier-Key-Status (in einer beliebigen Anwendung) überwacht werden?

Das Problem, das ich mit dem Verhalten von kEventHotKeyReleased haben ist:

Sagen Sie zum Beispiel drücke ich die Cmd-Shift-P-Tastenkombination. Sobald ich die Taste "P" loslasse, wird das Hotkey-Ereignis ausgelöst. Ich muss in der Lage sein, das Ereignis auszulösen (oder manuell auszulösen), wenn alle der Tasten (d. H .: die Cmd und Shift-Tasten sind ebenfalls freigegeben).

Es ist einfach, für Hotkeys zu überwachen, aber ich habe nichts für die Überwachung einzelner Tastenanschläge gesehen. Wenn ich die Modifier-Key-Zustände überwachen könnte, wäre ich im Geschäft.

Irgendwelche Hinweise, wie das geht?

Vielen Dank im Voraus!


UPDATE:

Ich habe versucht, mit kEventRawKeyUp und kEventRawKeyModifiersChanged aber während kEventHotKeyReleased funktioniert diese beiden nicht, obwohl ich sie in genau der gleichen Art und Weise wie kEventHotKeyReleased eingerichtet.

EventTypeSpec eventTypes[] = {{kEventClassKeyboard, kEventHotKeyReleased}, {kEventClassKeyboard, kEventRawKeyUp}}; 
// Changing the order in the list does not help, nor does removing kEventHotKeyReleased 
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL); 
// err == noErr after this line 

Die globalHotKeyHandler Methode wird für kEventHotKeyReleased genannt, aber nicht für kEventRawKeyUp aus irgendeinem Grund kann ich nicht zu begreifen scheinen. Hier ist, was meine globalHotKeyHandler Methode wie folgt aussieht:

OSStatus globalHotkeyHandler(EventHandlerCallRef nextHandler, EventRef anEvent, void *userData) { 
    NSLog(@"Something happened!"); 
} 

Gibt es einen zusätzlichen Anruf, die gemacht werden muss oder etwas anderes habe ich vergessen?

N. B: Auf den ersten Blick scheint es, wie es, dass Zugriff für Hilfsgeräte deaktiviert ist aber es ist nicht sein könnte. Also bin ich ziemlich ahnungslos.


UPDATE 2:

suchte ich ein bisschen auf dem CGEventTap Leibowitzn vorgeschlagen und ich kam mit dieser Einrichtung auf:

CFMachPortRef keyUpEventTap = CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,kCGEventKeyUp,&keyUpCallback,NULL); 
CFRunLoopSourceRef keyUpRunLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, keyUpEventTap, 0); 
CFRelease(keyUpEventTap); 
CFRunLoopAddSource(CFRunLoopGetCurrent(), keyUpRunLoopSourceRef, kCFRunLoopDefaultMode); 
CFRelease(keyUpRunLoopSourceRef); 

... und der Rückruf:

CGEventRef keyUpCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { 
    NSLog(@"KeyUp event tapped!"); 
    return event; 
} 

Wie Sie sehen können, verwende ich kCGEventKeyUp als die Maske für den Event tippen, aber irgendwie bekomme ich mouse down Ereignisse ??! ??


UPDATE 3:

Ok vergessen, dass ich die Linie in dem doc übersehen, daß die CGEventMaskBit (kCGEventKeyUp) für diesen Parameter zu verwenden, so dass der korrekte Aufruf lautet:

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventKeyUp),&keyUpCallback,NULL); 

Ich habe immer noch ein Problem: Modifier-Tasten lösen nicht die kCGEventKeyUp ...


UPDATE 4:

Ok das wieder vergessen ... Ich bin verpflichtet, meine eigenen Fragen 5 Minuten zu beantworten, nachdem sie huh heute fragen!

Zusatztasten abzufangen, verwenden kCGEventFlagsChanged:

CGEventTapCreate(kCGHIDEventTap,kCGHeadInsertEventTap,kCGEventTapOptionListenOnly,CGEventMaskBit(kCGEventFlagsChanged),&callbackFunction,NULL); 

Also im Grunde habe ich den Schlüssel und Zusatztaste Zustandserkennung arbeiten, aber ich weiß, noch interessiert bin, warumkEventRawKeyUp nicht funktioniert ...


NB: beachten Sie auch, dass ich mit dem Ziel, die Unterstützung für neue und ältere Versionen des OS auf Tiger bin Entwicklung so viel wie möglich. CGEventTap ist nur 10.4+, also werde ich dies jetzt verwenden, aber eine rückwärtskompatible Lösung wäre willkommen.

Antwort

3

Eine Option ist EventTaps zu verwenden. Auf diese Weise können Sie alle Tastaturereignisse überwachen. Siehe: http://developer.apple.com/mac/library/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/c/func/CGEventTapCreate

Leider funktionieren Ereignisabgriffe nicht mehr, wenn eine Anwendung eine sichere Eingabe anfordert. Zum Beispiel Quicken.

+0

Ich denke, es gibt eine Möglichkeit, nur Modifikatortasten zu überwachen. Sieh dir den Quellcode im Google Schnellsuchfeld an. Es enthält Code, der erkannt wird, wenn der Benutzer zweimal auf die Befehlsschaltfläche klickt. Siehe: http://www.google.com/codesearch/p?hl=en&sa=N&cd=2&ct=rc#qWBe9JkJhME/trunk/QuickSearchBox/QSB/QSBApplicationDelegate.m&q=modifiersChangedWhileInactive%20package:http://qsb-mac \ .googlecode \.com – Leibowitzn

+0

Ahh, sie registrieren gerade für das folgende Kohlenstoffereignis: {kEventClassKeyboard, kEventRawKeyModifiersChanged} – Leibowitzn

+0

Ich habe bemerkt, kEventRawKeyModifiersChanged und kEventRawKeyUp, aber ich kann nicht scheinen, dass sie arbeiten für das Leben von mir. Siehe das Update in meiner Frage. (Danke für deine Hilfe übrigens!) – Form

1
OSStatus err = InstallApplicationEventHandler(&globalHotkeyHandler, GetEventTypeCount(eventTypes), eventTypes, NULL, NULL); 

Dies ist nicht global. Dies installiert den Handler nur, wenn Ihre eigene Anwendung aktiv ist und (ich glaube) nach den eigenen Ereignisfiltern des Carbon Event Managers.

Sie müssen InstallEventHandler verwenden, die als ersten Parameter ein Ereignisziel verwendet (InstallApplicationEventHandler ist ein Makro, das das Ziel des Anwendungsereignisses übergibt).

Für Ereignisse, die auftreten, während Ihre Anwendung nicht aktiv ist, ist das Ziel, das Sie wollen GetEventMonitorTarget(). Für Ereignisse, die auftreten, während Ihre Anwendung aktiv ist, ist das Ziel, das Sie wünschen, GetEventDispatcherTarget(). Um Ereignisse zu erfassen, unabhängig davon, welche Anwendung aktiv ist, installieren Sie Ihren Handler auf beiden Zielen. obwohl

Heute würde ich nur CGEventTaps verwenden, wie Leibowitzn vorgeschlagen.

+0

Es ist seltsam, weil InstallApplicationEventHandler meinen Hotkey überall installiert, nicht nur während meine Anwendung aktiv ist. Ich kann die Hotkeys von jeder Anwendung aus auslösen. Außerdem, wenn ich versuche, InstallEventHandler mit GetEventMonitorTarget() zu verwenden, scheint es nicht zu funktionieren, aber ich muss etwas falsch machen. Welchen Vorteil hat es, CGEventTap anstelle von dem zu verwenden, was ich gerade benutze? – Form

+0

Es ist viel einfacher. –

+0

Wenn Sie nur einen Hotkey registrieren möchten, verwenden Sie dazu [die Funktion RegisterEventHotKey] (http://developer.apple.com/legacy/mac/library/documentation/Carbon/Reference/Carbon_Event_Manager_Ref/Reference/reference.html # // apple_ref/c/func/RegisterEventHotKey), die genau für diesen Zweck existiert. –

Verwandte Themen