在 Emacs 中全局重写密钥绑定

如何设置一个全局重写并优先于该密钥的所有其他绑定的密钥绑定?我想覆盖所有主/次模式映射,并确保我的绑定始终有效。

这当然行不通:

(global-set-key "\C-i" 'some-function)

它工作在 text-mode,但当我使用 lisp-modeC-i是反弹到 lisp-indent-line

我可以通过和覆盖这个绑定在 lisp-mode和在每个其他模式单独,但必须有一个更简单的方法。每次为新文件类型安装新模式时,都必须返回并检查以确保所有密钥绑定都没有被新模式覆盖。

我之所以这样做,是因为我想模仿从其他编辑器那里学到并根深蒂固的绑定。

22903 次浏览

I don't think you can. That is roughly equivalent to saying that you want to define a global variable that cannot be hidden by local variable declarations in functions. Scope just doesn't work that way.

However, there might be a way to write an elisp function to go through the mode list and reassign it in every single one for you.

I use a minor mode for all my "override" key bindings:

(defvar my-keys-minor-mode-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "C-i") 'some-function)
map)
"my-keys-minor-mode keymap.")


(define-minor-mode my-keys-minor-mode
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " my-keys")


(my-keys-minor-mode 1)

This has the added benefit of being able to turn off all my modifications in one fell swoop (just disable the minor mode) in case someone else is driving the keyboard or if I need to see what a default key binding does.

Note that you may need to turn this off in the minibuffer:

(defun my-minibuffer-setup-hook ()
(my-keys-minor-mode 0))


(add-hook 'minibuffer-setup-hook 'my-minibuffer-setup-hook)

Unless you really want to do this yourself, you should check around and see if anyone else already has done it.

There is a package for Emacs which gives your windows-like keybindings. You should be able to find it through google.

Although scottfrazer's answer is exactly what you asked for, I will mention for posterity another solution.

From The Emacs Manual:

"Don't define C-c letter as a key in Lisp programs. Sequences consisting of C-c and a letter (either upper or lower case) are reserved for users; they are the only sequences reserved for users, so do not block them."

If you bind your personal global bindings to C-c plus a letter, then you "should" be safe. However, this is merely a convention, and any mode is still able to override your bindings.

As an addition to scottfrazer's answer, I've written the following so that my keybindings retain precedence, even if subsequently-loaded libraries bring in new keymaps of their own.

Because keymaps can be generated at compile time, load seemed like the best place to do this.

(add-hook 'after-load-functions 'my-keys-have-priority)


(defun my-keys-have-priority (_file)
"Try to ensure that my keybindings retain priority over other minor modes.


Called via the `after-load-functions' special hook."
(unless (eq (caar minor-mode-map-alist) 'my-keys-minor-mode)
(let ((mykeys (assq 'my-keys-minor-mode minor-mode-map-alist)))
(assq-delete-all 'my-keys-minor-mode minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))

If you want to "always use the keybinds in the map, unless I explicitly override them for a specific mode-map", and assuming you are using scottfrazier's approach, you want:

(defun locally-override (key cmd)
(unless (local-variable-p 'my-keys-minor-mode-map)
(set (make-variable-buffer-local 'my-keys-minor-mode-map)
(make-sparse-keymap))
(set-keymap-parent my-keys-minor-mode-map
(default-value 'my-keys-minor-mode-map)))
(define-key my-keys-minor-mode-map key cmd))

So

(locally-override "\C-i" nil)

should remove the "\C-i" binding from the minor mode in the current buffer only. Warning: this is completely untested, but seems like the right approach. The point of setting the parent rather than just coping the global value of my-keys-minor-mode-map is so any later changes to the global value are automatically reflected in the local value.

I found this question while searching for "emacs undefine org mode keybindings", because I wanted to unbind the existing C-c C-b behavior to allow my global map to bury-buffer to work in an org buffer.

This ended up being the simplest solution for me:

(add-hook 'org-mode-hook
(lambda ()
(local-unset-key (kbd "C-c C-b"))))

Install use-package, eval and you're done:

(require 'bind-key)
(bind-key* "C-i" 'some-function)