Frage

Ich arbeite an einer Typing-Tutor-Anwendung für Mac OSX mit Tastenanschlägen, auch wenn die Anwendung nicht im Fokus steht.

Gibt es eine Möglichkeit, das System vorwärts zu bringen, möglicherweise über die App, möglicherweise durch nsdistributedNotificationCenter? Ich habe mich albern gegoogelt und konnte keine Antwort finden ...

BEARBEITEN: Beispielcode unten.

Danke @nsgod, dass du mich in die richtige Richtung gezeigt hast - ich habe einen hinzugefügt Globaler Ereignismonitor mit der Methode addGlobalMonitorForEventsMatchingMask:handler:, was wunderbar funktioniert. Für die Vollständigkeit sieht meine Implementierung so aus:

// 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);

}];

Für mich war der schwierige Teil der Verwendung von Blöcken, also werde ich eine kleine Beschreibung geben, falls es jedem hilft:

Die Sache, die über den obigen Code zu bemerken, ist, dass alles ist Ein einziger Methodenaufruf auf nsvent. Der Block wird direkt als Argument geliefert, direkt zu die Funktion. Sie könnten sich ein bisschen wie eine Inline -Delegate -Methode vorstellen. Nur weil es eine Weile dauerte, bis ich für mich einsprangen konnte, werde ich hier Schritt für Schritt durcharbeiten:

[NSEvent addGlobalMonitorForEventsMatchingMask:NSKeyDownMask

Dieses erste Stück ist kein Problem. Sie rufen eine Klassenmethode auf nSEvent an und geben es mit, welches Ereignis Sie überwachen möchten, in diesem Fall nskeydownmask. EIN Liste der Masken für unterstützte Ereignisstypen kann gefunden werden hier.

Jetzt kommen wir zum schwierigen Teil: Handler, der einen Block erwartet:

handler:^(NSEvent *event){

Ich habe ein paar Kompilierfehler gebraucht, um dies richtig zu machen, aber (danke Apple) waren sie sehr konstruktive Fehlermeldungen. Das erste, was zu bemerken ist, ist der Karat ^. Das signalisiert den Beginn des Blocks. Danach innerhalb der Klammern,,

NSEvent *event

Dies deklariert die Variable, die Sie im Block verwenden, um das Ereignis zu erfassen. Sie könnten es nennen

NSEvent *someCustomNameForAnEvent

Es spielt keine Rolle, Sie werden diesen Namen im Block nur verwenden. Dann ist das so gut wie alles, was es gibt. Stellen Sie sicher, dass Sie Ihre lockige Klammer schließen und den Methodenaufruf beenden:

}];

Und du bist fertig! Das ist wirklich eine Art „Ein-Liner“. Es spielt keine Rolle, wo Sie diesen Anruf in Ihrer App ausführen - ich mache ihn in der ApplicationDidfinishlaus -Methode des AppDelegate. Im Block können Sie dann andere Methoden in Ihrer App aus aufrufen.

War es hilfreich?

Lösung

Wenn Sie mit einer Mindestanforderung von OS X 10.6+ einverstanden sind und mit "schreibgeschützt" Zugriff auf den Ereignisstrom ausreichen können, können Sie einen globalen Ereignismonitor in Kakao installieren:Handbuch zur Behandlung von Kakao-Events: Überwachung von Ereignissen.

Wenn Sie OS X 10.5 und früher unterstützen müssen und der schreibgeschützte Zugriff in Ordnung ist und es nichts ausmacht, mit dem Carbon-Event-Manager zu arbeiten, können Sie im Grunde genommen den Kohlenstoffäquivalent verwenden GetEventMonitorTarget(). (Sie werden es schwer haben, eine (offizielle) Dokumentation zu dieser Methode zu finden). Diese API war zuerst in OS X 10.3 erhältlich, glaube ich.

Wenn Sie Leseschreiberzugriff auf den Ereignisstrom benötigen, müssen Sie sich eine etwas niedrigere API unter Anwendungsservices> Corgraphics ansehen:CGEventTapCreate() und Freunde. Dies war zuerst in 10.4 erhältlich.

Beachten Sie, dass alle 3 Methoden erforderlich sind, dass der Benutzer "Zugriff für Hilfsmittel aktivieren" in den Systemeinstellungen> Universal Access Preference -Bereich (zumindest für Schlüsselereignisse) aktiviert hat.

Andere Tipps

Ich poste den Code, der für meinen Fall funktioniert hat.

Ich füge den globalen Event -Handler hinzu, nachdem die App gestartet wurde. Meine Verknüpfung lässt Strg+Alt+CMD+T meine App öffnen.

- (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];
        }
    }];

}

Das Problem, das ich dabei finde, ist, dass jede von einer andere App globale registrierte Schlüssel nicht gekämpft wird ... oder zumindest in meinem Fall, vielleicht mache ich etwas falsch.

Wenn Ihr Programm beispielsweise alle Schlüssel wie "Befehlshift-3" anzeigen muss, wird dies nicht angezeigt, um es anzuzeigen ... da es vom Betriebssystem aufgenommen wird.

Oder hat jemand das herausgefunden? Ich würde gerne wissen ...

Wie NSGOD bereits betonte, können Sie auch Corgraphics verwenden.

In Ihrer Klasse (zB in -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();

Außerhalb der Klasse, aber in derselben .m -Datei:

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top