Резервная привязка ключей Emacs
У меня есть второстепенный режим. Если этот режим активен и пользователь нажимает DEL, я хочу выполнить какое-то действие, но только если выполняется какое-то условие. Если условие выполнено и действие выполнено, после этого я больше ничего не хочу делать. Но если условие не выполняется, я не хочу ничего делать и разрешить выполнение действия DEL по умолчанию.
Не уверен, как я мог решить это. Но, думаю, я мог бы сделать это двумя способами:
1) Я мог бы привязать клавишу DEL к функции в вспомогательном режиме, а затем проверить, выполняются ли условия. Но тогда как мне узнать, что команда по умолчанию для DEL?
2) Я мог бы добавить предварительный командный хук, как это. Выполните команду и затем разорвите цепочку. Но как мне разорвать цепь?
(add-hook 'pre-command-hook
(lambda()
(when (equal last-input-event 'backspace)
;; Do something and then stop (do not execute the
;; command that backspace is bound to)
)))
Как бы вы решили это? Спасибо!
3 ответа
Способ сделать это - временно отключить ваш второстепенный режим, а затем посмотреть привязку клавиш.
Притворись, что ты связан 'do-thingy
в DEL. Тогда это поможет (если условие, которое вы хотите вызвать, это (equal last-input-event 'backspace)
:
(defun do-thingy ()
"Do something, unless last event was backspace."
(interactive)
(if (equal last-input-event 'backspace)
(let* ((my-minor-mode nil)
(original-func (key-binding (kbd "DEL"))))
;; original-func is whatever DEL would be if
;; my-minor-mode were disabled
(call-interactively original-func))
(message "Here's my minor mode behavior!")))
Примечание. В этом случае предполагается, что вы установили привязки клавиш стандартным образом, как в младшем режиме. В частности, вы должны добавить свою таблицу ключей в переменную minor-mode-map-alist
добавив элемент (my-minor-mode . my-minor-mode-keymap)
, Вот как выше let
Оператор работает, он ищет нужную привязку с временно отключенным режимом.
Если вы используете define-minor-mode
чтобы определить ваш второстепенный режим, раскладка клавиатуры автоматически настраивается на "правильный путь".
Это то, что я использую для моего smart-tab
пакет, который делает именно это.
(defun smart-tab-default ()
"Indents region if mark is active, or current line otherwise."
(interactive)
(if mark-active
(indent-region (region-beginning)
(region-end))
(call-interactively
(or
;; Minor mode maps for tab (without smart-tab-mode)
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding "\t")))
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding [(tab)])))
(local-key-binding "\t")
(local-key-binding [(tab)])
(global-key-binding "\t")
(global-key-binding [(tab)])))))
И в команде smart-tab
(который привязывается к вкладке в второстепенном режиме), имеет следующее:
(if (smart-tab-must-expand prefix)
;; use smart tab
(smart-tab-default))
Сначала проверяется наличие каких-либо незначительных привязок режима для вкладки (не включаяsmart-tab-mode
), затем локальные и, наконец, глобальные сочетания клавиш.
Кажется, нет способа сделать то, что вы хотите, надежно. Если ваша новая команда привязана к DEL, то того, что раньше было привязано к DEL в текущей раскладке, больше не существует. Другой предложенный вами подход не сработает, потому что предварительные командные хуки не мешают выполнению следующих действий. Вы можете также подумать о том, чтобы прервать дальнейшее выполнение с помощью ^G (Keyboard-Quit), но это неконтролируемое прерывание, которое может остановить больше вещей, чем вы хотите.
Даже если вы сделаете процесс настройки нового связывания немного более сложным, чем просто перепривязка, и вспомните, что было там связано раньше, так что вы можете назвать его потом, у вас действительно не будет того, что вы ищете. Если кто-то хочет перепривязать действие "по умолчанию", он должен сделать это, изменив свою функцию вместо замены привязки клавиш.
То, что вы хотите сделать, не соответствует модели Emacs о том, как работает связывание ключей.