Shortcuts in App für Service festlegen/ändern

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Shortcuts in App für Service festlegen/ändern

    Hallo!

    Ich habe eine App erstellt, die einen Service anbietet. Dieser lässt sich bei markierten
    Texten aus anderen Programmen aufrufen. Um die App schnell aufrufen zu können, wollte
    ich ein Tastaturkürzel vergeben. Das funktioniert auch gut, wenn ich es in der Info.plist
    fest vorgebe. Falls der Anwender ein anderes Kürzel verwenden möchte (evtl. gibt es
    das bei ihm ja schon für andere Programme), muss er dies bisher in den Systemeinstellungen
    machen. Das scheint mir nicht sehr anwenderfreundlich, denn dieser muss erst einmal
    wissen, dass er das nicht in der App selbst sondern nur in den Systemeinstellungen
    ändern kann und dann den richtigen Eintrag in einer recht langen Liste finden.

    Meine bisherige Suche nach Lösungen, um selbst das Kürzel ändern zu können, hat
    mich zu Tipps geführt, die ~/Library/Preferences/pbs.plist zu ändern oder per Script
    Systemeinstellungen aufzurufen und Einträge zu ändern.

    Ersteres funktioniert nicht. Meine App kann zwar die pbs.plist ändern, aber selbst
    nach einem Neustart hat der dortige Eintrag keine Wirkung. Ich vermute, dass - wie in
    einem Eintrag bei StackOverflow angedeutet - das bei den neueren Versionen von OS X
    nicht mehr funktioniert. Evtl. muss ein spezieller Befehl zur Synchronisation aufgerufen
    werden, den vermutlich nur Apple kennt.

    Die Lösung, skriptgesteuert Systemeinstellungen aufzurufen und zu manipulieren,
    fand ich einerseits aufwändig und andererseits auch suboptimal, da der Anwender
    nicht damit rechnen wird, dass sich die Systemeinstellungen öffnen.

    Meine Hoffnung ist, dass jemand im Forum noch eine gute Idee hat, wie es anders
    funktionieren könnte.

    Noch eine Frage zur Vorgabe des Kürzels: gibt es ein Tool, das auf einem System
    die schon verwendeten Kürzel ermittelt und sortiert ausgibt? Vielleicht sogar eine
    "invertierte" Ausgabe erstellt, die die noch verfügbaren Kürzel anzeigt?

    Grüße
    Marco
  • Status der Dienste

    Wie schon geschrieben, führten mich Tipps zu ~/Library/Preferences/pbs.plist . Die Datei beginnt bei mir mit:

    Quellcode

    1. {
    2. NSServicesStatus = {
    3. "com.apple.FileMerge - FileMerge/Compare Files - diffFilesService" = {
    4. "enabled_context_menu" = 1;
    5. "enabled_services_menu" = 1;
    6. };
    7. "com.apple.SummaryService - Summarize - doSummarization" = {
    8. "enabled_context_menu" = 1;
    9. "enabled_services_menu" = 1;
    10. };
    11. "com.apple.TextEdit - New TextEdit Window Containing Selection - openSelection" = {
    12. "enabled_context_menu" = 1;
    13. "enabled_services_menu" = 1;
    14. "key_equivalent" = "@~$t";
    15. };
    Alles anzeigen

    Es gibt keine Struktur parallel zu NSServicesStatus. Generell scheint jeder Eintrag anzugeben, ob der Dienst über
    Services-Menü und Kontext-Menü nutzbar ist und ggf. noch den Shortcut (key_equivalent). Dazu habe ich dann
    folgende Klasse erstellt:

    Quellcode

    1. class ServiceStatus {
    2. var enabled_context_menu = false
    3. var enabled_services_menu = false
    4. var key_equivalent = ShortcutKey(shortCutDisplayText: "")
    5. }

    ShortcutKey ist eine Klasse, in der insbesondere eine Abbildung von der Darstellung wie in der pbs.plist
    oder von einem NSEvent in ein internes Format geschieht. Das interne Format verwendet die Symbole,
    die auch in den Menüs verwendet werden.


    Status verändert speichern

    Der Inhalt der Datei lässt sich über
    1. "defaults read ~/Library/Preferences/pbs.plist ",
    2. NSDictionary(contentsOfFile: "~/Library/Preferences/pbs.plist ") und
    3. CFPreferencesCopyAppValue(key, appDomain)


    auslesen. Aber es macht tatsächlich einen Unterschied, welchen Weg man beim Schreiben wählt.
    Zuerst hatte ich das angepasste Dictionary 'newDict' mit folgendem Code gespeichert.


    Quellcode

    1. let data = try NSPropertyListSerialization.dataWithPropertyList(newDict, format: NSPropertyListFormat.BinaryFormat_v1_0, options: 0)
    2. data.writeToFile("~/Library/Preferences/pbs.plist", atomically: true)
    Der neue Inhalt mit angepasstem Shortcut wurde auch wieder korrekt gelesen (im Programm und mit
    defaults read). Nur ließ sich mein Dienst nicht über den neuen Shortcut aktivieren. Auch das Ändern
    von enabled_context_menu und enabled_services_menu hatte keinen Effekt.

    Mit CFPreferences ist das Schreiben jetzt nur noch ein Aufruf. Und damit geschriebene Daten werden
    auch vom System wie gewünscht verwendet, so dass ich nun aus meinem Programm heraus den
    Shortcut ändern kann.

    Quellcode

    1. CFPreferencesSetAppValue("NSServicesStatus", newDict, "pbs")


    Offene Fragen

    Im Prinzip funktioniert es schon. Aber leider doch nicht ganz richtig.
    1. Das Tastaturkürzel ist erst nach einem Neueinloggen aktualisiert.
    2. Das Aktivieren eines Dienstes klappt nicht.
    Beides funktioniert bei Änderung in Systemeinstellungen sofort.
    CFPreferencesSynchronize hat nicht geholfen.
    Außerdem ist bei einem Dienst ein Shortcut in der Info.plist definiert und
    der taucht nun nicht in der pbs.plist auf, ist aber aktiv.

    Bin mir gerade unsicher, was am Dienstag genau funktioniert hat. Ich werde
    da wohl doch noch länger brauchen als ich bis gerade gehofft hatte.


    Anmerkungen

    Der Code zum Umgestallten des Dictionaries (Einpflegen der Änderungen des Anwenders) ist leider nicht
    so elegant. Ich bin noch dabei, diesen besser lesbar zu machen,

    Zum Testen habe ich anfangs die Pfade hardcoded verwendet, aber dann natürlich schrittweise auf
    Verwendung von NSSearchPathForDirectoriesInDomains umgestellt.
  • marcoo schrieb:

    2. Das Aktivieren eines Dienstes klappt nicht.
    Mit dem Kommandozeilentool pbs(8) kannst du OSX dazu veranlassen, das Servicemenü neu aufzubauen.

    Shell-Script

    1. #!/bin/bash
    2. # Set preference to enabled
    3. defaults write pbs NSServicesStatus -dict-add "<app-id> - <service-name> - perform" "<dict><key>enabled_context_menu</key><true/><key>enabled_services_menu</key><true/></dict>"
    4. # Clear menu cache
    5. /System/Library/CoreServices/pbs -flush
    6. # Restart pasteboard service
    7. defaultLanguage=`defaults read .GlobalPreferences AppleLanguages | tr -d [:space:] | cut -c2-3`
    8. languages="default en English $defaultLanguage"
    9. for language in $languages
    10. do
    11. /System/Library/CoreServices/pbs $language
    12. done
    Alles anzeigen
    „Meine Komplikation hatte eine Komplikation.“
  • Danke für das Script. Die man-page von defaults hatte ich so verstanden, dass ich auf der Ebene keine
    Einträge hinzufügen kann, sondern nur auf oberster. Und ich wusste nicht, dass man die Einträge auch
    mit xml definieren kann.

    Bei dem auf meinem Mac (Yosemite) installierten pbs kann man alle Sprachen in einem Aufruf angeben.
    Die Ausgabe gleicht der beim Aufruf mit English alleine.

    Quellcode

    1. /System/Library/CoreServices/pbs $languages
    Mit der App habe ich verschiedene Vorgehensweisen ausprobiert. Es reicht offenbar, wenn ich
    nach dem Schreiben der pbs.plist (in der App ja nun mit CFPreferencesSetAppValue) den Aufruf
    des Programms /System/Library/CoreServices/pbs mit -flush mache. Das passt auch zu
    meinem Verständnis der man-page: "The next time Services information is needed, pbs will do a
    complete rescan for apps vending Services, and read their plist." steht bei -flush. Zur language steht
    dort "You may pass pbs language codes (e.g. "fr") to cause it to load that localization immediately.",
    was bei mir nicht notwendig ist, da ich die localization nicht in der App ändere.


    Die Probleme, die ich zeitweise hatte, lagen vermutlich daran, dass ich aus der App heraus einen
    falschen Methodennamen und einen anderen Menütext als in der Info.plist geschrieben hatte - den
    Text zwischen AppId und Methodenname interpretiere ich nun als Menütext der default-Sprache.


    Bleibt noch das Problem mit dem Programm pbs: Apple schreibt in der Doku zu den Services explizit,
    dass keine App sich auf pbs verlassen sollte, und dass pbs evtl. verändert oder entfernt wird. Die
    Systemeinstellungen scheinen pbs auch nicht zu verwenden. Ich werde noch versuchen, hierzu
    eine Alternative zu finden und das Ergebnis dann vorstellen.