Как связать С- [по-настоящему?

10

C-[эквивалентно клавише escape на американских клавиатурах на английском языке, поэтому любая попытка его связывания испортит M-поведение.

Emacs, кажется, без проблем рассказывает <escape>и C-[разбирается в кадрах GUI. Следующее работает нормально, и привязки, начиная с, M-остаются работать:

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

Однако, если я связываю

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

внезапно Emacs сходит с ума и связывает, как M-xразрыв. Более того, нажатие C-[отказывает в запуске связанной лямбды. Интересно, что C-x @ c [(применить контроль модификатора к открытой скобке) все еще говорит C-[ is undefined.

Есть ли способ связать что-либо, C-[не нарушая emacs?

Кристоф Марусси
источник

Ответы:

7

Вы не можете изменить C-[привязку на картах уровня пользователя, как вы это сделали бы global-set-key. Однако вы можете изменить его как событие клавиатуры, прежде чем оно достигнет этих раскладок. Вы можете сказать, например:

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

а затем использовать [control-bracketleft]в ваших клавишных картах. Довольно просто, не правда ли?

Режиссерский крой

К сожалению, это не так просто, и это решение требует некоторых корректировок, которые окажутся очень болезненными. Вы были предупреждены. Но давайте сначала посмотрим, почему карты уровня пользователя не могут ответить на этот вопрос. Далее я обращаюсь к руководству по Emacs Lisp для emacs 26.1, когда я говорю «вижу что-то» без большей точности.

C-[на очень ранней стадии интерпретируется как управляющий символ ASCII ESC(см. 21.7.1 - События клавиатуры ). Этот код распространяется на все остальные места в качестве префикса для более длинных последовательностей. Для этого есть причина: ESCна самом деле это мета-префикс (см. meta-prefix-char), И все привязки, которые читают M-что-либо , преобразуются в последовательность, которая начинается с ESC. Таким образом, изменения глобальной карты будет недостаточно: вам нужно сначала изменить meta-prefix-char, а затем переназначить ESCновую meta-prefix-charв каждой и каждой карте, которая используется, M-прежде чем вы сможете безопасно отобразить карту C-[.

Хорошо, тогда, конечно: давайте использовать input-decode-map. Есть пара похожих карт, которые мы можем использовать (см. Разделы 21.8.3 и 22.14), но давайте придерживаться этого. И хорошо ... это работает! Вы сделали, не так ли?

На самом деле, нет, история не заканчивается здесь. Это работает ... пока вы используете оконную систему. Если из-за неудачи вы оказались в тюрьме в консоли linux в аварийном состоянии, вы понимаете, насколько драматичной стала ситуация: клавиши со стрелками Homeи, конечно же, M-привязки - все это мусор. Почему? Потому что, когда терминал говорит ESC(что он делает, когда вы печатаете C-[), это действительно означает ESC и запускает последовательность того же вида, которую он использует для передачи не-ASCII символов.

Наблюдая за катастрофой, вы можете посчитать целесообразным защитить вышеуказанную input-decode-mapмодификацию таким образом, чтобы она активировалась только в том случае, если оконная система управляет клавиатурой:

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

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

Затем терминалы работают так, как раньше.

Теперь мы можем иметь дело с C-[терминалами? На самом деле, да, мы можем, как на консоли Linux, так и на других эмуляторах терминала, с которыми я могу играть. Но это делает историю довольно длинной, поскольку новые персонажи выходят на сцену. Ведь это уже не один emacs: терминал теперь играет центральную роль.

Давайте послушаем, что говорит консоль Linux. Введите C-vперед каким-нибудь ключом, чтобы услышать это ясно. C-[есть ESC; так и есть Esc. Стрелка вверх звучит как ESC [ A, пока M-aесть ESC A. Хмм ... Похоже, это мета-ключевые извилины в Emacs, не так ли? Тем не мение.

Если мы не готовы сыграть некоторые трюки, основанные на времени, прошедшем между событиями персонажа (которые, кстати, не будут отличаться Escот других C-[), похоже, у нас нет другого выбора, кроме как сказать консоли, что мы на самом деле не имеем в виду ESCкогда мы наберем C-[. Более того, довольно скоро выясняется, что C-[это не единственная проблема со стандартными кодами терминала: модификаторы в большинстве случаев стирают передаваемую информацию. Нам нужно настроить терминал по той же причине, по которой мы настраиваем emacs: было бы намного практичнее, если бы мы это сделали.

На этом этапе вы должны осмотреть глаза документации вашего терминала: справочные страницы loadkeys(1)для консоли linux, xterm xterm(1)в разделе « Привязки пользовательских клавиш» и все , что я знаю для других терминалов. В KDE konsole, вы можете определить собственные переводы в Настройки / Редактировать текущий профиль ... затем Клавиатура . Вот выдержка из ~/.local/share/konsole/Test.keytab игры с этим последним диалогом:

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

После того, как терминал отправит ESC O 5 [запрос C-[(как в приведенной выше конфигурации), вы можете вернуться к emacs. Конечно, вы еще не закончили.

Чтобы указать emacs, какой диалект использует данный терминал, вы можете настроить его input-decode-map. Да, к счастью, это тот самый, который мы изменили в начале этой истории, и это тот самый момент, term/xterm.elк которому относится xterm. Хорошее место для настройки tty-setup-hook(см. Раздел 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))
        )
      )))

Имейте в виду, что этот хук работает, только если вы находитесь в терминале. Таким образом, вы не можете вставить сюда код для инициализации оконной системы. Вот функция перевода сама по себе:

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

И тогда вы можете немного отдохнуть: это конец пути. Конечно, если вам не нужны терминалы, это быстро, так как вы пропустите всю болезненную часть. Но вы признаете, что это также довольно неполно.

Две последние заметки:

  • Я выбираю ESC O 5 [для кода C-[. Это всего лишь пример: я не буду притворяться, что это хороший выбор. Только та 5 часть, которая означает C-, кажется, подчиняется какой-то установленной конвенции

  • настройка консоли linux оставляет плохой вкус: кажется, что связывание невозможно без использования промежуточного существующего символа, а те, которые мне нужны , не существуют . Я использую символы в диапазоне F21- F246как в большинстве интернет-примеров, но это не очень хорошо. Это нормально для нескольких несвязанных привязок, но это не будет служить систематической схеме.

редактировать

  • Я закончил это с Escделом - которое имеет свою индивидуальность - в другом посте: Как удалить привязки к префиксному ключу ESC
  • Вот фрагмент конфигурации для кормления loadkeys. Я помещаю это в /root/custom.kmap и загружаю, когда мне нужно (что редко). Моя фактическая конфигурация также отображает стрелки и различные комбинации модификаторов, но она довольно длинная, выбор символов и последовательностей сомнителен, и я не уверен, что коды клавиш для моей клавиатуры будут совпадать с вашими. Так что давайте держать его на должном уровне: это не что иное, как иллюстрация.

    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
источник
1
Спасибо, это отличный ответ. Но, конечно, даже такой замечательный ответ, как этот, несомненно, не нужно поднимать до верхней части первой страницы 34 раза. У каждого удара есть небольшая цена, которую разделяет сообщество: проверка на спам, поиск нового интересного контента и т. Д. Может быть, вы могли бы объединить небольшие улучшения вместе? Или просто придерживайтесь того, что у вас есть. Судя по опыту, идеального поста не бывает, в какой-то момент вам просто нужно двигаться дальше.
Жиль "ТАК - перестать быть злым"
@ Жиль Понял, и извините за это. Я не знал, что есть некоторая проблема, регулирующая это по желанию.
Champignac
0

Следующее решение немного клудко, но, похоже, работает:

Позвольте ~/.xbindkeysrcсодержать следующее:

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

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

Теперь xbindkeysпереведем C-[к C-<f13>и C-]к C-<f14>, так что они могут быть связаны в Emacs свободно. Вы, вероятно, захотите связать abort-recursive-editчто-то, кроме C-], например C-S-g,.

Недостатком является то, что теперь C-[это не работает во всех приложениях, кроме Emacs, что можно исправить, добавив некоторую логику, чтобы проверить, отправляется ли комбинация клавиш в emacs ...

Кристоф Марусси
источник
FWIW, я не думаю, что есть что-то особенное C-].
Малабарба
Да, я C-]тоже , но по какой-то странной причине моя привязка перестала работать после того, как я запустил Xbindkeys, так что я тоже отскочил.
Кристоф Марусси