Emacs: Xah Fly Keys Customization

By Xah Lee. Date: . Last updated: .

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)

The (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

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.

For example:

;; 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 【Alt+Space】 as a extra key for xah-fly-command-mode-activate (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 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 the definition for xah-fly-leader-key-map.

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

(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 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:

(require 'xah-fly-keys)

(xah-fly-keys-set-layout "qwerty") ; required if you use qwerty

(xah-fly-keys 1)

;; the following must come after loading xah-fly-keys

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

Here's the code:

(define-prefix-command 'my-nice-keymap)

(define-key my-nice-keymap (kbd "SPC") 'my-command-1)
(define-key my-nice-keymap (kbd "3") 'my-command-2)
(define-key my-nice-keymap (kbd "a") 'my-command-3)

;; make xah-fly-keys 【leader 8】 as prefix for my-nice-keymap
(define-key xah-fly-leader-key-map (kbd "8") my-nice-keymap)

;; so now,
;; 【leader 8 space】 is my-command-1
;; 【leader 8 3】 is my-command-2
;; 【leader 8 a】 is my-command-3
;; 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-nice-keymap
 (define-prefix-command 'my-nice-keymap)
 '(
   ("SPC" . my-command-1)
   ("3" . my-command-2)
   ("a" . my-command-3)
   ;;
   ))

;; make xah-fly-keys 【leader 8】 as prefix for my-nice-keymap
(xah-fly--define-keys
 (define-prefix-command 'xah-fly-leader-key-map)
 '(
   ("8" . my-nice-keymap)
   ;;
   ))

;; all letters are dvorak. They get translated to whatever your xah-fly-keys-set-layout is set to

Add Hook

There are these hooks you can use:

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 the function xah-fly-command-mode-init. (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:

Change Command Mode Key Depending on Major Mode

Suppose you want to change the key 5 to call xah-html-html-to-text when in command mode and only when current major mode is xah-html-mode.

Here's the code:

(defun my-bindkey-xfk-command-mode ()
  "Define keys for `xah-fly-command-mode-activate-hook'"
  (interactive)

  (cond

   ;; if current mode is xah-html-mode, change some key
   ((eq major-mode 'xah-html-mode)
    (define-key xah-fly-key-map (kbd "5") 'xah-html-html-to-text))

   ;; more major-mode checking here

   ;; if nothing match, do nothing
   (t nil)))

(add-hook 'xah-fly-command-mode-activate-hook 'my-bindkey-xfk-command-mode)

Change Cursor Shape, Command Mode, Insert Mode

You can make the mode state more obvious, by changing current line highlight. For example:

(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, such as:

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

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 4 important command/variable:

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

     )))

The "a" "b" "c" there are Dvorak keys.

The function xah-fly--define-keys takes care of translating Dvorak to QWERTY, if user has qwery set (xah-fly-keys-set-layout "qwerty") .

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) means press 【leader b】 will call end-of-buffer.

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

Patreon me $5 patreon

Or Buy Xah Emacs Tutorial

Or buy a nice keyboard: Best Keyboard for Emacs

If you have a question, put $5 at patreon and message me.