23.15 Таблицы клавиш для перевода последовательностей событий

Когда функция read-key-sequence считывает последовательность клавиш (см. Ввод последовательности клавиш), она использует таблицы перевода для перевода определенных последовательностей событий в другие. Таблицы перевода это input-decode-map, local-function-key-map и key-translation-map (в порядке приоритета).

Таблицы перевода имеют ту же структуру, что и другие таблицы клавиш, но используются по-другому: они определяют переводы, которые необходимо выполнить при считывании последовательностей клавиш, а не привязки для полных последовательностей клавиш. При считывании каждой последовательности клавиш она проверяется по каждой таблице перевода. Если одна из таблиц перевода привязывает k к вектору v, то всякий раз, когда k появляется как подпоследовательность где-либо в последовательности клавиш, эта подпоследовательность заменяется событиями из v.

Например, терминалы VT100 отправляют ESC O P при нажатии клавиши на клавиатуре PF1. В таких терминалах Emacs должен перевести эту последовательность событий в одно событие pf1. Это делается путем привязки ESC O P к [pf1] в input-decode-map. Таким образом, когда вы нажимаете C-c PF1 на терминале, терминал испускает последовательность символов C-c ESC O P, и read-key-sequence переводит это обратно в C-c PF1 и возвращает его как вектор [?\C-c pf1].

Таблицы перевода вступают в силу только после того, как Emacs декодирует ввод с клавиатуры (с помощью системы кодирования ввода, указанной в keyboard-coding-system). См. Кодирование ввода/вывода терминала.

Переменная: input-decode-map

Эта переменная содержит таблицу клавиш, описывающую последовательности символов, отправляемые функциональными клавишами на обычном символьном терминале.

Значение input-decode-map обычно настраивается автоматически в соответствии с записью Terminfo или Termcap терминала, но иногда для этого требуется помощь файлов Lisp, специфичных для терминала. Emacs поставляется с файлами, специфичными для терминалов, для многих распространенных терминалов; их основная цель — добавить записи в input-decode-map, которые не могут быть выведены из Termcap и Terminfo. См. Инициализация, специфичная для терминала.

Переменная: local-function-key-map

Эта переменная содержит таблицу клавиш, похожую на input-decode-map, за исключением того, что она описывает последовательности клавиш, которые следует перевести в альтернативные интерпретации, которые обычно предпочтительнее. Она применяется после input-decode-map и до key-translation-map.

Записи в local-function-key-map игнорируются, если они конфликтуют с привязками, сделанными в режиме, в локальной или глобальной таблице клавиш. То есть, переназначение применяется только в том случае, если исходная последовательность клавиш в противном случае не имела бы привязки.

local-function-key-map наследуется от function-key-map. Последнее следует изменять только в том случае, если вы хотите, чтобы привязка применялась во всех терминалах, поэтому использование первого почти всегда предпочтительнее.

Переменная: key-translation-map

Эта переменная — еще одна таблица клавиш, используемая так же, как input-decode-map, для перевода событий ввода в другие события. Она отличается от input-decode-map тем, что работает после завершения local-function-key-map, а не до него; она получает результаты перевода от local-function-key-map.

Подобно input-decode-map, но в отличие от local-function-key-map, эта таблица клавиш применяется независимо от того, имеет ли последовательность ввода клавиш обычную привязку. Однако обратите внимание, что фактические привязки клавиш могут влиять на key-translation-map, даже если они переопределяются им. Действительно, фактические привязки клавиш переопределяют local-function-key-map и, таким образом, могут изменять последовательность клавиш, которую получает key-translation-map. Очевидно, что лучше избегать такой ситуации.

Назначение key-translation-map состоит в том, чтобы пользователи могли сопоставлять один набор символов с другим, включая обычные символы, обычно привязанные к self-insert-command.

Вы можете использовать input-decode-map, local-function-key-map и key-translation-map не только для простых псевдонимов, используя функцию вместо последовательности клавиш в качестве перевода клавиши. Затем эта функция вызывается для вычисления перевода этой клавиши.

Функция перевода клавиш принимает один аргумент, который является подсказкой, указанной в read-key-sequence — или nil, если последовательность клавиш считывается циклом команд редактора. В большинстве случаев вы можете игнорировать значение подсказки.

Если функция сама считывает ввод, она может повлиять на последующее событие. Например, вот как определить C-c h для преобразования следующего символа в гиперсимвол:

(defun hyperify (prompt)
  (let ((e (read-event)))
    (vector (if (numberp e)
                (logior (ash 1 24) e)
              (if (memq 'hyper (event-modifiers e))
                  e
                (add-event-modifier "H-" e))))))

(defun add-event-modifier (string e)
  (let ((symbol (if (symbolp e) e (car e))))
    (setq symbol (intern (concat string
                                 (symbol-name symbol))))
    (if (symbolp e)
        symbol
      (cons symbol (cdr e)))))

(keymap-set local-function-key-map "C-c h" 'hyperify)

Функция перевода клавиш может захотеть скорректировать свое поведение на основе параметров событий внутри последовательности клавиш, содержащей неклавишные события (см. События ввода). Эта информация доступна из переменной current-key-remap-sequence, которая привязывается к подпоследовательности клавиш, которую переводится во время вызовов функций перевода клавиш.

23.15.1 Взаимодействие с обычными таблицами клавиш

Конец последовательности клавиш обнаруживается, когда эта последовательность клавиш либо привязана к команде, либо когда Emacs определяет, что никакое дополнительное событие не может привести к последовательности, привязанной к команде.

Это означает, что, хотя input-decode-map и key-translation-map применяются независимо от того, имеет ли исходная последовательность клавиш привязку, наличие такой привязки все же может помешать выполнению перевода. Например, вернемся к нашему примеру VT100 выше и добавим привязку для C-c ESC к глобальной таблице; теперь, когда пользователь нажимает C-c PF1, Emacs не сможет декодировать C-c ESC O P в C-c PF1, потому что он остановит чтение клавиш сразу после C-c ESC, оставив O P на потом. Это на случай, если пользователь действительно нажал C-c ESC, в таком случае Emacs не должен останавливаться и ждать следующей клавиши, чтобы решить, нажал ли пользователь действительно ESC или PF1.

По этой причине лучше избегать привязки команд к последовательностям клавиш, где конец последовательности клавиш является префиксом перевода клавиши. Основные такие проблемные суффиксы/префиксы — это ESC, M-O (что на самом деле ESC O) и M-[ (что на самом настоящем ESC [).