Emacs: Xah Fly Keys Customization

By Xah Lee. Date: . Last updated: .

This page shows how to customize Emacs: Xah Fly Keys.

Disable Change to Emacs Control Keybinding

;; 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 changed by xah-fly-keys.

Disable Changes to Emacs Meta Keybinding

You can disable this by:

;; must come before loading xah-fly-keys
(setq xah-fly-use-meta-key nil)
(require 'xah-fly-keys)

Add a Key to Activate Command Mode

Here's a example of how to add a command mode activation key.

(require 'xah-fly-keys)
(xah-fly-keys-set-layout "qwerty")

;; must come after loading xah-fly-keys
(global-set-key (kbd "<f4>") 'xah-fly-command-mode-activate)

Emacs Keybinding Syntax

Emacs Keybinding Syntax

How to Make the CapsLock Key do Home Key

How to Make the CapsLock Key do Home Key

Add a Key to Activate Insert Mode

For example:

(require 'xah-fly-keys)
(xah-fly-keys-set-layout "qwerty")

;; make End key to activate insertion mode
;; must come after loading xah-fly-keys
(global-set-key (kbd "<end>") 'xah-fly-insert-mode-activate)

This is useful if have a keyboard with many thumb keys. [see Ergonomic Keyboard Reviews]

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)

Add Key to Insert Mode to Activate Command Mode

This is useful when you want a single key to switch back to command mode while in insert mode.

(defun xah-xfk-addon-insert ()
  "Modify keys for xah fly key command mode keys
  To be added to `xah-fly-insert-mode-activate-hook'"
  ;; this makes backslash key to switch to command mode.
  ;; to type a backslash, do C-q \
  (define-key xah-fly-key-map (kbd "\\") 'xah-fly-command-mode-activate))

(add-hook 'xah-fly-insert-mode-activate-hook 'xah-xfk-addon-insert)

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.

Add a 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 or extra thumb keys.

(global-set-key (kbd "<f9>") xah-fly-leader-key-map)
; must come after loading xah-fly-keys

Add a Leader Key Sequence

Here's a example of adding 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 calendar.

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 xah-fly-leader-key-map.

Here's the short version of xah-fly-leader-key-map definition:

 (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 xah-fly-e-keymap

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 xah-fly-e-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

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:

 ;; 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
 (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)

Add Hook

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 to Command Mode Keymap

(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'"
  (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 Insert Mode Keymap

(defun my-xfk-addon-insert ()
  "Modify keys for xah fly key command mode keys
To be added to `xah-fly-insert-mode-activate-hook'"
  (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)

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.

Get a list of the major mode's commands you want. You do this by first activate the major mode (or open a file that invoke the major mode), then, Alt+x describe-mode. It will list all commands of the mode.

Then, decide a leader key to call them. For example, if leader key is F9, you might have F9 a and F9 b and F9 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"
      ;; 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 "<f9>") xah-golang-leader-map)

  (add-hook 'go-mode-hook 'xah-config-go-mode))

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:

(defun my-wrapper ()
  "call different commands depending on what's current major mode."
   ((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.

[see Emacs: Find Major Mode Name]

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.

  (xah-fly-keys-set-layout "dvorak")
  (xah-fly-keys t))

(if (daemonp)
    (add-hook 'server-after-make-frame-hook 'my/server-fix-up))

Where to Add Keys?

You can bind keys to any of those spots for personal commands.

Final Words

I recommend that you do not change much keys in xah-fly-keys. 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:

back to Emacs: Xah Fly Keys

Xah Fly Keys