kovidgoyal / kitty

Cross-platform, fast, feature-rich, GPU based terminal
https://sw.kovidgoyal.net/kitty/
GNU General Public License v3.0
24.57k stars 983 forks source link

Inconsistent Meta handling when Meta and Alt are separate #4826

Closed dbivolaru closed 2 years ago

dbivolaru commented 2 years ago

Description

Ok I think I managed to get a minimum test setup going:

Real modifier <LALT> set to Super_L and mapped to Mod4 Virtual modifier <ALT> also mapped to Mod4

Real modifier <LWIN> set to Meta_L and mapped to Mod1 Virtual modifier <META> also mapped to Mod1

Kitty interprets the key-press M-e as ^[[101;33u and Super-e as ^[e.

Press xkb_keycode: 0x85 clean_sym: Meta_L composed_sym: Meta_L mods: numlock glfw_key: 57446 (LEFT_META) xkb_key: 65511 (Meta_L) alternate_key: 57444 (LEFT_SUPER)
on_key_input: glfw key: 0xe066 native_code: 0xffe7 action: PRESS mods: numlocktext: '' state: 0 ignoring as keyboard mode does not support encoding this event
Release xkb_keycode: 0x85 clean_sym: Meta_L mods: meta+numlock glfw_key: 57446(LEFT_META) xkb_key: 65511 (Meta_L) alternate_key: 57444 (LEFT_SUPER)
on_key_input: glfw key: 0xe066 native_code: 0xffe7 action: RELEASE mods: meta+numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event
Press xkb_keycode: 0x86 clean_sym: Meta_R composed_sym: Meta_R mods: numlock glfw_key: 57452 (RIGHT_META) xkb_key: 65512 (Meta_R) alternate_key: 57450 (RIGHT_SUPER)
on_key_input: glfw key: 0xe06c native_code: 0xffe8 action: PRESS mods: numlocktext: '' state: 0 ignoring as keyboard mode does not support encoding this event
Release xkb_keycode: 0x86 clean_sym: Meta_R mods: meta+numlock glfw_key: 57452(RIGHT_META) xkb_key: 65512 (Meta_R) alternate_key: 57450 (RIGHT_SUPER)
on_key_input: glfw key: 0xe06c native_code: 0xffe8 action: RELEASE mods: meta+numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event

Expected

Kitty should interpret the key-press M-e as M-e and Super-e as e.

Environment

kitty.x86_64.0.24.4-1.fc35 Linux 5.16.12-200.fc35.x86_64 Wayland

Keyboard setup

xkb symbols

partial modifier_keys
xkb_symbols "hhkb" {
    key <LWIN> { [ Meta_L, Meta_L ] };
    key <RWIN> { [ Meta_R, Meta_R ] };
    key <LALT> { type[Group1] = "ONE_LEVEL", symbols[Group1] = [ Super_L ] };
    key <RALT> { type[Group1] = "ONE_LEVEL", symbols[Group1] = [ Super_R ] };
    key <META> { [ NoSymbol, Meta_L, Meta_R ] };
    key <ALT> { [ NoSymbol, Alt_L, Alt_R ] };
    key <HYPR> { [ NoSymbol, Hyper_L, Hyper_R ] };
    modifier_map Mod1 { <LWIN>, <RWIN>, <META> };
    modifier_map Mod3 { <HYPR> };
    modifier_map Mod4 { <LALT>, <RALT>, <SUPR>, <ALT> };
};

xmodmap (for reference only)

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Meta_L (0x85),  Meta_R (0x86),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3        Hyper_L (0xcf)
mod4        Super_L (0x40),  Super_R (0x6c),  Alt_L (0xcc),  Super_L (0xce)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

kitty.conf

Can be reproduced with defaults.

References

Ref: https://github.com/kovidgoyal/kitty/issues/3430#issuecomment-1066099286_ CC: @orki

kovidgoyal commented 2 years ago

On Sun, Mar 13, 2022 at 03:26:39PM -0700, Dorian Bivolaru wrote:

Description

Ok I think I managed to get a minimum test setup going:

Real modifier <LALT> set to Super_L and mapped to Mod4 Virtual modifier <ALT> also mapped to Mod4

Real modifier <LWIN> set to Meta_L and mapped to Mod1 Virtual modifier <META> also mapped to Mod1

Kitty interprets the key-press M-e as ^[[101;33u and Super-e as ^[e.

That is correct. There is no such key a M-e in legacy terminal key protocol. And you have madded super to Alt so kitty is sending ^[e which is alt-e as expected.

dbivolaru commented 2 years ago

@kovidgoyal With a "pure" Meta key setup on Mod1, kitty fails to send the right character sequence which in this case is ^[e or for 8-bit terminals a 0xe5 (ie 0x65 with the 8th bit set - that's what I mean with M-e). This is exactly what the linux console, Xterm and Gnome Terminal do.

Ref: https://man7.org/linux/man-pages/man5/terminfo.5.html "If the terminal has a “meta key” which acts as a shift key, setting the 8th bit of any character transmitted, this fact can be indicated with km."

Historically this issue has been fixed in 2007 in Xterm: https://invisible-island.net/xterm/xterm.log.html#xterm_225 Original discussion: https://lists.debian.org/debian-x/2004/09/msg00390.html

My add: Alt itself was never meant to generate escape sequences but alternate characters which are keyboard layout specific (especially looking at non-US keyboards), plus special things like SysRq and other local terminal functions. Just by coincidence in most distros Alt and Meta are mapped together and the rightmost Alt is implemented with two levels (Alt then Meta) to still allow for the original Alt functionality.

But what should generate an escape sequence is Meta and never Alt. Unless xkb says they are mapped together. An interesting side effect is that M-e key bindings in vim for example do not work under kitty when a pure Meta key is present. And there are keyboards out there sporting one (like Solaris).

My question is why hard-code Alt in kitty? Only Meta should generate escapes. This wrong approach is also reflected in the macos_option_as_alt instead of relying on the OS's use option key as meta and handling meta correctly.

If you're fine I will make a PR for this in the next weeks.

kovidgoyal commented 2 years ago

Meta is an X11 specific concept. Indeed, nowadays there is no real hardware with ameta key as far as I know. kitty is not an X11 specific terminal emulator. If I understand you correctly, you want Meta to be treated the same as Alt in the legacy terminal key encoding scheme? In principle that's OK, but I would need to see the patch to be sure.

orki commented 2 years ago

Real modifier <LALT> set to Super_L and mapped to Mod4 Virtual modifier <ALT> also mapped to Mod4

I don't know what to mkae of this. If <LALT> is set to Super_L but <ALT> is also mapped to Super_L, is <SUPR> also mapped to Super_L? In this case, how do we distinguish between Super_L and Alt_L?

dbivolaru commented 2 years ago

@orki Yes, the <SUPR> virtual modifier (keycode 0xce) is set to Super_L in /usr/share/X11/xkb/symbols/pc by default as it should. TLDR; you don't distinguish between Alt and Super in this case.

Example setup

My example is something that anyone can use on a "normal" keyboard (ie that lacks an actual physical Meta key ie keycode 0x7f <LMTA> / 0x80 <RMTA>). I had to make it so that one still has Super and Alt otherwise you cannot navigate in the WM/GUI anymore (think Alt+Tab or Super+Tab). Ask me how I know.

Original discussion on mailing list & History

The one posted by Daniel Jacobowitz on the Debian mailing list uses completely separate Meta and Alt mappings but keeps Meta, Super and Hyper on his real Meta keys. These are not available on keyboards these days. This is how Solaris was setup back in the day, the real Meta key was both doing Meta and Super and was used in the terminal but also as WM/GUI (think Super) shortcut (Meta+C Meta+X Meta+V was copy/cut/paste - if you carefully check these are not bound on bash).

Due to the Mod4 conflation of Meta and Super, this is how the Meta key ended up as a Windows keycode on Sun USB keyboards when used on a PC.

Normally all these keys can and should work separately.

Hope it helps.

Explanation of Super + Alt behavior

In my example experimental setup with Alt and Super on the same key <LALT>, when you press <LALT>+e it is considered that both modifiers are active (ie should be interpreted as Super-Alt-e). The WM seems to still honor shortcuts based on one or the other.

Explanation of Super + Hyper behavior ("as is" 2022 on most mainstream Linux distros eg Fedora Core)

On a different note, in the default Linux setups these days Super and Hyper are both on the <LWIN> 0x85 / <RWIN> 0x86 keys (Mod4) as you might have noticed. So it's not that different than what I did with Alt and Super, but just many people don't use Hyper either. If you would setup Hyper bindings you can use the Windows keys for those out of the box and depending on the WM/App code path it will do either one or the other first in case of overlapping Super/Hyper bindings. But pressing the key will send both: mod4 Super_L (0x85), Super_R (0x86), Super_L (0xce), Hyper_L (0xcf).