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?

Saddle Point
  • 481
  • 7
  • 23

2 Answers2

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.

Ian
  • 1,321
  • 10
  • 12
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.