Rebinding Keys, or, The Horror of Alt+TAB in Emacs
Table of Contents
I use exwm so M-TAB is available to me without being hijacked by the OS, but rebinding this failed in surprising places. I want it globally to be set to iflipb-next-buffer
(giving familiar alt+tab functionality to exwm), but if any of the buffers I’m travelling past happen to inherit magit or gnus, my tab-sequence gets broken because they have it bound to their own thing and I can’t seem to rebind it. It turns out that there are at least five ways to bind M-TAB
and, it seems, you have to match the right ones if you want to over-write something. The two culprits that made my life difficult were magit (also because of modes that inherit from magit) and gnus. Gnus is a special case because it dates back to almost the dawn of emacs, meaning that the ways of binding keys try to compensate for generations that pre-date modern keyboards and operating sytems.
Now, as is always a good idea, I’ve got my custom global keybindings in my own map so I can easily turn them off to get back to base-truth. These are the five ways I had to bind in order to guarantee my M-TAB
over-wrote all the bindings in child modes.
Custom-Minor Mode that Captures M-TAB
(defvar tsa-keys-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "M-TAB") 'iflipb-next-buffer) ;; this works most of the time
(define-key map [(meta tab)] 'iflipb-next-buffer) ;; gnus
(define-key map "\M-\C-i" 'iflipb-next-buffer) ;; gnus
(define-key map (kbd "M-C-i") 'iflipb-next-buffer) ;; gnus
(define-key map [M-tab] 'iflipb-next-buffer) ;; from magit
map)
"tsa-keys-minor-mode keymap.")
(define-minor-mode tsa-keys
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " ")
(global-set-key (kbd "<C-f3>") 'tsa-keys)
(tsa-keys 1)
Ensuring over-writes work
And now giving priority to my minor-mode so it is always the final minor-mode:
(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) 'tsa-keys)
(let ((mykeys (assq 'tsa-keys minor-mode-map-alist)))
(assq-delete-all 'tsa-keys minor-mode-map-alist)
(add-to-list 'minor-mode-map-alist mykeys))))
Resources
- Re: minor-maps and ensuring they give over-rides from StackOverflow https://stackoverflow.com/questions/683425/globally-override-key-binding-in-emacs
- A helpful related Stack Exchange post about this https://emacs.stackexchange.com/questions/9631/what-is-the-difference-between-tab-and-tab
- My Reddit post seeking answers: https://www.reddit.com/r/emacs/comments/iywqly/why_cant_i_rebind_some_modes_bindings/
Comments?
If anyone can shed some light on these different ways of binding M-TAB they would be very welcome, and I’ll update this post accordingly.