1

For example, when I press command + d, I want to run the default M-d command kill-word. But instead it runs S-d.

How can I do that in terminal Emacs in Kitty terminal on macOS (I don't want to globally swap option and command in my system)? Or is there a way to swap all known S-* and M-* commands in Emacs?

  • Emacs version: GNU Emacs 28.1 (build 1, x86_64-apple-darwin21.5.0, Carbon Version 165 AppKit 2113.5) of 2022-07-04.
  • I have macos_option_as_alt yes in my Kitty config.
  • I've tried term-key but it does not seem to can be helped.
Saddle Point
  • 481
  • 7
  • 23
  • 1
    This is a question about Kitty,. not Emacs. – db48x Aug 22 '22 at 14:30
  • @db48x You mean it's never ever possible to do that in emacs as a general solution for every terminal? I didn't know that. Thank you very much! – Saddle Point Aug 23 '22 at 00:26
  • I believe the OSX build of Emacs has limited support for swapping alt and command, but there’s no general mechanism to swap arbitrary modifiers. Afterall, you can just use xmodmap (or similar tools for non–X platforms) to get any set of modifiers you want. – db48x Aug 23 '22 at 00:32
  • @db48x For GUI, there are convenient `mac-*-modifier` variables. So I've though there is an easy way for terminal too. – Saddle Point Aug 23 '22 at 00:35
  • Completely different code path. If you want GUI features, use the GUI. – db48x Aug 23 '22 at 00:36
  • See the modifiers in OSX in my answer here: https://emacs.stackexchange.com/questions/72953/why-i-cant-type-things-such-as-and-in-emacs-with-my-macos-running-brazilian-Portuguese-input-but-they-do-work-outside-of-Emacs? - you can try to change their role as you need, but I do not know Kitty influence on that. Maybe will be useful to ask on Kitty page? – Ian Aug 28 '22 at 13:07
  • @lan I don't have all these `ns-*` variables, but some `mac-*-modifiers` variables. (I'm using `emacs-mac`) But they only work in GUI. I maybe ask on Kitty page later. Thank you all the same! – Saddle Point Aug 28 '22 at 14:23
  • @lan I find that they exists in `emacs-plus`. But they also only work in GUI after a quick test. – Saddle Point Aug 28 '22 at 14:26
  • See this: https://sw.kovidgoyal.net/kitty/keyboard-protocol/ for key modifiers code in Kitty, if you don't already have it and this: https://github.com/CyberShadow/term-keys emacs package, it has an interface for Kitty - and seems to be configurable up to some point. – Ian Aug 29 '22 at 11:49
  • @lan Thanks for you suggestions. I tried `term-key` last week and it definitely help and successfully made some key bindings like (`S-*`/`M-*`) work in terminal. But it can't swap them... – Saddle Point Aug 29 '22 at 12:04

5 Answers5

1

Option 1

  1. Swap Option and Command keys

  2. Instruct Kitty to use Option as alt

(Another option would be to raise an issue with kitty to have an option to swap command and option keys)

Option 2

Copy the following snippet to *scratch* buffer, and do M-x eval-buffer. This snippet makes all the command which are on esc-map, to be available on s- "prefix". IOW, the following snippet is not going to dynamically substitute s- keys with M- keys, but it is going to put the most frequently used M- commands, on the s- "prefix".

(defvar super-mode-map
  (make-keymap))

(defun esc-map->super-map ()
  (map-keymap
   (lambda (key cmd)
     (ignore-errors    ; Replace `ignore-errors' with `demoted-errors'
       (let ((key-desc (single-key-description key)))
     ;; (message "%s\t\t\t%S" (format "s-%s" key-desc) cmd)
     (define-key super-mode-map (kbd (format "s-%s" key-desc)) cmd))))
   esc-map ; `M-` keybindings are from this map
   ))

(define-minor-mode super-mode
  "Super Mode."
  :lighter " Super."
  :keymap super-mode-map
  (esc-map->super-map))

(defun super-mode--turn-on ()
  (when (not super-mode)
    (super-mode 1)))

(defun super-mode--turn-off ()
  (when super-mode
    (super-mode -1)))

(define-globalized-minor-mode global-super-mode
  super-mode super-mode--turn-on)

(global-super-mode)

Once, I install the above snippet, the mode-line has Super as the lighter, and C-h w gives me

kill-word is on s-d, C-<delete>, M-d

