0

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?

2 Answers 2

1

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.

1
  • That's helpful. Thank you for the information. Commented Oct 8, 2022 at 6:38
0

How to swap super and meta in terminal Emacs on macOS?

Before trying on kitty try the below suggestion on GUI Emacs first.

  1. Install the following snippet
(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)))))


  1. Install also the following snippet. Which puts commands on the 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-%\"")))



  1. Now do M-x modmap-mode. You will see the following buffer popup, and it tells what the command just did.

M-x modmap-mode

  1. Try M-x, C-M-%. See what happens.
  2. Try s-x, C-s-%. See what happens.
  3. Try C-h k on above keys. See what Emacs reports.

M-x modmap-mode in action (1)

M-x modemap-mode in action (2)

  1. Do 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.

2
  • Everything works like a charm in the GUI emacs. I think there's a typo in the messages part of step 2. Commented Sep 15, 2022 at 8:57
  • How to adapt it to Kitty? Commented Sep 15, 2022 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.