How to Override Keybindings in Emacs

Advertise Here

, 2008-07, 2009-12-17

This page shows you how to reclaim keybindings when some major or minor mode override your global keybindings. If you don't know how to define global keybindings, see: Emacs: How to Define Keyboard Shortcuts.

When you have made some personal keyboard shortcuts in emacs using “global-set-key”, both major modes and minor modes will override those if it uses the same keys. This is because major mode and minor mode's keymaps have priority over global keymaps.

To reclaim your binding, you will have to redefine the key of that mode's keymap, and this needs to happen after that mode finished loading, because otherwise when the mode is activated, its keymap definition simply overrides yours.

Well written major modes will run hook at the end. So, you can use a hook to define your keybinding. Minor modes usually do not have hooks. In that case, you can call (require ‹minor mode feature symbol›) first, then define your keybinding.

The exact steps may not be the same for every mode, but the principle is the same. The following shows several examples.

Examples

Isearch

By default, 【Ctrl+s】 will do a interactive search. Pressing that again will find the next match. Suppose you prefer to have 【Alt+s】 instead, so in your emacs init file you defined:

(global-set-key (kbd "M-s") 'isearch-forward)
(global-set-key (kbd "M-S") 'isearch-backward)

You want to use “M-s” to repeat the search. However, once you are in the isearch prompt, technically it is a minor mode called “isearch-mode”. In “isearch-mode”, “C-s” is defined to run “isearch-repeat-forward”. You want “M-s” to run “isearch-repeat-forward”. Here's the code to reclaim it:

(add-hook 'isearch-mode-hook
 (lambda ()
 (define-key isearch-mode-map (kbd "M-s") 'isearch-repeat-forward)
 (define-key isearch-mode-map (kbd "M-S") 'isearch-repeat-backward)
 )
)

Shell Mode

“shell-mode” 【Alt+x shell】, and “shell-command” 【Alt+!】 have many special keys. Suppose you want to change them. They both use a keymap named “comint-mode-map”. The following is a exmaple of redefining some of its keys.

;; reclaim some binding used by shell mode and shell-command.
;; the shell mode and associated mode and commands use keys in comint-mode-map.
(add-hook 'comint-mode-hook
 (lambda ()
   (define-key comint-mode-map (kbd "M-p") 'recenter) ; was comint-previous-input. Use Ctrl+↑ or f11
   (define-key comint-mode-map (kbd "M-n") 'nil) ; was comint-next-input. Use Ctrl+↓ or f12

   (define-key comint-mode-map (kbd "M-r") 'kill-word) ; was comint-previous-matching-input.
   (define-key comint-mode-map (kbd "M-s") 'other-window) ; was comint-next-matching-input.

   ;; rebind displaced commands that i still want a key
   (define-key comint-mode-map (kbd "<f11>") 'comint-previous-input)
   (define-key comint-mode-map (kbd "<f12>") 'comint-next-input)
   (define-key comint-mode-map (kbd "S-<f11>") 'comint-previous-matching-input)
   (define-key comint-mode-map (kbd "S-<f12>") 'comint-next-matching-input)
))

Minibuffer

The minibuffer is where emacs does prompts. It is technically a minor mode. It defines the following keybindings:

Minibuffer's Keybindings
KeyCommand
C-jexit-minibuffer
Enterexit-minibuffer
C-gabort-recursive-edit
M-nnext-history-element
next-history-element
M-pprevious-history-element
previous-history-element
M-snext-matching-history-element
M-rprevious-matching-history-element

Here's a example of how to redefine its keybindings:

;; reclaim some bindings used in minibuffer for ergoemacs bindings for QWERTY
(define-key minibuffer-local-map (kbd "M-p") 'recenter) ; was previous-history-element. Use ↑ key or f11.
(define-key minibuffer-local-map (kbd "M-n") 'nil) ; was next-history-element. Use ↓ key or f12.

(define-key minibuffer-local-map (kbd "M-r") 'kill-word) ; was previous-matching-history-element.
(define-key minibuffer-local-map (kbd "M-s") 'other-window) ; was nest-matching-history-element

;; add back some bindings for commands whose binding we displaced
(define-key minibuffer-local-map (kbd "<f11>") 'previous-history-element)
(define-key minibuffer-local-map (kbd "<f12>") 'next-history-element)
(define-key minibuffer-local-map (kbd "S-<f11>") 'previous-matching-history-element)
(define-key minibuffer-local-map (kbd "S-<f12>") 'next-matching-history-element)

(info "(elisp) Text from Minibuffer")

General Tips

Here's some general steps. Suppose you want to modify a xyz mode. Call “describe-function” to get its inline doc, then click on the link to open its elisp source code file.

Finding the Mode's Name

A mode has several names. For example, let's look at the “shell” command for shell interface. Its invocation command's name is “shell”, its mode line display name is “Shell” (stored in the variable named “mode-name”), its mode name is “shell-mode” (stored in the variable named “major-mode”), its feature symbol is “shell” (you can see this line (provide 'shell) in its source code), and its package name is “shell”, its file name is “shell.el”. All these names may be different for a mode. You can try to have a look of these names with other modes. For example, try “dired”, “html-mode”, “c-mode”, “perl-mode”.

Every major mode has a variable named “major-mode”. The value of that variable is the most important name for modifying its keymap or adding hooks.

You can find out the mode's name by switching to the mode, then type 【Alt+x describe-variable】, then give “major-mode”, then emacs will show its value.

Finding Out the Mode's Hook

In the elisp source code, search for “run-mode-hooks” or “-hook”. Major modes should always have a hook, but some quickly written mode may not have it.

If the value of the mode's variable “major-mode” is “xyz-mode”, then the hook variable name is usually “xyz-mode-hook”.

(info "Hooks") (info "Mode Hooks")

Finding Out the Mode's Keymap's Variable Name

To find out the keymap variable name for the mode, search for “-mode-map” or “-map”.

If the value of the mode's variable “major-mode” is “xyz-mode”, then its keymap variable name is usually “xyz-mode-map”.

Note that not all modes defines a keymap in its source file. Some inherit from other modes, some uses keymaps from other elisp file that are not modes, some doesn't have a keymap.

Rebind Displaced Commands

When you redefine some keys in a mode's keymap, be sure to make bindings for the displaced commands if those commands are important to you. For example, in shell-mode, i wanted “M-p” to do something. The “M-p” is “previous-history-element”. I think that command is useful enough to have a hotkey. So, i defined some other key for that. (You can call “describe-key” command to find out a key's binding while in that mode.)

blog comments powered by Disqus