The accepted answer of this question provides a way in terminal Emacs to get command(super
) key bindings worked as M-*
. The solution should work for every terminal.
How to swap the command (super
) and option (meta
) then?
The accepted answer of this question provides a way in terminal Emacs to get command(super
) key bindings worked as M-*
. The solution should work for every terminal.
How to swap the command (super
) and option (meta
) then?
No need to swap/use the modifier keys.
When working with Emacs in Terminal, you can use a built-in feature to
implement the behavior specific for the modifier keys Super
, Hyper
, and Alt
.
This feature can be started by: C-x @
followed by one of the characters
s
or h
or a
corresponding to the modifier mode and followed by the rest
of the desired command. For instance, C-x @ s v
(for s-v') or C-s @ h C-a
(for 'Hyper-Control-a').
You don't need to write any code line, and, interesting, works also in GUI mode, so developing a habit to use it in terminal does not harm when in GUI.
How to swap
super
andmeta
in terminal Emacs on macOS?
Before trying on kitty
try the below suggestion on GUI Emacs first.
(require 'dash)
;; (defvar modmap--bare-keys
;; (cl-loop with case-fold-search = nil
;; for ascii-num in (number-sequence 0 255)
;; for key-desc = (key-description (char-to-string ascii-num))
;; unless (string-match-p (rx (or "M-" "C-")) key-desc)
;; collect key-desc))
(defvar modmap--bare-keys
'("TAB" "RET" "ESC" "SPC" "!" "\"" "#" "$" "%" "&" "'" "(" ")" "*" "+"
"," "-" "." "/" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" ":" ";" "<"
"=" ">" "?" "@" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M"
"N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "[" "\\" "]" "^"
"_" "`" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
"p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "{" "|" "}" "~" "DEL"))
;; (defvar modmap--fn-keys
;; (mapcar (lambda (s)
;; (intern (format "<%s>" s)))
;; `(
;; ;; Cursor arrow keys.
;; left up right down
;; ;; Other cursor repositioning keys.
;; begin end home next prior
;; ;; Miscellaneous function keys.
;; select print execute backtab insert undo redo clearline
;; insertline deleteline insertchar deletechar
;; ;; Numbered function keys (across the top of the keyboard).
;; ,@(mapcar (lambda (n)
;; (format "f%s" n))
;; (number-sequence 1 35))
;; ;; Keypad keys (to the right of the regular keyboard)
;; ;; with names or
;; ;; punctuation.
;; kp-add kp-subtract kp-multiply kp-divide kp-backtab
;; kp-space kp-tab kp-enter kp-separator kp-decimal kp-equal
;; kp-prior kp-next kp-end kp-home kp-left kp-up kp-right kp-down
;; kp-insert kp-delete
;; ;; Keypad keys with digits.
;; ,@(mapcar (lambda (n)
;; (format "kp%s" n))
;; (number-sequence 0 9))
;; ;; Keypad PF keys.
;; ,@(mapcar (lambda (n)
;; (format "kp-f%s" n))
;; (number-sequence 1 4)))))
(defvar modmap--fn-keys
'(<left> <up> <right> <down> <begin> <end> <home> <next> <prior>
<select> <print> <execute> <backtab> <insert> <undo> <redo>
<clearline> <insertline> <deleteline> <insertchar> <deletechar> <f1>
<f2> <f3> <f4> <f5> <f6> <f7> <f8> <f9> <f10> <f11> <f12> <f13> <f14>
<f15> <f16> <f17> <f18> <f19> <f20> <f21> <f22> <f23> <f24> <f25>
<f26> <f27> <f28> <f29> <f30> <f31> <f32> <f33> <f34> <f35> <kp-add>
<kp-subtract> <kp-multiply> <kp-divide> <kp-backtab> <kp-space>
<kp-tab> <kp-enter> <kp-separator> <kp-decimal> <kp-equal> <kp-prior>
<kp-next> <kp-end> <kp-home> <kp-left> <kp-up> <kp-right> <kp-down>
<kp-insert> <kp-delete> <kp0> <kp1> <kp2> <kp3> <kp4> <kp5> <kp6>
<kp7> <kp8> <kp9> <kp-f1> <kp-f2> <kp-f3> <kp-f4>))
(defvar modmap--all-keys
(append modmap--bare-keys (mapcar #'symbol-name modmap--fn-keys)))
(defvar modmap--modifiers->string
`(
(alt . "M-")
(ctrl . "C-")
;; (hyper . "H-")
;; (shift . "S-")
(super . "s-")
))
(defvar modmap--all-modifiers
(mapcar #'car modmap--modifiers->string))
(defvar modmap--from->to
`((super . alt)
(alt . super)))
(defun modmap--print-keys (keys)
(apply #'concat
(cl-loop with alist = modmap--modifiers->string
for x in keys
collect (cond ((numberp x) (char-to-string x))
((stringp x) x)
((symbolp x) (alist-get x alist))
(t (error "This shouldn't happen"))))))
(defun modmap--replace (keys &optional modifier-translations)
(cl-loop for key in keys
collect (or (alist-get key (or modifier-translations
modmap--from->to))
key)))
(defun modmap--do (&optional install)
(interactive "P")
(cl-loop with format-spec = "\n%-30s\t%s"
with case-fold-search = nil
for modifiers in (-powerset modmap--all-modifiers)
do (cl-loop for keys in modmap--all-keys
for from = (append modifiers (list keys))
for to = (modmap--replace from modmap--from->to)
for from-keys = (modmap--print-keys from)
for to-keys = (modmap--print-keys to)
unless (string= from-keys to-keys)
do (princ (format format-spec from-keys to-keys))
(when install
(with-demoted-errors "Error :%S"
(define-key input-decode-map
(kbd from-keys)
(kbd to-keys)))))))
(defgroup modmap-mode nil
"Options for Modmap Mode."
:tag "Modmap Mode"
:group 'my)
(defvar modmap--input-decode-map)
(define-minor-mode modmap-mode
"Modmap Mode."
:lighter " Modmap Mode."
:group 'modmap-mode
:global t
(cond
(modmap-mode
(setq modmap--input-decode-map (copy-tree input-decode-map t))
(with-output-to-temp-buffer (get-buffer-create "*modmap*")
(let* ((format-spec "\n%-30s\t%s")
(header ""))
(princ (format "\n%s" "You have requested the following translation ..."))
(setq header (format format-spec "From" "To"))
(princ (format "\n\n%s" header))
(princ (format "\n%s" (make-string (length header) ?-)))
(cl-loop for (from . to) in modmap--from->to
do (princ (format format-spec
(modmap--print-keys (list from))
(modmap--print-keys (list to)))))
(princ (format "\n\n%s" "Installing following translation in `input-decode-map'"))
;; Is `input-decode-map' may not be the _right_ translation map in
;; to which the modifier translations can be installed? I am not
;; sure. This is a prototype code ... and for now this works.
;;
;; According to
;;
;; (info "(elisp) Translation Keymaps")
;;
;; When the ‘read-key-sequence’ function reads a key sequence
;; (*note Key Sequence Input::), it uses “translation keymaps” to
;; translate certain event sequences into others.
;;
;; The translation keymaps are ‘input-decode-map’,
;; ‘local-function-key-map’, and ‘key-translation-map’ (in order
;; of priority).
(setq header (format format-spec "\nWhen you type this" "Emacs translates it to"))
(princ (format "\n%s" header))
(princ (format "\n%s" (make-string (length header) ?-)))
(modmap--do 1))))
(t
(when (boundp 'modmap--input-decode-map)
(setq input-decode-map modmap--input-decode-map)))))
s
key.;; Install some bindings on `super` keys for demo purposes.
;; M-x is `execute-extended-command'
;; s-x prints "Hello s-x"
(global-set-key (kbd "s-x")
(defun hello-world-a ()
(interactive)
(message "%s" "Emacs says \"Hello s-x\"")))
;; C-M-% is normally `query-replace-regexp'
;; C-s-% prints "Hello C-M-%"
(global-set-key (kbd "C-s-%")
(defun hello-world-b ()
(interactive)
(message "%s" "Emacs says \"Hello \"C-M-%\"")))
M-x modmap-mode
. You will see the following buffer popup, and it tells what the command just did.M-x
, C-M-%
. See what happens.s-x
, C-s-%
. See what happens.C-h k
on above keys. See what Emacs
reports.s-x modmap-mode
, and try the above steps once more. See what happens.The M-x modmap-mode
essentially "swaps" M-
and s-
keys.