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 get Command + Control + */Command + Option + */... like key bindings translate to C-M-*/C-S-*/... in terminal Emacs in Kitty on macOS then?

Saddle Point
  • 481
  • 7
  • 23

1 Answers1

0
  1. Start kitty
  2. Do emacs -nw
  3. Copy the snippet to *scratch* buffer and then do M-x eval-buffer
(require 'dash)

(defvar kitty--char-and-shifted-char)
(setq kitty--char-and-shifted-char
      (mapcar (lambda (it)
                (cons (string-to-char (car it))
                      (string-to-char (cdr it))))
              (append
               (mapcar (lambda (c)
                         (cons (char-to-string c) (char-to-string (upcase c))))
                       (number-sequence ?a ?z))
               '(
                 ("`" . "~")
                 ("1" . "!")
                 ("2" . "@")
                 ("3" . "#")
                 ("4" . "$")
                 ("5" . "%")
                 ("6" . "^")
                 ("7" . "&")
                 ("8" . "*")
                 ("9" . "(")
                 ("0" . ")")
                 ("-" . "_")
                 ("=" . "+")
                 ("[" . "{")
                 ("]" . "}")
                 ("\\" . "|")
                 (";" . ":")
                 ("'" . "\"")
                 ("," . "<")
                 ("." . ">")
                 ("/" . "?")))))

(defun kitty--modifiers->value (modifiers)
  (cl-loop with modifiers->value = '(
                                     (shift . 1)
                                     (alt . 2)
                                     (ctrl . 4)
                                     (super . 8)
                                     (hyper . 16)
                                     (meta . 32)
                                     (caps_lock . 64)
                                     (num_lock . 128))
           for modifier in modifiers
           summing (alist-get modifier modifiers->value) into n
           finally return (1+ n)))

(defun kitty-modifiers->emacs-keys (keys)
  (apply #'concat
         (cl-loop with alist = `((shift . "S-")
                                 (super . "s-")
                                 (alt . "M-")
                                 (ctrl . "C-"))
                  for x in keys
                  collect (cond ((numberp x) (char-to-string x))
                                ((stringp x) x)
                                ((symbolp x) (alist-get x alist))))))

(defvar kitty--info)
(setq kitty--info
      (cl-loop for (base-char . shifted-char) in kitty--char-and-shifted-char
               ;; M-char1
               collect (list
                        base-char
                        nil
                        (list (char-to-string base-char)))
               ;; M-S-char1
               collect (list
                        base-char
                        (list 'shift)
                        (list (char-to-string shifted-char)))))

(defun kitty-configure--Command-key (CommandKey)
  (interactive
   (list
    ;; When we press `Command' key, what do we want to see `M-' or `s-'.
    ;;
    ;; Since `Option' key sends `M-', it is preferable to choose `s-'
    (let* ((choices '(("super" . super)
                      ("alt" . alt)))
           (option (completing-read "Treat Command key as " choices nil t)))
      (assoc-default option choices))))
  (cl-loop with format-spec = "%-32s\t%s"
           ;; When we press Command, Kitty sends a super modifier along with the
           ;; key
           with kitty--prefix = 'super
           with modifier-set = '(ctrl
                                 ;; hyper
                                 )
           initially (let* ((header (format format-spec
                                            "What Emacs Sees"
                                            "What Kitty Sends")))
                       (message "When you press `Command' key ....")
                       (message "%s" header)
                       (message "%s" (make-string (length header) ?-)))
           for new-modifiers in (-powerset modifier-set)
           do (cl-loop for (base-char modifiers emacs-keys) in kitty--info
                       for what-emacs-should-see = (kitty-modifiers->emacs-keys
                                                    (cons CommandKey (append new-modifiers emacs-keys)))
                       for what-kitty-sends = (format "M-[ %s ; %s u"
                                                      (key-description
                                                       (format "%s" base-char))
                                                      (key-description
                                                       (format "%s" (kitty--modifiers->value
                                                                     (cons kitty--prefix
                                                                           (append new-modifiers modifiers))))))
                       do (message format-spec what-emacs-should-see what-kitty-sends)
                       (define-key input-decode-map
                                   (kbd what-kitty-sends)
                                   (kbd what-emacs-should-see)))))


  1. Do M-x kitty-configure--Command-key
  2. You will be prompted for how you want the Command key to behave. Choose super or alt. I suggest you pick super. Since Option key can be configured to send M (or is it ESC?)
  3. You will see following *Messages*. They give an indication of what keys Emacs sees.

