Comment lier C- [pour de vrai?

10

C-[est équivalent à la touche d'échappement sur les claviers en anglais américain, ainsi, toute tentative de la lier gâchera le M-comportement.

Emacs semble avoir du mal à pas dire <escape>et à C-[part dans des cadres GUI. Les travaux suivants fonctionnent correctement et les liaisons commençant par M-restent à fonctionner:

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

Cependant, si je lie

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

soudain emacs devient fou et contraignant comme une M-xpause. De plus, presser C-[refuse de déclencher la lambda liée. Chose intéressante, C-x @ c [(appliquer le contrôle des modificateurs à la parenthèse ouverte) dit toujours C-[ is undefined.

Existe-t-il un moyen de lier quelque chose C-[sans casser emacs?

Kristóf Marussy
la source

Réponses:

7

Vous ne pouvez pas vraiment changer la C-[liaison au niveau des cartes utilisateur, comme vous le feriez avec global-set-key. Cependant, vous pouvez le modifier en tant qu'événement clavier avant qu'il n'atteigne ces images clés. Vous pouvez dire par exemple:

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

puis utiliser [control-bracketleft]dans vos keymaps. Assez simple n'est-ce pas?

Coupure du réalisateur

Malheureusement, ce n'est pas si simple, et cette solution nécessite quelques ajustements, qui sembleront très douloureux. Tu as été prévenu. Mais voyons d'abord pourquoi les cartes de niveau utilisateur ne peuvent pas répondre à la question. Dans ce qui suit, je me réfère au manuel Emacs Lisp pour emacs 26.1 quand je dis "voir quelque chose" sans plus de précision.

C-[est interprété très tôt comme le caractère de contrôle ASCII ESC(voir 21.7.1 - Événements clavier ). Ce code est réparti dans tous les autres endroits comme préfixe pour les séquences plus longues. Il y a une raison à cela: ESCest en fait le préfixe méta (voir meta-prefix-char), et toutes les liaisons qui lisent M-quelque chose se traduiront par une séquence commençant par ESC. Ainsi, changer la carte globale ne sera pas suffisant: vous devez d'abord changer meta-prefix-char, puis remapper ESCsur votre nouvelle meta-prefix-charcarte dans chaque carte utilisée M-avant de pouvoir cartographier en toute sécurité C-[.

OK alors, bien sûr: utilisons input-decode-map. Il y a quelques cartes similaires que nous pouvons être tentés d'utiliser (voir les sections 21.8.3 et 22.14), mais restons-en à celle-ci. Et bien ... ça marche! Vous avez terminé, n'est-ce pas?

En fait, non, l'histoire ne s'arrête pas là. Cela fonctionne ... tant que vous utilisez un système de fenêtre. Si, par malchance, vous êtes emprisonné dans la console Linux dans un état d'urgence, vous vous rendez compte à quel point la situation est devenue dramatique: les touches fléchées Home, et bien sûr les M-liaisons, sont toutes des ordures. Pourquoi? Parce que lorsque le terminal dit ESC(ce qu'il fait lorsque vous tapez C-[), cela signifie vraiment ESCet démarre une séquence du même type qu'il utilise pour transmettre des caractères non ASCII.

En observant la catastrophe, vous pouvez considérer qu'il est sage de protéger la input-decode-mapmodification ci-dessus de telle sorte qu'elle ne s'active que dans le cas où un système de fenêtre contrôle le clavier:

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

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

Les terminaux fonctionnent alors comme avant.

Maintenant, pouvons-nous traiter C-[sur les terminaux? En fait, oui, nous pouvons, sur la console Linux ainsi que sur les autres émulateurs de terminaux avec lesquels je peux jouer. Mais cela rend l'histoire assez longue, car de nouveaux personnages entrent en scène. Car ce n'est plus seul emacs: le terminal a désormais le rôle central.

Écoutons ce que la console Linux a à dire. Tapez C-vdevant une touche pour l'entendre clairement. C-[est ESC; il en est de même Esc. La flèche vers le haut ressemble à ESC [ A, tandis que l' M-aest ESC A. Hmm ... On dirait que cette méta-circonvolutions clés dans emacs n'est-ce pas? En tous cas.

À moins que nous sommes prêts à jouer quelques tours en fonction du temps écoulé entre les événements de caractères (qui , par ailleurs ne distinguer Escde C-[), il semble que nous avons pas d'autre choix que de dire la console ce que nous faisons pas dire ESCquand on tape C-[. De plus, il apparaît assez vite que ce C-[n'est pas le seul problème avec les codes terminaux de stock: les modificateurs sont la plupart du temps effacés des informations transmises. Nous devons personnaliser le terminal pour la même raison que nous personnalisons emacs: ce serait tellement plus pratique si nous le faisions.

À ce stade, vous oserez regarder en profondeur la documentation de votre terminal: les pages de manuel loadkeys(1)pour la console linux, pour xterm xterm(1)dans la section Liaisons de touches personnalisées et tout ce que je ne sais pas pour les autres terminaux. Dans KDE konsole, vous pouvez définir des traductions personnalisées dans Paramètres / Modifier le profil actuel ... puis Clavier . Voici un extrait ~/.local/share/konsole/Test.keytab après avoir joué avec cette dernière boîte de dialogue:

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

Une fois que vous avez l'envoi de terminal ESC O 5 [pour C-[(comme dans la configuration ci - dessus), vous pouvez revenir à emacs. Bien sûr, vous n'avez pas encore terminé.

Pour indiquer à emacs le dialecte utilisé par un terminal donné, vous pouvez ajuster input-decode-map. Oui, c'est fortuitement celui-là même que nous avons modifié au début de cette histoire, et c'est celui-là même que term/xterm.eltouche xterm. Un bon endroit pour le réglage est tty-setup-hook(voir section 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))
        )
      )))

Sachez que ce hook ne fonctionne que si vous êtes dans un terminal. Ainsi, vous ne pouvez pas insérer ici le code pour l'initialisation du système de fenêtres. Voici la fonction de traduction en elle-même:

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

Et puis vous pouvez vous reposer: c'est la fin du voyage. Bien sûr, si vous ne vous souciez pas des terminaux, c'est rapide car vous éviterez toute la partie douloureuse. Mais vous admettez que c'est aussi assez incomplet.

Deux notes finales:

  • Je choisis ESC O 5 [de coder C-[. Ce n'est qu'un exemple: je ne prétendrai pas que c'est un bon choix. Seule la 5 partie, ce qui signifie C-, semble obéir à une sorte de convention établie

  • configurer la console linux laisse un mauvais goût: il ne semble pas possible de faire la liaison sans utiliser un symbole existant intermédiaire , et ceux dont j'aurais besoin n'existent pas . J'utilise des symboles dans la plage F21- F246comme dans la plupart des exemples Internet, mais ce n'est pas très satisfaisant. C'est correct pour quelques liaisons non liées, mais cela ne servira pas de schéma systématique.

Éditer

  • J'ai complété cela avec le Esccas - qui a sa propre personnalité - dans un autre post: Comment supprimer les liaisons à la clé de préfixe ESC
  • voici un fragment d'une configuration pour se nourrir loadkeys. Je le mets dans /root/custom.kmap et le charge quand j'en ai besoin (ce qui est rare). Ma configuration actuelle mappe également des flèches et différentes combinaisons de modificateurs, mais elle est plutôt longue, le choix des symboles et des séquences est discutable, et je ne suis pas sûr que les codes clés de mon clavier correspondent aux vôtres. Gardons-le donc à son niveau: ce n'est rien d'autre qu'une 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
la source
1
Merci, c'est une excellente réponse. Mais même une excellente réponse comme celle-ci n'a sûrement pas besoin d'être renvoyée 34 fois en haut de la page d'accueil. Chaque bosse a un petit coût qui est partagé par la communauté: vérifier le spam, chercher s'il y a du nouveau contenu intéressant, etc. Peut-être pourriez-vous regrouper des améliorations mineures? Ou restez simplement avec ce que vous avez. Parlant d'expérience, il n'y a pas de poste parfait, à un moment donné, il suffit de passer à autre chose.
Gilles 'SO- arrête d'être méchant'
@Gilles J'ai compris, et désolé pour cela. Je ne savais pas qu'il y avait un problème d'ajuster cela à souhait.
Champignac
0

La solution suivante est un peu kludky, mais semble fonctionner:

Soit ~/.xbindkeysrccontenir les éléments suivants:

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

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

Maintenant xbindkeysse traduira C-[vers C-<f13>et C-]vers C-<f14>, afin qu'ils puissent être liés librement dans emacs. Vous voudrez probablement vous lier abort-recursive-edità autre chose que C-], par exemple C-S-g,.

L'inconvénient est que maintenant C-[est cassé dans toutes les applications sauf Emacs, qui pourrait être corrigé en ajoutant une logique pour tester si la combinaison de touches est envoyée à emacs ...

Kristóf Marussy
la source
FWIW, je ne pense pas qu'il y ait quelque chose de spécial C-].
Malabarba
Ouais, moi non plus, mais pour une raison étrange, ma C-]reliure a cessé de fonctionner après avoir tiré Xbindkeys, donc je rebondis aussi.
Kristóf Marussy