I want to be able to bind ⌥← to move the cursor to the previous word, ⌥→ to the next word, ⌥↓ to scroll down a page etc. in Emacs on Mac OS, as in native text editing controls, but also still be able to enter special characters using the option key. When I bind mac-option-modifier
or ns-alternate-modifier
to 'alt
, I can bind things like I want, but no longer enter special characters; when I bind it to 'none
, I can enter special characters but can’t use it for my key bindings.
1 Answer
Emacs supports binding the Mac modifier keys to different internal keys depending on what kind of key event they’re used to trigger:
The value of each variable is either a symbol, describing the key for any purpose, or a list of the form (:ordinary symbol :function symbol :mouse symbol), which describes the modifier when used with ordinary keys, function keys (that do not produce a character, such as arrow keys), and mouse clicks.
So you can use this to allow A-
as the binding prefix for the option key when used in combination with ‘function keys’ (including arrow keys and backspace), but leave it set to 'none
for all other combinations, which enables typing special characters as usual:
(setq ns-alternate-modifier '(:ordinary none :function alt :mouse alt))
The specific key bindings to emulate native Mac OS text controls are:
;; note that scroll-up and scroll-down are reversed in Emacs compared to most apps
(global-set-key (kbd "A-<up>") 'scroll-down-command)
(global-set-key (kbd "A-<down>") 'scroll-up-command)
(global-set-key (kbd "A-<left>") 'backward-word)
(global-set-key (kbd "A-<right>") 'forward-word)
(global-set-key (kbd "A-<backspace>") 'backward-kill-word)
;; the following key bindings emulate the native command key scrolling and text editing shortcuts
(global-set-key (kbd "s-<up>") 'beginning-of-buffer)
(global-set-key (kbd "s-<down>") 'end-of-buffer)
(global-set-key (kbd "s-<left>") 'move-beginning-of-line)
(global-set-key (kbd "s-<right>") 'move-end-of-line)
(global-set-key (kbd "s-<backspace>") (lambda ()
(interactive)
(kill-line 0)))