Jak powiązać C- [naprawdę?

10

C-[jest równoważny klawiszowi Escape na klawiaturach w języku angielskim w USA, dlatego każda próba powiązania go popsunie M-zachowanie.

Emacs wydaje się nie mieć problemy z odróżnieniem <escape>i C-[osobno w klatkach GUI. Następujące elementy działają poprawnie, a wiązania zaczynające się od M-pozostają nadal aktywne:

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

Jeśli jednak powiążę

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

nagle emacs szaleje i wiąże się jak M-xbreak. Ponadto naciśnięcie C-[odmawia uruchomienia związanej lambda. Co ciekawe, C-x @ c [(zastosowanie kontroli modyfikatora do otwartego nawiasu) wciąż mówi C-[ is undefined.

Czy jest jakiś sposób na powiązanie czegoś C-[bez zerwania emacsa?

Kristóf Marussy
źródło

Odpowiedzi:

7

Nie można tak naprawdę zmienić C-[powiązania na mapach na poziomie użytkownika, tak jak zrobiłbyś to global-set-key. Można go jednak zmienić jako zdarzenie na klawiaturze, zanim dotrze do tych map klawiszy. Możesz powiedzieć na przykład:

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

a następnie użyj [control-bracketleft]w swoich mapach klawiszy. Całkiem proste, prawda?

Wersja reżyserska

Niestety nie jest to takie proste, a to rozwiązanie wymaga pewnych korekt, które będą bardzo bolesne. Zostałeś ostrzeżony. Ale najpierw zobaczmy, dlaczego mapy na poziomie użytkownika nie mogą odpowiedzieć na pytanie. W dalszej części odsyłam do instrukcji Emacs Lisp dla emacsa 26.1, kiedy mówię „zobacz coś” bez większej precyzji.

C-[jest interpretowany na bardzo wczesnym etapie jako znak kontrolny ASCII ESC(patrz 21.7.1 - Zdarzenia klawiatury ). Ten kod jest rozłożony na inne miejsca jako prefiks dla dłuższych sekwencji. Jest tego powód: w ESCrzeczywistości jest to prefiks meta (patrz meta-prefix-char), a wszystkie wiązania, które czytają M-coś, zostaną przetłumaczone na sekwencję, która zaczyna się od ESC. Dlatego zmiana mapy globalnej nie wystarczy: najpierw musisz zmienić meta-prefix-char, a następnie zmienić mapowanie ESCna nową meta-prefix-charna każdej mapie, z której korzysta, M-zanim będzie można bezpiecznie mapować C-[.

OK, oczywiście: użyjmy input-decode-map. Istnieje kilka podobnych map, których możemy ulec pokusie (patrz rozdziały 21.8.3 i 22.14), ale trzymajmy się tej. No cóż ... to działa! Skończyłeś, prawda?

Właściwie nie, historia nie kończy się tutaj. Działa to ... dopóki używasz systemu okiennego. Jeśli z powodu pecha zostałeś uwięziony w konsoli Linuksa w stanie wyjątkowym, zdajesz sobie sprawę, jak dramatyczna stała się sytuacja: klawisze strzałek Homei, oczywiście, M-powiązania są śmieciami. Dlaczego? Ponieważ kiedy terminal mówi ESC(co robi podczas pisania C-[), naprawdę oznacza to ESC i rozpoczyna sekwencję tego samego rodzaju, której używa do przesyłania znaków spoza ASCII.

Obserwując katastrofę, możesz uznać, że rozsądnie jest chronić powyższą input-decode-mapmodyfikację w taki sposób, aby aktywowała się tylko w przypadku, gdy system okien kontroluje klawiaturę:

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

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

Terminale działają wtedy tak, jak kiedyś.

Czy możemy sobie teraz poradzić C-[na terminalach? Właściwie tak, możemy, zarówno na konsoli Linux, jak i na innych emulatorach terminali, z którymi mogę grać. Ale to sprawia, że ​​historia jest dość długa, ponieważ nowe postacie wkraczają na scenę. Ponieważ nie jest to już tylko emacs: terminal pełni teraz centralną rolę.

Przyjrzyjmy się, co ma do powiedzenia konsola Linux. Wpisz C-vprzed jakimś klawiszem, aby usłyszeć to wyraźnie. C-[jest ESC; tak jest Esc. Strzałka w górę brzmi jak ESC [ A, gdy M-ajest ESC A. Hmm ... Wygląda na to, że ten meta-kluczowy obieg w emacsie, prawda? Tak czy siak.

O ile nie jesteśmy gotowi zagrać w niektóre sztuczki w oparciu o czas, jaki upłynął między wydarzeniami postaci (które, nawiasem mówiąc, nie odróżniają się Escod nich C-[), wydaje się, że nie mamy wyboru, jak tylko powiedzieć konsoli, co tak naprawdę nie mamy na myśli ESCkiedy piszemy C-[. Co więcej, wkrótce wydaje się, że C-[nie jest to jedyny problem z zapasowymi kodami terminali: modyfikatory są w większości przypadków usuwane z przesyłanych informacji. Musimy dostosować terminal z tego samego powodu, dla którego dostosowujemy emacs: byłoby to o wiele bardziej praktyczne, gdybyśmy to zrobili.

W tym momencie odważysz się spojrzeć głęboko w dokumentację terminala: strony loadkeys(1)podręcznika użytkownika dla konsoli Linux, xterm xterm(1)w sekcji Niestandardowe przypisania klawiszy i cokolwiek innego dla innych terminali. W KDE konsolemożesz zdefiniować niestandardowe tłumaczenia w Ustawieniach / Edytuj bieżący profil ... a następnie Klawiatura . Oto fragment z ~/.local/share/konsole/Test.keytab gry w tym ostatnim oknie dialogowym:

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

Po wysłaniu terminala ESC O 5 [do C-[(jak w powyższej konfiguracji) możesz wrócić do emacsa. Oczywiście jeszcze nie skończyłeś.

Aby poinstruować emacsa, jakiego dialektu używa dany terminal, możesz dostosować input-decode-map. Tak, to na szczęście ten, który zmodyfikowaliśmy na początku tej historii, i to jest ten, który term/xterm.eldotyka, gdy zaangażowany jest xterm. Dobrym miejscem do regulacji jest tty-setup-hook(patrz punkt 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))
        )
      )))

Pamiętaj, że ten hak działa tylko wtedy, gdy jesteś w terminalu. Dlatego nie można wstawić tutaj kodu inicjującego system okien. Oto sama funkcja tłumaczenia:

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

A potem możesz odpocząć: to koniec podróży. Oczywiście, jeśli nie przejmujesz się terminalami, jest to szybkie, ponieważ pominiesz wszystkie bolesne części. Ale przyznasz, że jest również raczej niekompletny.

Dwie końcowe uwagi:

  • Wybieram ESC O 5 [kod C-[. To tylko przykład: nie będę udawać, że to dobry wybór. Tylko ta 5 część, która oznacza C-, wydaje się przestrzegać jakiejś ustalonej konwencji

  • konfiguracja konsoli linux pozostawia zły gust: nie wydaje się możliwe wykonanie powiązania bez użycia pośredniego istniejącego symbolu, a te, których potrzebowałbym , nie istnieją . Używam symboli z zakresu F21- F246jak w większości przykładów internetowych, ale nie jest to zbyt satysfakcjonujące. Jest OK dla kilku niepowiązanych powiązań, ale nie posłuży do systematycznego schematu.

Edytować

  • Skończyłem to ze Escsprawą - która ma swoją osobowość - w innym poście: Jak usunąć powiązania z kluczem prefiksu ESC
  • tutaj jest fragment konfiguracji, którą można karmić loadkeys. Umieszczam to w /root/custom.kmap i ładuję, kiedy trzeba (co jest rzadkie). Moja aktualna konfiguracja mapuje również strzałki i różne kombinacje modyfikatora, ale jest dość długa, wybór symboli i sekwencji jest wątpliwy i nie jestem pewien, czy kody klawiszy dla mojej klawiatury będą pasować do twojej. Trzymajmy to na właściwym poziomie: to tylko ilustracja.

    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
źródło
1
Dzięki, to świetna odpowiedź. Ale z pewnością nawet taka świetna odpowiedź z pewnością nie musi być podnoszona 34 razy na górę pierwszej strony. Każda nierówność ma niewielki koszt, który jest wspólny dla społeczności: sprawdzanie spamu, sprawdzanie, czy są nowe ciekawe treści itp. Może możesz zgrupować drobne ulepszenia razem? Lub po prostu trzymaj się tego, co masz. Mówiąc z doświadczenia, nie ma czegoś takiego jak idealny post, w pewnym momencie musisz po prostu przejść dalej.
Gilles 'SO - przestań być zły'
@Gilles Rozumiem i przepraszam za to. Nie wiedziałem, że jest jakiś problem z dostosowaniem tego na życzenie.
Champignac
0

Poniższe rozwiązanie jest nieco nieprzyzwoite, ale wydaje się działać:

Niech ~/.xbindkeysrczawierają następujące elementy:

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

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

Teraz xbindkeysbędą tłumaczyć się C-[na C-<f13>i C-]na C-<f14>, aby mogli być swobodnie związani w emacs. Prawdopodobnie będziesz chciał powiązać abort-recursive-editcoś innego niż C-], na przykład C-S-g.

Minusem jest to, że teraz C-[jest zepsuta w każdej aplikacji oprócz Emacsa, co można naprawić, dodając logikę do testowania, czy kombinacja klawiszy jest wysyłana do emacsa ...

Kristóf Marussy
źródło
FWIW, nie sądzę, żeby było w tym coś specjalnego C-].
Malabarba
Tak, ja też, ale z jakiegoś dziwnego powodu moje C-]wiązanie przestało działać po tym, jak uruchomiłem Xbindkeys, więc też go odbiłem.
Kristóf Marussy