When you press ‘Command’ key ....
What Emacs Sees                     What Kitty Sends
-------------------------------------------------
s-C-a                               M-[ 9 7 ; 1 3 u
s-C-A                               M-[ 9 7 ; 1 4 u
s-C-b                               M-[ 9 8 ; 1 3 u
s-C-B                               M-[ 9 8 ; 1 4 u
s-C-c                               M-[ 9 9 ; 1 3 u
s-C-C                               M-[ 9 9 ; 1 4 u
s-C-d                               M-[ 1 0 0 ; 1 3 u
s-C-D                               M-[ 1 0 0 ; 1 4 u
s-C-e                               M-[ 1 0 1 ; 1 3 u
s-C-E                               M-[ 1 0 1 ; 1 4 u
....
s-a                                 M-[ 9 7 ; 9 u
s-A                                 M-[ 9 7 ; 1 0 u
s-b                                 M-[ 9 8 ; 9 u
s-B                                 M-[ 9 8 ; 1 0 u
s-c                                 M-[ 9 9 ; 9 u
s-C                                 M-[ 9 9 ; 1 0 u
s-d                                 M-[ 1 0 0 ; 9 u
s-D                                 M-[ 1 0 0 ; 1 0 u
s-e                                 M-[ 1 0 1 ; 9 u
s-E                                 M-[ 1 0 1 ; 1 0 u
  1. Do C-h k Command+x and see what sees
  2. Do Command+x and see what Emacs sees
  3. Do C-Command+% and see what Emacs sees.
  4. Do M-x kitty-configure--Command-key, and for a change pick alt and repeat the previous steps.

Above snippet doesn't handle any key not seen in *Messages* specifically it does NOT handle Functional key definition and any other .

Setting up of the keys that are NOT configured by this snippet, is left as an exercise to the reader.


FWIW, on Debian/Windows Keyboard,emacs running within kitty doesn't respond to LeftWinKey. (LeftWinKey is usually s- (=super) on GTK Emacs).

So, the snippet shared above not only can be used on Macs to configure the Command key, but also can be used to configure LeftWin on Debian/Windows machines.

I--the author of this snippet--use Debian/Windows laptop btw. This is a a en:us keyboard with qwerty layout.

~$ setxkbmap -print -verbose 10
Setting verbose level to 10
locale is C
Trying to load rules file ./rules/evdev...
Trying to load rules file /usr/share/X11/xkb/rules/evdev...
Success.
Applied rules from evdev:
rules:      evdev
model:      pc105
layout:     us,mn,us
variant:    ,,
options:    numpad:microsoft,keypad:pointerkeys,compose:menu,caps:shiftlock
Trying to build keymap using the following components:
keycodes:   evdev+aliases(qwerty)
types:      complete+numpad(microsoft)
compat:     complete+ledcaps(shift_lock)
symbols:    pc+us+mn:2+us:3+inet(evdev)+capslock(shiftlock)+compose(menu)+keypad(pointerkeys)
geometry:   pc(pc105)
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)" };
    xkb_types     { include "complete+numpad(microsoft)"    };
    xkb_compat    { include "complete+ledcaps(shift_lock)"  };
    xkb_symbols   { include "pc+us+mn:2+us:3+inet(evdev)+capslock(shiftlock)+compose(menu)+keypad(pointerkeys)" };
    xkb_geometry  { include "pc(pc105)" };
};