overriding Responder Chain - Shortcuts beeinflussen

  • overriding Responder Chain - Shortcuts beeinflussen

    Hi,

    Ich habe ein TextFeld und möchte wenn es ausgewählt ist einen eigenen Keyboard Shortcut definieren. Das klappt visuell schon ganz gut. Ich gebe einen Shortcut ein und das Textfeld zeigt mir den Character sowie die dazu gedrückten Modifier an. Ich fange die Events über eine NSWindow Classe ab die als Custom Class für das Fenster in der XiB definiert ist. Das nennt sich dann wohl Overriding?

    In der NSWindow Classe fang ich die Events mit folgendem Befehl ab.

    Quellcode

    1. - (void)sendEvent:(NSEvent *)event {
    2. NSLog(@"String: %@ ",event);
    3. }




    In diesem Stadium stören mich die festgelegte Shortcuts, die im Main Menu definiert sind. Wie Beispielsweise "command+h" dann wird "Application Hide" ausgeführt. Ich würde aber lieber eine Fehlermeldung sehen die darüber informiert das dieser Shortcut schon belegt ist.

    Im Event Handeling Guide unter Path of Key Events zeigt den Weg eines Key Events. Ich befinde mich dann wohl am "Key interface control?" Scheideweg, richtig?

    Um die Befehle für das Menu abzufangen müsste ich am "Key equivalent?" ansetzen, richtig? Wenn ich die Doku richtig verstanden habe müsste ich dazu die NSApplication Class overriden.
    Wenn ich aber eine SubClass von NSApplication erstelle und diese im Interface Builder für Application als Custom Class definiere kann ich keine Events abfangen.

    Wie in der NSWindow kann ich laut Class Reference für NSApplication auch mit....


    Quellcode

    1. -(void)sendEvent:(NSEvent *)theEvent{
    2. NSLog(@"String: %@ ",theEvent);
    3. }


    ... arbeiten. Warum funktioniert das nicht?
    Gruss zuko
  • Amin Negm-Awad schrieb:

    Du solltest dich eigentlich bei Key-Equivalents befinden.

    Has du deine Subklasse auch als Primary-Class (oder wie das im UI heißt) angegeben?


    Hallo Amin als Primary Class ganz bestimmt nicht, weil ich gar nicht weiß was man da mach muss.

    Wenn ich command +h auf dem Keyboard drücke sehe ich auch kein Event reinkommen das lässt mich zweifeln das ich mit der NSWindow Classe wirklich bei den Key-Equivalents befinde.
    Gruss zuko
  • Amin Negm-Awad schrieb:

    Wähle das Target aus und dann oben in den Tabs Info. Dann findest du einen Key "Pricncipal Class", den du auf deine Subklasse setzen musst.


    Danke Amin, das wars ich seh jetzt alle Events. Ich konnte die NSWindow Class nicht als Principal definieren es gab Fehlermeldungen.
    Mit einer NSApplication die als Custom Class in der Xib für Application definiert wurde hats dann funktioniert. Wenn ich Beispielsweise...


    Quellcode

    1. -(void)sendEvent:(NSEvent *)theEvent{
    2. if ([theEvent type] == NSKeyDown) {
    3. if ([theEvent modifierFlags] & NSCommandKeyMask && [theEvent keyCode]==4) { // Command H
    4. NSLog(@"Yes");
    5. return;
    6. }
    7. [super sendEvent: theEvent];
    8. }
    Alles anzeigen


    ...schreibe wird mit Command+H der Hide Befehl nicht mehr aufgerufen.

    Apple empfiehlt das Overriden der Principal Class nur als aller letztes Mittel und unter Key-Equivalents steht



    Key equivalents. A key equivalent is a key or key combination (usually a key modified by the Command key) that is bound typically to some menu item or control object in the application. Pressing the key combination simulates the action of clicking the control or choosing the menu item.
    The application object handles key equivalents by going down the view hierarchy in the key window, sending each object a performKeyEquivalent: message until an object returns YES. If the message isn’t handled by an object in the view hierarchy, NSApp then sends it to the menus in the menu bar. Some Cocoa classes, such as NSButton, NSMenu, NSMatrix, and NSSavePanel provide default implementations.


    Das müsste dann ja heissen das das Event Command+H bis hin zum Textfeld gesendet wird, wo ich gerade etwas eintippe bevor er ins Menu geschickt wird.
    Auf dem Weg fragt es jedes View Objekt ob es gebraucht wird. Ich müsste dann nur sagen das es gebraucht wird.

    Ich hab es mit NSMenu zunächst in der NSApplication (override) Class versucht

    Quellcode

    1. -(void)sendEvent:(NSEvent *)theEvent{
    2. if ([[[NSApplication sharedApplication]mainMenu] performKeyEquivalent:theEvent]==YES) {
    3. NSLog(@"Yes Yes");
    4. return;
    5. }
    6. [super sendEvent: theEvent];
    7. }
    Alles anzeigen


    Es wird zwar "Yes Yes" in der Konsole ausgegeben aber den Hide Befehl verhindert/ blockiert es nicht.
    Weiter unten in der Hierarchie habe ich mit einem Field Editor das selbe versucht um zu sehen ob das Event dort ankommt aber die Konsole hat nichts ausgeworfen.

    Wie sag ich dem Application object das ich das Event brauche so das es nicht ins Menu weiter geschickt wird? Am Besten ganz weit unten in der Hierarchie?
    Gruss zuko
  • Amin Negm-Awad schrieb:

    Hast du denn -perfromKeyEquivalent: überschrieben?


    Nein das ist ein ganz leeres Projekt in dem auf verschiedenen Ebenen ein Overriding angesetzt wird.

    Einmal bei NSApplication (MyApplication) als Principle Class.
    Einmal über NSWindow (MyWindow) als Delegate für das einzige Fenster im Projekt wo über...

    Quellcode

    1. - (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)client


    ...ein eigener Field Editor (MyTextView) definiert wird.

    Ich lad mal das TestprojeKt hoch. Der Field Editor lässt sich abschalten wenn man in der xib die Delegate Verbindung zum Objekt "MyWindow" löscht.

    Was auch verwirrend ist


    Quellcode

    1. -(void)sendEvent:(NSEvent *)theEvent{
    2. if ([theEvent type]== NSKeyDown) {
    3. // if ([[[NSApplication sharedApplication]mainMenu] performKeyEquivalent:theEvent]==YES) {
    4. //
    5. //
    6. // NSLog(@"Yes Yes");
    7. // //return;
    8. //
    9. //
    10. // }
    11. if ([theEvent modifierFlags] & NSCommandKeyMask && [theEvent keyCode]==4) { // blocks command+H
    12. NSLog(@"Yes");
    13. return;
    14. }
    15. NSLog(@"%@",theEvent);
    16. }
    17. [super sendEvent:theEvent];
    18. }
    Alles anzeigen


    So wird Command+H vom Hide Befehl getrennt....wird die performKeyEquivalent: Abfrage reingenommen, wird der Hide Befehl ausgeführt.
    Ich frag doch nur ob das Event vom Menu verwendet wird.

    Ist das ein Bug?
    Gruss zuko
  • zuko schrieb:

    Amin Negm-Awad schrieb:

    Willst du nicht mal -performKeyEquivalent: überschreiben?


    Achso du meinst den KeyEquivalent im Menu Item überschreiben? Ich hatte gehofft das liesse sich anders lösen.

    Nein, ich meinte, in der View-Subklasse überschreiben.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:

    zuko schrieb:

    Amin Negm-Awad schrieb:

    Willst du nicht mal -performKeyEquivalent: überschreiben?


    Achso du meinst den KeyEquivalent im Menu Item überschreiben? Ich hatte gehofft das liesse sich anders lösen.

    Nein, ich meinte, in der View-Subklasse überschreiben.


    Ich weiß jetzt nicht genau was du mit überschreiben meinst aber mit folgender Methode in irgendeiner View SubClass im Responder Chain lässt sich command+H abfangen so das der Hide Befehl nicht mehr ausgeführt wird.


    Quellcode

    1. - (BOOL)performKeyEquivalent:(NSEvent *)theEvent{
    2. if ([theEvent modifierFlags] & NSCommandKeyMask && [theEvent keyCode]==4) { // disable Command H
    3. // Do something
    4. NSLog(@"Yes");
    5. return YES;
    6. }
    7. return NO;
    8. }
    Alles anzeigen



    Danke.
    Gruss zuko
  • zuko schrieb:

    Amin Negm-Awad schrieb:

    zuko schrieb:

    Amin Negm-Awad schrieb:

    Willst du nicht mal -performKeyEquivalent: überschreiben?


    Achso du meinst den KeyEquivalent im Menu Item überschreiben? Ich hatte gehofft das liesse sich anders lösen.

    Nein, ich meinte, in der View-Subklasse überschreiben.


    Ich weiß jetzt nicht genau was du mit überschreiben meinst aber mit folgender Methode in irgendeiner View SubClass im Responder Chain lässt sich command+H abfangen so das der Hide Befehl nicht mehr ausgeführt wird.


    Quellcode

    1. - (BOOL)performKeyEquivalent:(NSEvent *)theEvent{
    2. if ([theEvent modifierFlags] & NSCommandKeyMask && [theEvent keyCode]==4) { // disable Command H
    3. // Do something
    4. NSLog(@"Yes");
    5. return YES;
    6. }
    7. return NO;
    8. }
    Alles anzeigen



    Danke.

    Genau das meinte ich.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Amin Negm-Awad schrieb:


    Genau das meinte ich.


    OkiDoki


    Chris schrieb:

    Amin Negm-Awad schrieb:


    Er will das ja nicht global, sondern in einem bestimmten Textfeld.

    ich denke eher er will in einem Textfeld den Shortcut definieren und dann global benutzen.

    Chris


    Ich denke das will ER. Danke für die Links. ich hab mich diesbezüglich schon schlau gemacht und dabei den ShortcutRecorder schon entdeckt.
    Ich finde das ist eine tolle Lösung aber ich wollte es selber verstehen und auf die Carbon API verzichten.
    Ich weiß das es unter Cocoa noch keinen vollwertigen Ersatz gibt und das die Carbon API diesbezüglich auch auf 64 bit läuft.

    Ich arbeite viel mit Shortcuts und bin der Meinung das nicht jede App ihre eigenen definieren sollte.
    Ein Beispiel: Momentan kämpfe ich gerade mit der Software meines Audio Interfaces. dort sind per Default an die 30-40 Hotkeys vordefiniert von denen ich höchstens 5 brauche.
    In der Doku wird zum einen nicht erklärt wie man diese aussschaltet und wenn man es dann herausgefunden hat und löscht ist auf einmal das "a" belegt, und lässt sich beim tippen nicht mehr verwenden. Vom Prinzip her schonmal ein Frechheit.

    Dafür gibt es Spezialisten die das besser und übersichtlicher bewerkstelligen wie Quickkeys oder Keyboard Maestro. Ich strebe eine Lösung an die mit der NSEvent Global Monitors Methode funktioniert. Das reicht vollkommen.

    Aber wo wir schonmal dabei sind. gibt es eine Methode die alle registrierten Hotkeys der laufenden Apps auflistet?
    Gruss zuko
  • "Ich habe ein TextFeld und möchte wenn es ausgewählt ist einen eigenen Keyboard Shortcut definieren."
    Für Pre-Shortcutverarbeitung muss man nicht mehr Carbon nehmen. (Das wäre ja auch schauerlich.) Man kann einen Block zuweisen:
    developer.apple.com/library/ma…entsMatchingMask:handler:
    (Local Monitor)
    Ich selbst habe es aber noch nie gemacht.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Chris schrieb:

    zuko schrieb:

    Aber wo wir schonmal dabei sind. gibt es eine Methode die alle registrierten Hotkeys der laufenden Apps auflistet?

    OSStatus CopySymbolicHotKeys (CFArrayRef *outHotKeyArray);

    Chris


    Unter Einbindung des Carbon Frameworks wirft er mit folgendem Code eine Liste aus.

    Quellcode

    1. CFArrayRef registeredHotKeys;
    2. if(CopySymbolicHotKeys(&registeredHotKeys) == noErr)
    3. {
    4. CFIndex count = CFArrayGetCount(registeredHotKeys);
    5. for(CFIndex i = 0; i < count; i++)
    6. {
    7. CFDictionaryRef hotKeyInfo = CFArrayGetValueAtIndex(registeredHotKeys, i);
    8. CFNumberRef hotKeyCode = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyCode);
    9. CFNumberRef hotKeyModifiers = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyModifiers);
    10. CFBooleanRef hotKeyEnabled = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyEnabled);
    11. NSLog(@"key code: %@ modifiers: %@ enabled: %@", hotKeyCode, hotKeyModifiers, hotKeyEnabled);
    12. }
    13. //you MUST release the dictionary when finished with it
    14. CFRelease(registeredHotKeys);
    15. }
    Alles anzeigen


    Geht das auch nur mit Cocoa?
    Weißt du aus welcher Property List die registrierten Hot Keys ausgelesen werden?


    Amin Negm-Awad schrieb:

    "Ich habe ein TextFeld und möchte wenn es ausgewählt ist einen eigenen Keyboard Shortcut definieren."
    Für Pre-Shortcutverarbeitung muss man nicht mehr Carbon nehmen. (Das wäre ja auch schauerlich.) Man kann einen Block zuweisen:
    developer.apple.com/library/ma…entsMatchingMask:handler:
    (Local Monitor)
    Ich selbst habe es aber noch nie gemacht.


    Vielleicht ist es nicht so präzise ausgedrückt aber ich meinte das das Textfeld den Shortcut darstellt.
    also wenn ich Command+shift+H drücke solls "⌘⇧ H" darstellen. Und eben bei Command H eine Fehlermeldung" ist durch Menu Item Hide belegt " .

    usw...
    Gruss zuko