Wie binde ich C- [für real?

10

C-[entspricht der Escape-Taste auf US-englischen Tastaturen. Daher wird jeder Versuch, sie zu binden, das M-Verhalten durcheinander bringen .

Emacs scheint keine Probleme erzählen zu haben <escape>und C-[in GUI Rahmen auseinander. Folgendes funktioniert einwandfrei und Bindungen, die mit beginnen M-, müssen noch funktionieren:

(global-set-key (kbd "<escape>") (lambda () (interactive) (message "<escape>")))

Allerdings, wenn ich binde

(global-set-key (kbd "C-[") (lambda () (interactive) (message "C-[")))

plötzlich wird emacs verrückt und bindend wie M-xpause. Darüber hinaus C-[weigert sich das Drücken , das gebundene Lambda auszulösen. Interessanterweise C-x @ c [sagt (Modifikatorsteuerung auf offene Klammer anwenden) immer noch C-[ is undefined.

Gibt es eine Möglichkeit, etwas zu binden, C-[ohne Emacs zu brechen?

Kristóf Marussy
quelle

Antworten:

7

Sie können die C-[Bindung auf Karten auf Benutzerebene nicht wirklich ändern , wie Sie es tun würden global-set-key. Sie können es jedoch als Tastaturereignis ändern, bevor es diese Keymaps erreicht. Sie können zum Beispiel sagen:

(define-key input-decode-map 
    (kbd "C-[") 
    [control-bracketleft])

und dann [control-bracketleft]in Ihren Keymaps verwenden. Ziemlich einfach, nicht wahr?

Director's Cut

Leider ist es nicht so einfach, und diese Lösung erfordert einige Anpassungen, die sehr schmerzhaft erscheinen. Du wurdest gewarnt. Aber lassen Sie uns zuerst sehen, warum Karten auf Benutzerebene die Frage nicht beantworten können. Im Folgenden verweise ich auf das Emacs Lisp-Handbuch für Emacs 26.1, wenn ich ohne weitere Genauigkeit "etwas sehen" sage.

C-[wird sehr früh als ASCII-Steuerzeichen interpretiert ESC(siehe 21.7.1 - Tastaturereignisse ). Dieser Code wird als Präfix für längere Sequenzen an allen anderen Stellen verteilt. Dafür gibt es einen Grund: ESCIst eigentlich das Meta-Präfix (siehe meta-prefix-char), und alle Bindungen, die M-etwas lesen , werden in eine Sequenz übersetzt, die mit beginnt ESC. Daher reicht es nicht aus, die globale Karte zu ändern: Sie müssen sie zuerst ändern meta-prefix-charund dann in jeder verwendeten Karte ESCneu zuordnen , bevor Sie sie sicher zuordnen können .meta-prefix-charM-C-[

OK dann natürlich: lass uns verwenden input-decode-map. Es gibt einige ähnliche Karten, die wir möglicherweise verwenden möchten (siehe Abschnitte 21.8.3 und 22.14), aber bleiben wir bei dieser. Und nun ... das funktioniert! Du bist fertig, nicht wahr?

Nein, die Geschichte endet hier nicht. Dies funktioniert ... solange Sie ein Fenstersystem verwenden. Wenn Sie aufgrund von Pech in einem Notfallzustand in der Linux-Konsole eingesperrt sind, stellen Sie fest, wie dramatisch die Situation geworden ist: Pfeiltasten Homeund natürlich M-Bindungen sind allesamt Müll. Warum? Denn wenn das Terminal sagt ESC(was es bei der Eingabe tut C-[), bedeutet dies wirklich ESC, dass eine Sequenz der gleichen Art gestartet wird, mit der Nicht-ASCII-Zeichen übertragen werden.

Wenn Sie die Katastrophe beobachten, können Sie es für sinnvoll halten, die oben genannte input-decode-mapÄnderung so zu schützen , dass sie nur aktiviert wird, wenn ein Fenstersystem die Tastatur steuert:

(let ((frame (framep (selected-frame))))
  (or (eq  t  frame)
      (eq 'pc frame)

      (define-key input-decode-map 
                  (kbd "C-[") 
                  [control-bracketleft])
     )))

Die Terminals funktionieren dann wie früher.

Können wir uns jetzt mit C-[Terminals befassen ? Ja, das können wir sowohl auf der Linux-Konsole als auch auf den anderen Terminal-Emulatoren, mit denen ich spielen kann. Aber das macht die Geschichte ziemlich lang, da neue Charaktere die Szene betreten. Denn es sind nicht mehr nur Emacs: Das Terminal hat jetzt die zentrale Rolle.

Lassen Sie uns ein Ohr für das haben, was die Linux-Konsole zu sagen hat. Geben Sie C-vvor einer Taste ein, um sie deutlich zu hören. C-[ist ESC; so ist es Esc. Der Aufwärtspfeil klingt wie ESC [ A, solange es M-aist ESC A. Hmm ... Sieht so aus, als ob diese Meta-Key-Umwälzungen in Emacs nicht wahr sind? Wie auch immer.

Es sei denn , wir sind bereit , ein paar Tricks auf der Grundlage der Zeit zwischen den Zeichen Ereignissen verstrichene zu spielen (die übrigens nicht unterscheiden Escvon C-[), es scheint , dass wir keine andere Wahl haben , aber die Konsole zu sagen , was wir tun , eigentlich nicht gemein ESCwenn wir tippen C-[. Darüber hinaus scheint es ziemlich bald so zu sein, dass dies C-[nicht das einzige Problem mit Standard-Terminalcodes ist: Modifikatoren werden die übertragenen Informationen meistens gelöscht. Wir müssen das Terminal aus dem gleichen Grund anpassen, aus dem wir Emacs anpassen: Es wäre viel praktischer, wenn wir dies tun würden.

An dieser Stelle sollten Sie einen tiefen Blick in die Dokumentationsaugen Ihres Terminals werfen: Manpages loadkeys(1)für die Linux-Konsole, für xterm xterm(1)im Abschnitt Benutzerdefinierte Tastenkombinationen und alles , was ich für andere Terminals nicht weiß . In KDE konsolekönnen Sie benutzerdefinierte Übersetzungen unter Einstellungen / Aktuelles Profil bearbeiten ... und dann Tastatur definieren . Hier ist ein Auszug aus ~/.local/share/konsole/Test.keytab dem letzten Dialog:

key [+Ctrl+AnyModifier : "\EO*["

Sobald Sie das Terminal senden haben ESC O 5 [für C-[(wie in der obigen Konfiguration) können Sie auf Emacs zurück. Natürlich bist du noch nicht fertig.

Um Emacs anzuweisen, welchen Dialekt ein bestimmtes Terminal verwendet, können Sie ihn anpassen input-decode-map. Ja, dies ist zufällig genau das, was wir zu Beginn dieser Geschichte geändert haben, und dies ist term/xterm.elgenau das, was berührt wird, wenn es um xterm geht. Ein guter Ort für die Anpassung ist tty-setup-hook(siehe Abschnitt 40.1.3):

(add-hook 'tty-setup-hook 
   (lambda ()
    (let ((term (getenv "TERM")))
      (cond 
        (;; xterm-function-map not in doc, but in term/xterm.el
         (boundp 'xterm-function-map) 
         (map-my-term-codes xterm-function-map))

        ((equal term "linux")
         (map-my-term-codes input-decode-map))
        )
      )))

Beachten Sie, dass dieser Hook nur ausgeführt wird, wenn Sie sich in einem Terminal befinden. Daher können Sie hier den Code für die Fenstersysteminitialisierung nicht einfügen. Hier ist die Übersetzungsfunktion für sich:

(defun map-my-term-codes (map)
      (define-key map (kbd "M-O 5 [") 
                      [control-bracketleft])
      )

Und dann können Sie sich etwas ausruhen: Es ist das Ende der Reise. Wenn Sie sich nicht für Terminals interessieren, können Sie natürlich schnell den ganzen schmerzhaften Teil überspringen. Aber Sie werden zugeben, dass es auch ziemlich unvollständig ist.

Zwei abschließende Anmerkungen:

  • Ich entscheide mich ESC O 5 [für Code C-[. Dies ist nur ein Beispiel: Ich werde nicht so tun, als wäre es eine gute Wahl. Nur der 5 Teil, das heißt C-, scheint einer etablierten Konvention zu gehorchen

  • Die Konfiguration der Linux-Konsole hinterlässt einen schlechten Geschmack: Es scheint nicht möglich zu sein, die Bindung ohne Verwendung eines vorhandenen Zwischensymbols durchzuführen, und diejenigen, die ich benötigen würde , existieren nicht . Ich verwende Symbole im Bereich F21- F246wie in den meisten Internetbeispielen, aber es ist nicht sehr zufriedenstellend. Es ist in Ordnung für ein paar nicht verwandte Bindungen, aber es wird kein systematisches Schema dienen.

Bearbeiten

  • Ich habe dies mit dem EscFall abgeschlossen - der seine eigene Persönlichkeit hat - in einem anderen Beitrag: So entfernen Sie Bindungen an den ESC-Präfixschlüssel
  • Hier ist ein Fragment einer Konfiguration, mit der gefüttert loadkeyswerden soll. Ich füge dies in /root/custom.kmap ein und lade es, wenn ich muss (was selten ist). Meine eigentliche Konfiguration ordnet auch Pfeile und verschiedene Kombinationen von Modifikatoren zu, aber es ist ziemlich lang, die Auswahl von Symbolen und Sequenzen ist fraglich und ich bin nicht sicher, ob die Tastencodes für meine Tastatur mit Ihren übereinstimmen. Lassen Sie es uns also auf dem richtigen Niveau halten: Dies ist nichts anderes als eine Illustration.

    keymaps 0-127
    
    # http://tldp.org/HOWTO/Keyboard-and-Console-HOWTO-15.html
    # web+man:keymaps
    # web+man:loadkeys
    
    # escape
    keycode  1  = F100
        alt keycode  1 = Escape # keep the Escape behavior somewhere          
    
    # keycode  26 = bracketleft
        control keycode 26 = F115 # Control_bracketleft does not exist          
    
    string F100     = "\033OO" # map this to [escape] in map-my-term-codes
    string F115     = "\033O5["
    
Champignac
quelle
1
Danke, das ist eine großartige Antwort. Aber sicherlich muss auch eine großartige Antwort wie diese 34 Mal nicht ganz oben auf der Titelseite stehen. Jede Beule hat geringe Kosten, die von der Community geteilt werden: Nach Spam suchen, nach neuen interessanten Inhalten suchen usw. Vielleicht könnten Sie kleinere Verbesserungen zusammenfassen? Oder bleib einfach bei dem, was du hast. Erfahrungsgemäß gibt es keinen perfekten Beitrag, irgendwann muss man einfach weitermachen.
Gilles 'SO - hör auf böse zu sein'
@ Gilles Verstanden, und tut mir leid. Mir war nicht bewusst, dass es ein Problem gab, dies auf Wunsch anzupassen.
Champignac
0

Die folgende Lösung ist etwas klobig, scheint aber zu funktionieren:

Lassen Sie ~/.xbindkeysrcFolgendes enthalten:

"xvkbd -xsendevent -text '\[Control_L]\[F13]'"
  m:0x14 + c:34

"xvkbd -xsendevent -text '\[Control_L]\[F14]'"
  m:0x14 + c:35

Jetzt xbindkeyswird C-[zu C-<f13>und C-]zu übersetzt C-<f14>, damit sie frei in Emacs gebunden werden können. Sie werden wahrscheinlich abort-recursive-editan etwas anderes als C-]zum Beispiel binden wollen C-S-g.

Der Nachteil ist, dass jetzt C-[in jeder Anwendung außer Emacs ein Fehler auftritt, der durch Hinzufügen einer Logik behoben werden kann, um zu testen, ob die Tastenkombination an Emacs gesendet wird ...

Kristóf Marussy
quelle
FWIW, ich glaube nicht, dass es etwas Besonderes gibt C-].
Malabarba
Ja, ich auch nicht, aber aus irgendeinem Grund C-]funktionierte meine Bindung nicht mehr, nachdem ich Xbindkeys gestartet hatte, also habe ich auch diese zurückgebunden.
Kristóf Marussy