Option 3: Setup a input-decode-map

  1. Open kitty, and do emacs -nw -Q from within kitty.
  2. Copy the following snippet to
(define-key input-decode-map "" (kbd "M-x"))
  1. Now place the cursor within the empty string above, and do C-q Command-x. IOW, you are essentially translating the raw input received by Emacs in to a key that Emacs understands.

For example, on Debian (Window Laptop), when I start kitty and do emacs -Q -nw followed by C-h k LeftWinKey x, Emacs is reporting

M-[ 1 2 0 is undefined

(FWIW, LeftWinKey x gets mapped to super on GUI Emacs.)

So, I do a C-x b and repeat the above steps I get

Setting up input-decode-map through quoted-insert

Now, LeftWinKey x runs execute-extended-command.

The disadvantage of this method is

Given all this headache, the question in my mind is, why are you putting your 500 bucks on kitty?


Anyways, I will use this question as an excuse to grok the output from describe-map-tree in a manner that can be manipulated with Emacs Lisp.

  • For Option 1: 1. I don't want to swap `option` and `command` system-wise. And I use both GUI emacs and some times terminal emacs and the default `option(S)`/`command(M)` layout in GUI works very well for me. Swapping the keys globally also requires me to retrain my muscle memory. So I prefer to 'fix' the issue in Kitty or Emacs. 2. I do have the `macos_option_as_alt yes` in my Kitty config but it's not related to this question. With this setting, `option-*` performs `M-*` commands but I'd like to have `command-*` to perform `M-*` commands and `option-*` to perform `S-*` commands. – Saddle Point Aug 26 '22 at 15:36
  • I don't mind the 500 bucks, I just want to unify my experience in both GUI emacs and terminal emacs :-) Also, I don't know if I can fix the issue in Kitty or Emacs. – Saddle Point Aug 26 '22 at 15:36
  • For the other 2 options, I need sometime to try to get it work...Thank you! – Saddle Point Aug 26 '22 at 15:38
  • I am just making things up as we go along ... Don't be frustrated if my suggestion are off-track. –  Aug 26 '22 at 15:42
  • Emacs, atleast on Debian Linux, doesn't install on `super` mappings. If you have your `super` mappings on a map----just like you have the `M-` keys on `esc-map`---it is basically easy to "rewrite"-----that is replace `M-` with `s-` and `s-` with `M-` in the keymaps----and hope that it works, and identify issues. –  Aug 26 '22 at 15:48
1

For example, when I press command + d, I want to run the default M-d

  1. Start kitty.
  2. Do emacs -Q -nw
  3. Copy the following snippet in to *scratch* buffer, and do M-x eval-buffer.
(require 'cl-lib)
(cl-loop for char in (number-sequence ?a ?z)
         for what-kitty-sends = (format "M-[ %s ; 9 u" (key-description (format "%s" char)))
         for what-emacs-should-see = (format "M-%s" (char-to-string char))
         do (message "[%c] %s ---> %s" char what-kitty-sends what-emacs-should-see)
         do (define-key input-decode-map
                        (kbd what-kitty-sends)
                        (kbd what-emacs-should-see)))

You will see the following in *Messages*

[a] ESC [ 9 7 ; 9 u ---> M-a
[b] ESC [ 9 8 ; 9 u ---> M-b
[c] ESC [ 9 9 ; 9 u ---> M-c
[d] ESC [ 1 0 0 ; 9 u ---> M-d
[e] ESC [ 1 0 1 ; 9 u ---> M-e
[f] ESC [ 1 0 2 ; 9 u ---> M-f
[g] ESC [ 1 0 3 ; 9 u ---> M-g
[h] ESC [ 1 0 4 ; 9 u ---> M-h
[i] ESC [ 1 0 5 ; 9 u ---> M-i
[j] ESC [ 1 0 6 ; 9 u ---> M-j
[k] ESC [ 1 0 7 ; 9 u ---> M-k
[l] ESC [ 1 0 8 ; 9 u ---> M-l
[m] ESC [ 1 0 9 ; 9 u ---> M-m
[n] ESC [ 1 1 0 ; 9 u ---> M-n
[o] ESC [ 1 1 1 ; 9 u ---> M-o
[p] ESC [ 1 1 2 ; 9 u ---> M-p
[q] ESC [ 1 1 3 ; 9 u ---> M-q
[r] ESC [ 1 1 4 ; 9 u ---> M-r
[s] ESC [ 1 1 5 ; 9 u ---> M-s
[t] ESC [ 1 1 6 ; 9 u ---> M-t
[u] ESC [ 1 1 7 ; 9 u ---> M-u
[v] ESC [ 1 1 8 ; 9 u ---> M-v
[w] ESC [ 1 1 9 ; 9 u ---> M-w
[x] ESC [ 1 2 0 ; 9 u ---> M-x
[y] ESC [ 1 2 1 ; 9 u ---> M-y
[z] ESC [ 1 2 2 ; 9 u ---> M-z

If I am on right track, Command+d will run kill-word, and Command+x will run execute-extended-command.

When you run C-h k Command+d, Emacs should report that it ultimately translates that to M-d.

  • @saddle-point, report what you feel about the suggestion. Depending on your feedback, we could progress further. This only sets up key translations for a small set of keys `M-a` to `M-z` and nothing more. We may have to establish maps for the whole shebang. I want to ensure that we are on right track, each step of the way. –  Aug 31 '22 at 10:35
  • @saddle-point, I updated the snippet I posted earlier at https://emacs.stackexchange.com/a/73379/31220. (I missed the `kbd` call in `define-key` in the initial draft, which I have now fixed). With that snippet, on my Debian, `LeftWinKey+x`, runs `M-x`. FWIW, `LeftWinKey` on my Windows Laptop sends the same string as `Command+key` on Mac Laptop. –  Aug 31 '22 at 10:57
  • That's magic! Works like a charm. Can you also get commands like `M-,` or `C-M-a` work? Also `S-*` by the options key? I have `S-*` commands from `lsp-mode` and other libraries. Thanks! – Saddle Point Aug 31 '22 at 11:52
  • Apropos `C-M-a` and stuff, I am working on deconstructing the kitty stuff. This is a work in progress. I have answered your original question. So, mark the answer, and award the 500 bucks you promised. Open a fresh question, and point me to it, I will post my resolution there. I want to get the bounty first ... There is lots of dense information here, and I think it will generally help other users if the information is taken one by one. –  Aug 31 '22 at 11:58
  • The original question includes getting the option and swap key swapped and worked. Maybe you can also post how to make option key behaves like `S-*`. Also `C-S-*` to `C-M-*`. But don't worry, I'm accepting your answer! – Saddle Point Aug 31 '22 at 12:07
  • Thanks. You kept your side of the deal. Post the two questions **(Q1)** *Swap `s` with `M-`, when the `Emacs` recognizes `s` and `M` keys. (This has nothing to do with `kitty`.)* I have a reply right at hand. **(Q2)** *Getting `Command+Control+a` etc translate to `C-M-a` on kitty.* This will take little bit of effort. But instinctively you know that I have arrived at an answer, and it is just a matter of working out the details. **(Q1) is of general interest to most people. Havinng a fresh question and answer for it, will help lots of other people.**. –  Aug 31 '22 at 12:24
  • Done: https://emacs.stackexchange.com/questions/73382/how-to-swap-super-and-meta-in-terminal-emacs-on-macos https://emacs.stackexchange.com/questions/73383/how-to-get-command-control-like-key-bindings-translate-to-c-m-in-ter – Saddle Point Aug 31 '22 at 12:37
  • 1
    Thanks. I have bookmarked the questions ... I will reply to them tomorrow. –  Aug 31 '22 at 12:38
0

I don't have access to a Mac machine, and I am not sure if this manual page applies to Mac machines.

Operating on X11 Keysyms

(info "(elisp) X11 Keysyms")

Anyways try this

(setq x-meta-keysym 'super)
(setq x-super-keysym 'meta)

You can specify which keysyms Emacs should use for the Control, Meta, Alt, Hyper, and Super modifiers by setting these variables:

-- Variable: x-ctrl-keysym

-- Variable: x-alt-keysym

-- Variable: x-meta-keysym

-- Variable: x-hyper-keysym

-- Variable: x-super-keysym

 The name of the keysym that should stand for the `Control` modifier
 (respectively, for `Alt`, `Meta`, `Hyper`, and `Super`).  

For example, here is how to swap the Meta and Alt modifiers within Emacs:

(setq x-alt-keysym 'meta)
(setq x-meta-keysym 'alt)
0

If mac-command-modifier is bound something like this should work to remap 'command' key as 'meta' and map 'hyper' to the 'function' key.

(setq mac-command-modifier 'meta          
      mac-function-modifier 'hyper        
      mac-right-option-modifier 'none))   

It's also possible to unbind keys in emacs to enable the OS or another app to use it (e.g. right 'alt' key for accented input on macOS). You might need to set or unset the mappings in kitty, or the 'Modifier Keys' section of the keyboard control panel for it to work as expected.

zzkt
  • 456
  • 3
  • 10
  • These variables only work in GUI emacs. – Saddle Point Aug 30 '22 at 08:13
  • Another option could be kitty specific remapping using https://karabiner-elements.pqrs.org/docs/json/complex-modifications-manipulator-definition/conditions/frontmost-application/ – zzkt Aug 30 '22 at 10:42
  • That's an interesting suggestion. But I can not get it work. Following the post I remap `command` to `option` successfully in when frontmost application is Kitty. The issue is, pressing `command + *` does not make emacs invoke the original commands bound originally on `option`, but instead it invoke some global `option + *` commands globally set on my system. For example, I set `option + d` to open the `Dictionary.app`. When I press `command + d`, it opens the `Dictionary.app` instead of running "the original `option + d`" in terminal emacs. – Saddle Point Aug 30 '22 at 12:28
  • (1) `C-q Command+x` => `^[[120;9u` . **This means that, `Command` is `super` (value 9 = `super`)**. (2) `C-q Option+x` => `^[x`. **This means that `Option` is sending `ESC`)** (3) ` C-h k Option+x` => `s-x ` **Why is `Option` sending `super`. Based on quoted insert it sends `ESC` (or `M` maybe). Not `super`. This is weird. And there is inconsistency between (2) and (3)**. Did you make an error while copy pasting? When you do (2), what do you see in `*Messages* buffer? Can you confirm you are doing `emacs -Q -nw`? –  Aug 31 '22 at 08:56
  • Update my earlier comment .... Check your observed outputs once more .... There is some inconsistency. I also want to see what `Emacs` reports in `*Messages*` buffer. Please add that info as well. –  Aug 31 '22 at 09:01
  • @whitetrillium You replied in the wrong thread and I don't get notification... I have uploaded a [video](https://www.youtube.com/watch?v=jxSp-1CX7a0) for that, please check ... – Saddle Point Aug 31 '22 at 09:19
  • @saddle-point, I looked at the video. I couldn't see the details in the video. I would have preferred bigger fonts, and a non-dark background. Once you start `Emacs` in kitty, you can do `M-x load-theme adwaita` or some such thing, so that you get some decent thing to look at. Anyways, it doesn't matter ... The output you shared in the https://gist.github.com/liebkne/012d5cacece556e6e9823cefac847ed5 is good enough. –  Aug 31 '22 at 10:32
0

Overview of suggestion

I still think that the best way to proceed would be to use the input-decode-map. This is an elaboration of Option 3 detailed here https://emacs.stackexchange.com/a/73299/31220.


Quick Suggestion for Experimentaion

Unlike my Debian, your Mac recognizes s- and M- keys.

So, start with this

(define-key input-decode-map (kbd "s-x") (kbd "M-x"))
(define-key input-decode-map (kbd "M-x") (kbd "s-x"))

Now do Command+x and Option+x, do they get swapped. If yes, it is just a matter of writing some loop to install the input-decode-map all other keys that Emacs sees.

Above paragraph means that, instead of saying whenever I see super convert it to M, you say whenever I see s-x convert it to a M-x, whenever I see s-a, convert it to M-a etc.

That is, you go on an case-by-case basis, introducing new translations as you go along. This is the point made in Mappings needed to use cmd as ctrl on kitty+macos, where the user uses a ruby script to generate the maps. In our case, we will be using an Emacs Lisp loop ot generate the translation tables, and it install it in one of the translation keymaps (most likely input-decode-map).

Answer these questions for a ready solution to your problem

Answer the following questions, and I will turn the suggestion below in to a readily-usable solution.

Question Set 1

  1. What does Emacs report when you do C-h k Command+x?
  2. What does Emacs report when you do C-h k Option+x?

(To answer, Copy paste what you see on *Help* buffer for above questions)

Question Set 2

  1. In *scratch* buffer, do C-q Command+x. What do you see?
  2. In *scratch* buffer, do C-q Option+x. What do you see?

To answer, do one of the following

  • share a screenshot of scratch buffer after doing above operations
  • Do some postmortem analysis of Emacs and kitty behaviours as seen in the next section, where I analyze the behaviour of LeftWinKey+x on Debian/Windows keyboard.

No access to Mac on my end; so unable to dig deeper

I don't have access to Mac machines. This means,

  • I don't have keys marked Command or Optoin.
  • I can't experiment, and delve deep in to what kitty is sending, and Emacs is doing on a Mac. At the best, I can make only a reasonable guess based on what you share with me.

(As I already shared with you, I don't have access to Mac machines, and this prevents me from experimentaion, and doing reasonable dedcuction from observed behaviours. So, I need to see what happens the Macs)

An attempt at reconciling what Emacs sees and what kitty sends --- A postmotem of observed behaviour of LeftWinKey+x on emacs -Q -nw running on Dell Windows Laptop

(This is for those interested in Debian, where Emacs running within kitty doesn't recognize LeftWinKey+x as s-x)

  1. LeftWinKey+x is NOT recognized
  2. When in *scratch* buffer, C-h k LeftWinKey+x reports M-[ 1 2 0 is undefined in *Messages* buffer, and the ;9u is inserted in to *scratch* buffer. (There is a brief way momemt where ESC blah blah flashes in the echo area. This message doesn't end up in the *Messages* buffer)
  3. While in *scratch* buffer, doing C-q LeftWinKey+x inserts the encircled "raw" string in the below image.

The circled portion in below image, is the raw code inserted with C-q LeftWinKey+x. C-q LeftWinKey + x on emacs -Q -nw running within kitty

The sexp in the above image is equivalent to

(define-key input-decode-map (kbd "ESC [ 1 2 0 ; 9 u") (kbd "s-x"))

To decode the "raw string" seen in the above image, do C-u C-x = on each component part. The cryptic first part is ESC [ or M-[.

Unicode Name buffer code display
ESCAPE #x1B terminal code #x1B
LEFT SQUARE BRACKET #x5B terminal code #x5B
x 120, #x78 terminal code #x78

The raw string seen by Emacs is equivalent to the first form of kitty sequence

Kitty-syntax CSI number ; modifiers u
Component Parts 0x1b 0x5b 120 ; 9 u
Emacs-syntax ESC x ; super

Reproduction of kitty-'s Keyboard Protocol

Reproduced from kitty Keyboard Protocol

S.No Kitty Syntax Key
1 CSI number ; modifiers [u~]
2 CSI 1; modifiers [ABCDEFHPQRS]
3 0x0d - Enter
4 0x7f or 0x08 Backspace
5 0x09 - Tab

(CSI is the bytes 0x1b 0x5b)

Encoding of Modifier keys in Kitty

Modifier Value (in binary format ) Value (Decimal)
shift 0b1 (1)
alt 0b10 (2)
ctrl 0b100 (4)
super 0b1000 (8)
hyper 0b10000 (16)
meta 0b100000 (32)
caps_lock 0b1000000 (64)
num_lock 0b10000000 (128)

In the escape code, the modifier value is encoded as a decimal number which is 1 + actual modifiers.

For example,

Example of how to arrive at decimal value of Modifiers for use with Kitty

Modifier Decimal
shift 1 + 1 = 2
ctrl+shift 1 + 0b101 = 6
No modifier 1
  • Hi, should I answer the questions with the first two lines of script evaluated? – Saddle Point Aug 31 '22 at 07:46
  • Yes. That willl give you some incentive to proceed ahead. –  Aug 31 '22 at 07:47
  • But what would help the problem at hand is the answer for the 2 sets of questions , with 2 question in each set found in `Answer these questions for a ready solution to your problem`. Let me know once you update the answers. I am convinced that this problem has a solution within the scope of Emacs, and doesn't involve kitty at all. If possible, extend the grace period on bounty ... so that I have some incentives to keep working on the question at hand. –  Aug 31 '22 at 07:51
  • One more question, should I use an empty config of Kitty to test? Or maybe with single config `macos_option_as_alt yes`. – Saddle Point Aug 31 '22 at 07:55
  • I don't have an answer ... Just post with whatever is your current `kitty` config. Start Emacs with `emacs -Q -nw` though, just to keep things simple. You haven't answered my one another question: **Do you have current bindings on `super`.**? –  Aug 31 '22 at 08:06
  • Hi, [here](https://gist.github.com/liebkne/012d5cacece556e6e9823cefac847ed5) are some basic output of the questions. I tried some `S` combs in `emacs -q -nw`, but it seems that they don't come with the default setting. How can I extend the bounty? – Saddle Point Aug 31 '22 at 08:39