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.
10
  • 1
    This is a question about Kitty,. not Emacs.
    – db48x
    Aug 22, 2022 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! Aug 23, 2022 at 0: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, 2022 at 0:32
  • @db48x For GUI, there are convenient mac-*-modifier variables. So I've though there is an easy way for terminal too. Aug 23, 2022 at 0:35
  • Completely different code path. If you want GUI features, use the GUI.
    – db48x
    Aug 23, 2022 at 0:36

5 Answers 5

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.

5
  • 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. Aug 26, 2022 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. Aug 26, 2022 at 15:36
  • For the other 2 options, I need sometime to try to get it work...Thank you! Aug 26, 2022 at 15:38
  • I am just making things up as we go along ... Don't be frustrated if my suggestion are off-track.
    – user31220
    Aug 26, 2022 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.
    – user31220
    Aug 26, 2022 at 15:48
1
+500

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.

8
  • @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.
    – user31220
    Aug 31, 2022 at 10:35
  • @saddle-point, I updated the snippet I posted earlier at 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.
    – user31220
    Aug 31, 2022 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! Aug 31, 2022 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.
    – user31220
    Aug 31, 2022 at 11:58
  • 1
    Thanks. I have bookmarked the questions ... I will reply to them tomorrow.
    – user31220
    Aug 31, 2022 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)
1
  • Unfortunately, none of the five variables exists in emacs-mac or emacs-plus... Aug 25, 2022 at 8:14
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.

7
  • These variables only work in GUI emacs. Aug 30, 2022 at 8:13
  • Another option could be kitty specific remapping using karabiner-elements.pqrs.org/docs/json/…
    – zzkt
    Aug 30, 2022 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. Aug 30, 2022 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`?
    – user31220
    Aug 31, 2022 at 8: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.
    – user31220
    Aug 31, 2022 at 9:01
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
6
  • Hi, should I answer the questions with the first two lines of script evaluated? Aug 31, 2022 at 7:46
  • Yes. That willl give you some incentive to proceed ahead.
    – user31220
    Aug 31, 2022 at 7: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.
    – user31220
    Aug 31, 2022 at 7:51
  • One more question, should I use an empty config of Kitty to test? Or maybe with single config macos_option_as_alt yes. Aug 31, 2022 at 7: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.?
    – user31220
    Aug 31, 2022 at 8:06

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.