UPDATE: WordPress messed up the formatting again! I will get a better version uploaded.
As a follow on to yesterday’s post and today’s Irreal about rebinding keys, let me talk a bit about how I do key bindings.
※ I copied and pasted some of my config into WordPress. Some of the keybindings might be missing elements like <right>, so please verify before pasting into your own config.
First, like Irreal, I prefer to keep the default bindings as-is. That’s why the addition of super (s-), alt (A-), and hyper (H-) keys are so important. Second, it allows me to leverage alternative functions without conflicting with stock Emacs.
Rebindings
There are only two rebindings I do in my config:
;; My additional configuration
;; My few overriding default behavior
(use-package emacs
:bind
(“M-;” . xah-comment-dwim)
(“C-z” . undo)
)
I like Xah’s comment-dwim and prefer C-z not to background my session (on a GUI).
Super bindings
;; My Super (s-) maps
(use-package emacs
:bind
(“s-+” . text-scale-increase)
(“s–“ . text-scale-decrease)
(“s-0” . text-scale-reset )
(“s-<down>” . end-of-buffer)
(“s-<left>” . backward-sentence)
(“s-<right>” . forward-sentence)
(“s-<up>” . beginning-of-buffer)
(“s-Z” . redo)
(“s-a” . mark-whole-buffer)
(“s-c” . my-smart-copy-dwim)
(“s-w” . xah-close-current-buffer)
(“s-v” . xah-paste-or-paste-previous)
(“s-x” . my-smart-cut-dwim)
(“s-z” . undo)
)
This is how I set up my own Mac-ish CUA mode. Note that I both don’t change the default commands like C-y for yank. I leverage more powerful commands from Xah Lee and SciMax.
Hyper bindings
;; My Hyper (H-) maps
(use-package emacs
:bind
(“H-<backspace>” . delete-forward-char )
(“H-<down>” . xah-end-of-line-or-block ) ; page down
(“H-<left>” . move-beginning-of-line ) ; home
(“H-<right>” . move-end-of-line ) ; end
(“H-<up>” . xah-beginning-of-line-or-block) ; page up
)
These are a work in progress.
Alt bindings
Here is a smattering of my org-mode & denote key bindings:
;; My Alt (A-) maps
;; These are exclusively org-mode and denote related
(use-package org
:bind (
(“A-a” . org-agenda)
(“A-c” . org-capture)
(“A-l” . org-insert-link)
(“A-S-l” . org-insert-link-global)
(“A-o” . org-open-at-point-global)
(“A-.” . org-time-stamp-inactive)
(“M-<SPC>” . org-mark-ring-goto)
:map org-mode-map
(
(“<return>” . scimax/org-return)
(“A-‘” . org-single-quote-region-or-point)
(“A-+” . org-strikethrough-region-or-point)
(“A–“ . org-subscript-region-or-point)
(“A-<return>” . org-return) ; be able to do a standard org-return
(“A-=” . org-superscript-region-or-point)
(“A-\”” . org-double-quote-region-or-point)
(“A-*” . org-toggle-heading)
(“A-<“ . org-insert-structure-template)
(“A-.” . org-time-stamp-inactive)
(“A-,” . org-time-stamp)
(“A-/” . org-sparse-tree)
(“A-<down>” . org-move-subtree-down)
(“A-<left>” . org-promote-subtree)
(“A-<right>” . org-demote-subtree)
(“A-<up>” . org-move-subtree-up)
(“A-@” . org-mark-subtree)
(“A-RET” . org-return) ; when using Scimax’s version
(“A-S-<left>” . org-do-promote)
(“A-S-<right>” . org-do-demote)
(“A-S-b” . org-backward-heading-same-level)
(“A-S-i” . org-time-stamp-inactive)
(“A-S-r” . org-refile)
(“A-S-s” . org-save-all-org-buffers)
(“A-S-u” . outline-up-heading)
(“A-^” . org-sort)
(“A-4” . org-latex-math-region-or-point)
(“A-b” . org-bold-region-or-point)
(“A-C” . org-code-region-or-point)
(“A-d” . org-deadline)
;; (“A-e” . ivy-insert-org-entity)
(“A-f” . org-forward-heading-same-level)
;; (“A-g” . org-mac-grab-link)
(“A-i” . org-italics-region-or-point)
(“A-j” . org-goto)
(“A-k” . scimax-org-headline-to-inlinetask)
(“A-l” . org-add-note) ; add a note to the current entry’s logbook
(“A-n” . org-next-visible-heading)
(“A-p” . org-previous-visible-heading)
;; (“A-q” . counsel-org-tag)
(“A-s” . org-schedule)
(“A-t” . org-toggle-narrow-to-subtree)
(“A-u” . org-underline-region-or-point)
(“A-v” . org-verbatim-region-or-point)
(“A-z” . org-archive-subtree)
(“A-¥” . (lambda ()
“Enter a backslash on the MBA JP keyboard.”
(interactive)
(insert “\\”)
))
)
)
)
App (Caps Lock) launcher bindings
This is a bit of code I actually used ChatGPT to help me refine. As I mentioned before, Caps Lock is redefined with Karbiner Elements to launch specific apps:
(use-package emacs
:if (memq window-system ‘(mac ns))
:config
(defvar my-applications
‘((“a” “DEVONagent.app” “activate-devonagent“)
(“d” “DEVONthink 3.app” “activate-devonthink“)
(“f” “Firefox.app” “activate-firefox“)
(“g” “Beeper Desktop.app” “activate-signal”)
(“i” “Messages.app” “activate-imessage” “/System/Applications/”)
(“m” “Proton Mail.app” “activate-protonmail“)
(“p” “Bitwarden.app” “activate-bitwarden“)
(“s” “Safari.app” “activate-safari”)
(“t” “iTerm.app” “activate-iterm“)
(“v” “Vivaldi.app” “activate-vivaldi“)
(“r” “Fiery Feeds.app” “activate-rss“))
“List of (key app-name function-name [optional app-path]).”)
(defun my-open-app (app-path)
“Open application at APP-PATH using `open -a`.”
(shell-command (concat “/usr/bin/open -a \”” app-path “\””)))
(dolist (app my-applications)
(let* ((key (car app))
(app-name (cadr app))
(func-name (intern (nth 2 app)))
(app-dir (or (nth 3 app) “/Applications/”))
(full-path (concat app-dir app-name))
(docstring (format “Launches %s from %s.” app-name full-path)))
(defalias func-name
`(lambda ()
,docstring
(interactive)
(my-open-app ,full-path)))
(global-set-key (kbd (format “A-C-s-%s” key)) func-name)))
(defun describe-launch-keys ()
“Display a list of custom app launch keybindings.”
(interactive)
(with-help-window “*Launch Keybindings*”
(princ “Custom Application Launch Keybindings (A-C-s-<key>):\n\n”)
(dolist (app my-applications)
(let* ((key (car app))
(app-name (cadr app)))
(princ (format ” A-C-s-%s → %s\n” key app-name))))))
)
Yes, I know many of these things can be done inside of Emacs. It is not my workflow, however.
There is more about my setup I can share. This works for me. YMMV.