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.
;; make key 【f4】 key do 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 Caps Lock 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
Add/Change Insert Mode Activation Key
If you have a nice keyboard with extra thumb keys such as kinesis, ergodox, you can set a dedicated key to switch to insert mode.
;; make key 【end】 to activate insertion mode. (global-set-key (kbd "<end>") 'xah-fly-insert-mode-activate)
Disable Changes to Control Key
xah-fly-keys supports standard control key such as 【Ctrl+o】 open, 【Ctrl+w】 close 【Ctrl+v】 paste 【Ctrl+z】 undo, etc.
You can disable them by:
(setq xah-fly-use-control-key nil) ; must come before loading xah-fly-keys
when disabled, no control binding will be touched by xah-fly-keys.
Disable Changes to Meta Key
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 Caps Lock.)
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.)
Change Global Leader Key
You can set your own choice of the global leader key like this:
(define-key xah-fly-key-map (kbd "<f9>") xah-fly-leader-key-map) ; must come after loading xah-fly-keys
Put the above in your init, after the code for 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)
② 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 be cmd1
- 【leader 8 3】 to be cmd2
- 【leader 8 a】 to be 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
There are these hooks you can use:
- xah-fly-command-mode-activate-hook → hook variable. Value should be a list of function symbols. When command mode is activated, these functions are called after activation.
- xah-fly-insert-mode-activate-hook → hook variable. Value should be a list of function symbols. When insert mode is activated, these functions are called after activation.
Auto Save When Switching to Command Mode
This code will make emacs save current file (if it is a file), when you switch to command mode:
;; automatic save buffer when switching to command mode (add-hook 'xah-fly-command-mode-activate-hook 'xah-fly-save-buffer-if-file)
You can remove hook like this:
;; remove a hook (remove-hook 'xah-fly-command-mode-activate-hook 'xah-fly-save-buffer-if-file)
Add or Change Command Mode Keys
You can do it this way.
(defun my-bindkey-xfk-insert-mode () "Define keys for `xah-fly-insert-mode-activate-hook'" (interactive) (define-key xah-fly-key-map (kbd "DEL") 'xah-fly-command-mode-activate) ;; more here ) (defun my-bindkey-xfk-command-mode () "Define keys for `xah-fly-command-mode-activate-hook'" (interactive) (define-key xah-fly-key-map (kbd "DEL") 'xah-fly-insert-mode-activate) ;; more here ) (add-hook 'xah-fly-insert-mode-activate-hook 'my-bindkey-xfk-insert-mode) ;; (add-hook 'xah-fly-command-mode-activate-hook 'my-bindkey-xfk-command-mode)
Alternatively, just modify xah-fly-keys.el directly. Modify
(or, just copy the whole function out, modify it, put in your init at after 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
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 Cursor Shape, Command Mode, Insert Mode
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 use background color, e.g.
(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
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.
Here's a outline of the code.
There's these 2 important variables:
- xah-fly-key-map → Variable. Value is a elisp keymap. This keymap is used for command mode and insertion mode.
- xah-fly-leader-key-map → 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:
xah-fly-command-mode-init→ set keybinding for command mode. Basically, it just modify xah-fly-key-map.
xah-fly-insert-mode-init→ 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
If you have a question, put $5 at patreon and message me.