Emacs: Xah Fly Keys Customization
This page shows how to customize Emacs: Xah Fly Keys.
Add/Change Command Mode Activation Key
Here's a example of how to set the command mode activation key.
(require 'xah-fly-keys) (xah-fly-keys-set-layout "qwerty") ;; make F4 activate command mode (global-set-key (kbd "<f4>") 'xah-fly-command-mode-activate)
(kbd "<f4>") is the F4 key.
For other key's syntax, see
Emacs: How to Define Keys
On a typical PC keyboard, i recommend you make the CapsLock key to send Home key signal for activating command mode.
(Home key by default will activate command mode.)
How to Make the CapsLock Key do Home Key
How to Make the CapsLock Key do Home Key
Add/Change Insert Mode Activation Key
If you have a nice keyboard with extra thumb keys such as Kinesis Advantage2 Keyboard or a Foot Pedal [see Kinesis Savant Elite2 Foot Pedal] , you can set a dedicated key to switch to insert mode.
(require 'xah-fly-keys) (xah-fly-keys-set-layout "qwerty") ;; make End key to activate insertion mode (global-set-key (kbd "<end>") 'xah-fly-insert-mode-activate)
Add Key to Toggle Command/Insert
(require 'xah-fly-keys) (xah-fly-keys-set-layout "qwerty") ;; make F4 toggle command/insert mode (global-set-key (kbd "<f4>") 'xah-fly-mode-toggle)
Disable Changes to Control Key Shortcuts
xah-fly-keys supports standard Control key shortcuts such as Ctrl+o open, Ctrl+w close Ctrl+v paste Ctrl+z undo, etc.
You can disable them by:
;; must come before loading xah-fly-keys (setq xah-fly-use-control-key nil) (require 'xah-fly-keys)
when disabled, no control binding will be touched by xah-fly-keys.
Disable Changes to Meta Key Shortcuts
The only meta keybinding
xah-fly-keys bind is
as a extra key for
(so, out of the box, it's convenient for people who haven't bothered setting CapsLock.)
You can disable this by:
(setq xah-fly-use-meta-key nil) ; must come before loading xah-fly-keys
Make Escape Key Do C-g
You can make the Escape key do emacs's Ctrl+g.
(define-key key-translation-map (kbd "ESC") (kbd "C-g"))
Note: this will work 99% of time. When it doesn't work, just press Ctrl+g. (the only case i know it doesn't work is when you quit emacs, and emacs says there are unsaved file and if you still want to quit, and pressing Escape to cancel quit doesn't work, but Ctrl+g works.)
Note: for text terminal users, escape key is critical, especially if you do not have Meta key setup. Because Meta+x can be typed by Escape x. So, if you remap Escape, you lose that.
Change Global Leader Key
You can set a global leader key, so you don't have to switch to command mode first. This is especially useful if you have a Foot Pedal [see Kinesis Savant Elite2 Foot Pedal] or extra thumb keys.
(global-set-key (kbd "<f9>") xah-fly-leader-key-map) ; must come after loading xah-fly-keys
Add or Change Leader Key Sequence
Here's a example of add/change a 3-key sequence.
Put this in your init, after loading xah-fly-keys:
;; make xah-fly-keys qwerty 【leader d f】 do command calendar (define-key xah-fly-e-keymap (kbd "u") 'calendar) ;; qwerty 【leader d f】 is dvorak 【leader e u】 ;; this overwrites existing command or keymap of 【leader e u】
Note, xah-fly-keys's key syntax is with dvorak keys. So, if you are using qwerty, you need to first find out what's the dvorak key.
For example, let's say you are a qwerty user, and you want to add/change the qwerty key sequence 【leader d f】 to call command
The steps are:
① Find out what's qwerty d in dvorak. (qwerty d is dvorak e) [see QWERTY Dvorak Layout Conversion Table]
② in xah-fly-keys.el file, find the keymap name that corresponds to the leader key map for the dvorak key, by finding it in the definition of
Here's the short version of
(xah-fly--define-keys (define-prefix-command 'xah-fly-leader-key-map) '( ;; ... ("1" . nil) ("2" . nil) ("3" . delete-window) ("4" . split-window-right) ("5" . balance-windows) ("6" . nil) ("7" . nil) ("8" . nil) ("9" . ispell-word) ("0" . nil) ("a" . mark-whole-buffer) ("b" . end-of-buffer) ("c" . xah-fly-c-keymap) ("d" . beginning-of-buffer) ("e" . xah-fly-e-keymap) ("f" . xah-search-current-word) ("g" . isearch-forward) ("h" . xah-fly-h-keymap) ("i" . xah-copy-file-path) ("j" . xah-copy-all-or-region) ("k" . xah-paste-or-paste-previous) ("l" . recenter-top-bottom) ("m" . dired-jump) ("n" . xah-fly-n-keymap) ("o" . exchange-point-and-mark) ("p" . query-replace) ("q" . xah-cut-all-or-region) ("r" . xah-fly-r-keymap) ("s" . save-buffer) ("t" . xah-fly-t-keymap) ("u" . switch-to-buffer) ("v" . nil) ("w" . xah-fly-w-keymap) ("x" . nil) ("y" . xah-show-kill-ring) ("z" . nil) ;; ))
Since you are looking for qwerty 【leader d】, and that's dvorak e, so you look at the entry for e, and the result is
③ now, since you want add/change qwerty 【leader d f】, now find out what's qwerty f in dvorak. (qwerty f is dvorak u)
④ Now you know, the key you want to change is u, in keymap
So, the code you want to put in init file is:
(xah-fly-keys 1) ;; make xah-fly-keys qwerty 【leader d f】 do calendar (define-key xah-fly-e-keymap (kbd "u") 'calendar) ;; this is dvorak 【leader e u】
Creating a Whole Keymap
Here's a example of creating a whole keymap.
Let's say you want
- 【leader 8 space】 to call cmd1
- 【leader 8 3】 to call cmd2
- 【leader 8 a】 to call cmd3
and anything after 【leader 8】 would be your personal keys.
Here's the code:
(define-prefix-command 'my-keymap) (define-key my-keymap (kbd "SPC") 'cmd1) (define-key my-keymap (kbd "3") 'cmd2) (define-key my-keymap (kbd "a") 'cmd3) ;; make xah-fly-keys 【leader 8】 as prefix for my-keymap (define-key xah-fly-leader-key-map (kbd "8") my-keymap) ;; so now, ;; 【leader 8 space】 is cmd1 ;; 【leader 8 3】 is cmd2 ;; 【leader 8 a】 is cmd3 ;; etc
If you want your letters to be translated according to
xah-fly-keys-set-layout, then do it this way:
(xah-fly--define-keys ;; create a keymap my-keymap (define-prefix-command 'my-keymap) '( ("SPC" . cmd1) ("3" . cmd2) ("a" . cmd3) ;; )) ;; make xah-fly-keys 【leader 8】 as prefix for my-keymap (xah-fly--define-keys (define-prefix-command 'xah-fly-leader-key-map) '( ("8" . my-keymap) ;; )) ;; all letters are dvorak. They get translated to whatever your xah-fly-keys-set-layout is set to
Change execute-extended-command (M-x) of Your Choice
Add one of the following, before loading xah fly keys:
(setq xah-fly-M-x-command 'execute-extended-command)
(setq xah-fly-M-x-command 'smex)
(setq xah-fly-M-x-command 'helm-M-x)
(setq xah-fly-M-x-command 'counsel-M-x)
There are these hooks you can use:
- Hook variable. Value should be a list of function symbols. When command mode is activated, these functions are called after activation.
- Hook variable. Value should be a list of function symbols. When insert mode is activated, these functions are called after activation.
Add/Change Keys in Xah Fly Keys Command Mode
(defun my-config-xah-fly-key () "Modify keys for xah fly key command mode keys To be added to `xah-fly-command-mode-activate-hook'" (interactive) (define-key xah-fly-key-map (kbd "1") 'my-command-abc) ;; more here ) (add-hook 'xah-fly-command-mode-activate-hook 'my-config-xah-fly-key)
Add/Change Keys in Xah Fly Keys Insert Mode
(defun my-xfk-addon-insert () "Modify keys for xah fly key command mode keys To be added to `xah-fly-insert-mode-activate-hook'" (interactive) (define-key xah-fly-key-map (kbd "2") 'my-command-xyz) ;; more here ) (add-hook 'xah-fly-insert-mode-activate-hook 'my-xfk-addon-insert)
Alternatively, just modify xah-fly-keys.el directly. Modify
(or, just copy the whole function out, modify it, put in your init after the code for loading xah-fly-keys.)
But i recommend that you do not change it. Just stick to it. Because, one thing about creating a keybinding system is that there's a lot habit to overcome. I've been changing keys every month for over 10 years. Each time, it's extremely painful, and with strong desire to go back. And, once you start to explore keys, you often become biased towards your CURRENT workflow or work. So, you get into a situation that you change every few months, when project changes, or your choice of major mode changes, and in particular, when your keyboard changes. Also, if you don't have a year or two dedicated study about keybinding system, you create a key system that you think must be logically flawless, but actually just to your habit, your hands, your current keyboard, and your workflow, not to someone else.
xah-fly-keys's keybinding choices is not scientifically the best, because that is basically an illusive concept, but is near optimal.
if you are interested in keybinding efficiency research, be sure to read:
- Emacs vs vim, Compute Keybinding Efficiency
- emacs and vi: Science of Command Efficiency
- Keybinding Design ⌨
- Emacs Keybinding, Keyboard, Articles Index
Setup Major Mode Custom Keys
Here's the best way to create leader key set for any major mode, so you don't have to press Ctrl+c.
First, get a list of the major mode's commands you want. Then, decide for a leader key to call them. For example, you might have F4 a and F4 b and F4 c.
Find out what's the keymap name in the major mode. (look at its source code), then do as follows. You can do this for org mode, magit mode. Here's a example with go-mode.el.
;; example of adding a leader key map to golang mode (when (fboundp 'go-mode) (defun xah-config-go-mode () "config go-mode. Version 2021-01-15" (interactive) (progn ;; create a keymap (define-prefix-command 'xah-golang-leader-map) ;; add keys to it (define-key xah-golang-leader-map (kbd "c") 'xah-gofmt) (define-key xah-golang-leader-map (kbd "j") 'godef-jump) ;; add more of the major mode key/command here ) ;; modify the major mode's key map, so that a key becomes your leader key (define-key go-mode-map (kbd "<delete>") xah-golang-leader-map) ;; ) (add-hook 'go-mode-hook 'xah-config-go-mode))
those asking about how to setup key in magit, the above is a good solution
Make a Key do x Depending on Major Mode
You can have a key do different things depending on what's the current major mode.
The most simple way, is to write a wrapper command. The wrapper command will check current mode and call different commands. Then, bind the wrapper command to a key in command mode.
Here's a example of a wrapper command.
When in command mode, suppose you want key 5 to call:
x1-cmdif current mode is
x2-cmdif current mode is
(defun my-wrapper () "call different commands depending on what's current major mode." (interactive) (cond ((string-equal major-mode "x1-mode") (x1-cmd)) ((string-equal major-mode "x2-mode") (x2-cmd)) ;; more major-mode checking here ;; if nothing match, do nothing (t nil)))
Then, just follow the keybinding instruction mentioned on this page to set this command to a key.
Change Color for Mode State
You can make the mode state more obvious, by changing current line highlight. e.g.
(defun my-highlight-line-on () (global-hl-line-mode 1)) (defun my-highlight-line-off () (global-hl-line-mode 0)) (add-hook 'xah-fly-command-mode-activate-hook 'my-highlight-line-on) (add-hook 'xah-fly-insert-mode-activate-hook 'my-highlight-line-off)
You can also change background color.
(defun my-xfk-command-color () (set-background-color "honeydew")) (defun my-xfk-insert-color () (set-background-color "white")) (add-hook 'xah-fly-command-mode-activate-hook 'my-xfk-command-color) (add-hook 'xah-fly-insert-mode-activate-hook 'my-xfk-insert-color)
Russian Layout Addon
Emacs: Xah Fly Keys for Russian Layout
Start in Command Mode When Emacs Daemon Starts
;; 2021-03-10 this fix the problem of: when emacs start as daemon, xah fly keys is not in command mode. thx to David Wilson (daviwil) (defun my/server-fix-up() "Make sure 'xah-fly-keys' is starting in command-mode. https://github.com/xahlee/xah-fly-keys/issues/103 https://github.com/daviwil/emacs-from-scratch/blob/master/show-notes/Emacs-Tips-08.org#configuring-the-ui-for-new-frames" (xah-fly-keys-set-layout "dvorak") (xah-fly-keys t)) (if (daemonp) (add-hook 'server-after-make-frame-hook 'my/server-fix-up))
Advanced Customization, How Does xah-fly-keys Work
If you look at the file, in 10 minutes you should have a basic idea. The code is simple.
There's these 2 important variables:
- Variable. Value is a elisp keymap. This keymap is used for command mode and insertion mode.
- Variable. Value is a elisp keymap. It's the leader keys sequence.
(note: in elisp, keymap is just a list of key/command pairs. The command part can be another keymap, in which case, it is a key sequence.)
There's these 2 important commands:
- set keybinding for command mode. Basically, it just modify xah-fly-key-map.
set keybinding for insert mode. Basically, it just modify xah-fly-key-map, by setting all keys to nil (which means, do emacs default, usually means they do
xah-fly-command-mode-init looks like this:
(defun xah-fly-command-mode-init () (xah-fly--define-keys xah-fly-key-map '( ("a" . execute-extended-command) ("b" . isearch-forward) ("c" . previous-line) ;; more here )))
"c" there are Dvorak keys.
xah-fly--define-keys takes care of translating Dvorak to QWERTY, if user has qwery set
xah-fly-insert-mode-init looks like this:
(defun xah-fly-insert-mode-init () (xah-fly--define-keys xah-fly-key-map '( ("a" . nil) ("b" . nil) ("c" . nil) ;; more )))
xah-fly-leader-key-map looks like this:
(xah-fly--define-keys (define-prefix-command 'xah-fly-leader-key-map) '( ("a" . mark-whole-buffer) ("b" . end-of-buffer) ("c" . xah-fly-c-keymap) ("d" . beginning-of-buffer) ("e" . xah-fly-e-keymap) ("f" . xah-search-current-word) ;; more ))
For example, the line
("b" . end-of-buffer)
press leader b will call
Note: All keys in the file are Dvorak keys. For example, if you see
("b" . isearch-forward), that's Dvorak b, and when user has QWERTY set, that b is automatically translated to n.
back to Emacs: Xah Fly Keys