Рамки GUI
В фреймах GUI (X11, Windows, OSX,…) Emacs считывает Tabключ как tab
функциональную клавишу. Однако, поскольку Tabклавиша на терминалах традиционно отправляет символ ^I
( Control + I), Emacs переводит tab
функциональную клавишу в символ Control + I (символ 9), который отображается как TAB
. Этот перевод сделан через function-key-map
.
Аналогичный перевод происходит с некоторыми другими функциональными клавишами. ( Backspaceи Deleteэто сложный случай, который я не буду подробно обсуждать здесь.)
Function key Translated to character Notes
Number Name Decomposition
backspace 127 DEL Ctrl+? May be translated to C-h instead
tab 9 TAB Ctrl+I
linefeed 10 LFD Ctrl+J Few keyboards have this key
return 13 RET Ctrl+M
escape 27 ESC Ctrl+[
Если вы хотите полностью отделить Tabот Ctrl+ I, удалите привязку из function-key-map
:
(define-key function-key-map [tab] nil)
Однако это не очень полезно, потому что записи в function-key-map
переопределяются привязками в зависимых от режима раскладках клавиш или в глобальной карте. Поэтому, если вы хотите определить другую привязку для tab
, просто сделайте это (в Elisp, а не в интерактивном режиме, потому что приглашение чтения ключа применяет function-key-map
перевод, так что вы в конечном итоге перепривязываете, TAB
а не tab
):
(global-set-key [tab] '…)
(define-key some-mode-map [tab] '…)
Все стандартные режимы, которые изменяют действие Tabклавиши, делают это, изменяя TAB
ключ, который является псевдонимом для C-i
символа, сгенерированного комбинацией клавиш Ctrl+ I. Если вы хотите, чтобы стандартные привязки применялись tab
вместо C-i
, вместо этого , оставляйте function-key-map
и изменяйте сопоставления клавиш в одиночку, а вместо этого перенаправляйте Ctrl+ Iна другую клавишу.
(define-key input-decode-map [(control ?i)] [control-i])
(define-key input-decode-map [(control ?I)] [(shift control-i)])
(define-key some-mode-map [control-i] '…)
Теперь Emacs сообщит Ctrl+ Iкак « <control-i>
(перевод с TAB
)». Это не красиво, но неизбежно: красивая печать символа 9 TAB
встроена в исходный код Emacs.
Клеммные рамы
В терминальных кадрах проблема сложнее и часто невозможна. Терминалы не передают ключи, они передают символы (точнее, фактически, они передают байты). TabКлюч передается как символ табуляции - который Control + I, такой же , как то , что комбинация клавиш Ctrl+ Iгенерирует. Функциональные клавиши, которые не имеют соответствующего символа (например, клавиши курсора), передаются как escape-последовательности, то есть последовательности символов, начинающиеся с ESC
= Control + [(именно поэтому Emacs определяет escapeкак префиксную клавишу - ESC
должен быть префиксом). См. Как работают ввод с клавиатуры и вывод текста? для получения дополнительной информации.
Существует несколько терминалов, которые можно настроить для отправки различных последовательностей клавиш для функциональных клавиш, но не так много. Это поддерживают как libtermkey / libtickit от LeoNerd, так и xterm Томаса Дики (начиная с версии 216). В Xterm эта функция является необязательной и активируется через modifyOtherKeys
ресурс. Однако я не знаю ни одного популярного эмулятора терминала, кроме xterm, который бы это поддерживал, в частности многих эмуляторов, построенных на libvte . Некоторые терминальные эмуляторы позволяют вам делать это вручную через пользовательскую переписку из цепочек ключей для экранирования последовательностей.
Этот механизм позволяет различать многие комбинации клавиш, а не только tab / Ci, return / Cm и escape / C- [. См. Проблемы с сочетаниями клавиш при использовании терминала для более подробного описания.
Базовая функция xterm поддерживается начиная с Emacs 24.4. Однако основы (в частности Tab, Return, Escape, Backspace) до сих пор отправить традиционные управляющие символы, потому что это то , что ожидают приложение. Существует режим, в котором Ctrl+ letterотправляет escape-последовательность вместо управляющего символа. Поэтому, чтобы отличить функциональные клавиши от Ctrlкомбинаций в Emacs 24.4, измените его поддержку для modifyOtherKeys
использования этого режима, установив для ресурса значение 2 вместо 1.
;; xterm with the resource ?.VT100.modifyOtherKeys: 2
;; GNU Emacs >=24.4 sets xterm in this mode and define
;; some of the escape sequences but not all of them.
(defun character-apply-modifiers (c &rest modifiers)
"Apply modifiers to the character C.
MODIFIERS must be a list of symbols amongst (meta control shift).
Return an event vector."
(if (memq 'control modifiers) (setq c (if (or (and (<= ?@ c) (<= c ?_))
(and (<= ?a c) (<= c ?z)))
(logand c ?\x1f)
(logior (lsh 1 26) c))))
(if (memq 'meta modifiers) (setq c (logior (lsh 1 27) c)))
(if (memq 'shift modifiers) (setq c (logior (lsh 1 25) c)))
(vector c))
(defun my-eval-after-load-xterm ()
(when (and (boundp 'xterm-extra-capabilities) (boundp 'xterm-function-map))
;; Override the standard definition to set modifyOtherKeys to 2 instead of 1
(defun xterm-turn-on-modify-other-keys ()
"Turn the modifyOtherKeys feature of xterm back on."
(let ((terminal (frame-terminal)))
(when (and (terminal-live-p terminal)
(memq terminal xterm-modify-other-keys-terminal-list))
(send-string-to-terminal "\e[>4;2m" terminal))))
(let ((c 32))
(while (<= c 126)
(mapc (lambda (x)
(define-key xterm-function-map (format (car x) c)
(apply 'character-apply-modifiers c (cdr x))))
'(;; with ?.VT100.formatOtherKeys: 0
("\e\[27;3;%d~" meta)
("\e\[27;5;%d~" control)
("\e\[27;6;%d~" control shift)
("\e\[27;7;%d~" control meta)
("\e\[27;8;%d~" control meta shift)
;; with ?.VT100.formatOtherKeys: 1
("\e\[%d;3~" meta)
("\e\[%d;5~" control)
("\e\[%d;6~" control shift)
("\e\[%d;7~" control meta)
("\e\[%d;8~" control meta shift)))
(setq c (1+ c)))))
(define-key xterm-function-map "")
t)
(eval-after-load "xterm" '(my-eval-after-load-xterm))