Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

keyboard layout agnostic shortcuts #606

Closed
maximbaz opened this issue Jun 6, 2018 · 34 comments
Closed

keyboard layout agnostic shortcuts #606

maximbaz opened this issue Jun 6, 2018 · 34 comments

Comments

@maximbaz
Copy link
Contributor

maximbaz commented Jun 6, 2018

I have two keyboard layouts, English and Russian. I noticed that when the active layout is Russian and I press Ctrl+C, sakura and xterm cancel the currently running command, but kitty does not. Same for Ctrl+D, sakura and xterm exit terminal, but kitty does not.

This is because kitty recognized the cyrillic letters being pressed and ignores such weird commands.

# Ctrl+C in English layout
scancode: 0x25 release: 0 clean_sym: Control_L composed_sym: Control_L mods: numlock glfw_key: LEFT CONTROL
scancode: 0x36 release: 0 clean_sym: c composed_sym: c mods: ctrl+numlock glfw_key: C
scancode: 0x36 release: 1 clean_sym: c mods: ctrl+numlock glfw_key: C
scancode: 0x25 release: 1 clean_sym: Control_L mods: ctrl+numlock glfw_key: LEFT CONTROL

# Ctrl+C in Russian layout
scancode: 0x25 release: 0 clean_sym: Control_L composed_sym: Control_L mods: numlock glfw_key: LEFT CONTROL
scancode: 0x36 release: 0 clean_sym: Cyrillic_es composed_sym: Cyrillic_es mods: ctrl+numlock glfw_key: UNKNOWN
scancode: 0x36 release: 1 clean_sym: Cyrillic_es mods: ctrl+numlock glfw_key: UNKNOWN
scancode: 0x25 release: 1 clean_sym: Control_L mods: ctrl+numlock glfw_key: LEFT CONTROL

It would be much much more pleasant if kitty would be layout agnostic and bind itself to the scancodes instead of ascii letters. In fact, my i3 has all shortcuts configured by scancodes so that the desired action consistently happens regardless of the currently active keyboard layout.

Ctrl+Shift+C is another common annoyance, when Russian layout is active, kitty doesn't copy the selection.

I'm thinking now, ideally kitty would ignore active layout and think that I have english layout when Ctrl is pressed, so that for example even Ctrl+/ is treated exactly as Ctrl+/ regardless of active layout (in Russian keyboard that physical key represents .). This doesn't happen today in sakura or xterm.

@kovidgoyal
Copy link
Owner

And doing that would make it impossible to use compose keys to enter non-english text. Which would make lots of other people unhappy, see #171

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 6, 2018

I read the thread, but didn't fully understand why it would prevent using compose keys, could you explain a bit more?

I have something like that working on my laptop, I press AltGr+o, / to make a Danish letter ø, is that what compose key is and why this would break?

@kovidgoyal
Copy link
Owner

Because compose keys in general work by using some modifier to change the action of normal keys or by re-assigning normal keys to mean something else. There is no way for a key event consuming application to know which is which. Either an application uses the compose and layout rules to figure out which key the user meant to press, or it does not. It cannot do so selectively on an ad hoc basis.

Your russian keyboard layout is mapping the c key to some cyrillic character. if you dont like that, the proper solution is to modify the russian layout, not add workarounds or it to every application you use.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 6, 2018

The layout maps all keys to cyrillic characters as Russian uses cyrillic alphabet instead of Latin one, that's the whole point of having the second layout in the first place 😀

Problem is, currently kitty terminal cannot be controlled if you only have Russian layout, you have to install English layout just to get the Latin letter "C" so that kitty can start recognizing Ctrl+C and Ctrl+Shift+C. Other terminals manage to understand these key presses regardless of active layout (and by the way, I am able to type AltGr+o, / to get Danish ø in sakura terminal).

Regardless, this pain extends beyond kitty, I didn't have high hopes for this issue to be solved. Thanks for explanations though 😉

@kovidgoyal
Copy link
Owner

kovidgoyal commented Jun 6, 2018

In that case what you need to do is add rules to the layout to map Ctrl+C to Ctrl+C and not ctrl+<cyrillic character>. Indeed, while it has been a long time since I looked at xkb layouts, I am fairly sure you can easily create rules to map Ctrl+<any key> to ctrl+<any key>

That should fix it in all applications that respect keyboard layouts.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 6, 2018

Interesting, I will have a look, thanks for the idea!

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 8, 2018

This was a very neat idea, but unfortunately I couldn't find how to do this. There is a keymap table where you can define what a given key should do depending on the currently hold modifier keys, but Ctrl is not in that list. All I saw about Ctrl is people reassigning it to a different key, but that doesn't help us here.

If someone finds a solution, please share.

@kovidgoyal
Copy link
Owner

Did you look at XCompose?

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 8, 2018

Not yet, just started looking 👍

But look what I found in meantime with xev, this is curious!

English layout, press "d", xev sees it as "d" (expected):

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 287760, (-807,-100), root:(1140,0),
    state 0x10, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (64) "d"
    XmbLookupString gives 1 bytes: (64) "d"
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 287884, (-807,-100), root:(1140,0),
    state 0x10, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (64) "d"
    XFilterEvent returns: False

Russian layout, press "d", xev sees it as cyrillic "в" (expected):

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 507942, (-490,157), root:(1457,257),
    state 0x2010, keycode 40 (keysym 0x6d7, Cyrillic_ve), same_screen YES,
    XLookupString gives 2 bytes: (d0 b2) "в"
    XmbLookupString gives 2 bytes: (d0 b2) "в"
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 508090, (-490,157), root:(1457,257),
    state 0x2010, keycode 40 (keysym 0x6d7, Cyrillic_ve), same_screen YES,
    XLookupString gives 2 bytes: (d0 b2) "в"
    XFilterEvent returns: False

English layout, press "Ctrl+d", xev sees it as "Ctrl+d" (expected):

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 309258, (-1349,-37), root:(598,63),
    state 0x10, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 310271, (-1349,-37), root:(598,63),
    state 0x14, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (04) ""
    XmbLookupString gives 1 bytes: (04) ""
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 310441, (-1349,-37), root:(598,63),
    state 0x14, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (04) ""
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 310973, (-1349,-37), root:(598,63),
    state 0x14, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

Russian layout, press "Ctrl+d", xev sees it as latin "Ctrl+d":

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 538564, (-342,490), root:(1605,590),
    state 0x2010, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

KeyPress event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 540366, (-342,490), root:(1605,590),
    state 0x2014, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (04) ""
    XmbLookupString gives 1 bytes: (04) ""
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 540546, (-342,490), root:(1605,590),
    state 0x2014, keycode 40 (keysym 0x64, d), same_screen YES,
    XLookupString gives 1 bytes: (04) ""
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x2c00001,
    root 0x1cf, subw 0x0, time 540946, (-342,490), root:(1605,590),
    state 0x2014, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XFilterEvent returns: False

I'm tempted to say kitty should do the same since xev does this out of the box, what do you think?

@kovidgoyal
Copy link
Owner

Take it up with the maintainers of libxkbcommon. It isn't kitty that decides what keys to report, it is libxkbcommon. See the glfw_xkb_handle_key_event function. IIRC xev doesn't use libxkbcommon it uses xlib. Most modern software uses libxkbcommon since it works with both X and wayland.

@maximbaz
Copy link
Contributor Author

maximbaz commented Jun 10, 2018

Another application-level idea: can we make kitty accept bindings for cyrillic letters? For example:

map ctrl+shift+м paste_from_clipboard

Or if it has to be a keysym reported by GLFW_DEBUG_KEYBOARD=1 kitty, then:

map ctrl+shift+cyrillic_em paste_from_clipboard

At the minimum, I'd like to be able to add 4 bindings so that these work when Russian is the active layout: Ctrl+C, Ctrl+D, Ctrl+Shift+C, Ctrl+Shift+V.

@kovidgoyal
Copy link
Owner

It has to be keys known to glfw, since the kitty layer sees only glfw key codes. And glfw does not have codes for keys beyond the basic ascii keys. But, thinking about it, one way to do this is that, if the key is unknown to glfw in the current layout, then use the key name from a fallback keyboard layout that can be configured via a config option in kitty.

That should be robust against changes in kernel/graphics stack and that way the user can configure exactly what layout to use a fallback for keys that do not match. The only question is, how to get xkb to load such a layout. Currently it loads the layout from the X server or wayland compsitor. I think this API is what we need https://xkbcommon.org/doc/current/group__keymap.html#ga502717aa7148fd17d4970896f1e9e06f

@kovidgoyal
Copy link
Owner

And, I dont think this even needs a kitty config option, since it is controlled via an environment variable already, see https://xkbcommon.org/doc/current/structxkb__rule__names.html

@kovidgoyal
Copy link
Owner

Note that I have not tested the fix, I leave that to you.

@maximbaz
Copy link
Contributor Author

Wooohooo, it works, thank you so much!!! 🎉 No more annoyances when I copy something with Ctrl+Shift+C only to realize later that I didn't copy anything because my layout was Russian.

Ctrl+C, Ctrl+D, Ctrl+Shift+C, Ctrl+Shift+V, all work now in Russian layout — and by the way I didn't have to configure absolutely anything, not even environment variables, I think it figures out the fallback on its own because I have both layouts configured.

metayan pushed a commit to metayan/kitty that referenced this issue Jun 11, 2018
…map shortcuts using the ascii equivalents, from the default layout.

Fixes kovidgoyal#606
@tertium
Copy link

tertium commented Feb 17, 2020

This issue should probably be reopened now, since the fix implemented in 4711746 no longer works: Cyrillic characters were added to xkb_glfw.c in e619eb9 and thus are not unknown to GLFW anymore.

Maybe I don't understand the full picture here, but I cannot imagine a use case for a keybinding attached to a Cyrillic letter — a user would have to switch layouts to access that keybinding, making it rather impractical. On the other hand, the effect of the change in e619eb9 is that now I have to manually add mappings to kitty.conf for each Cyrillic letter and each combination of modifiers in order to have layout-independent keybindings — and I do want <Ctrl-C> and <Ctrl-D> and <Ctrl-Z>, and the line-editing stuff, and the Kitty copy-paste shortcuts, etc. to work independently on what layout I'm currently in.

(Strictly speaking, 4711746 does not provide fully layout-agnostic keybindings for Cyrillic layouts, since some punctuation characters, "known" to GLFW, are moved to different positions. But it is probably as good as a keysym-based solution can be.)

@kovidgoyal
Copy link
Owner

kovidgoyal commented Feb 17, 2020

I dont really see what can be done here. shortcuts needed to be mapped to letters after the keyboard layout is done. Otherwise you cannot use for example a dvorak layout, or any layout that remaps keys. If pressing ctrl+c on your keyboard generates keycodes for ctrl+(something else) after layout mapping, then you have to bind to that (something else) in kitty.conf.

The only real solution would be to have an smap command that maps to values in the default/no layout case. In order to do that, the entire keyboard handling stack in glfw (both xkb and cocoa) and kitty would need to be re-written to pass two keycodes to kitty, the code after layout mapping and the code before layout mapping. And there was an effort underway to do that by @bew see #2000

I suggest you contribute to that effort if you want to move this forward.

@Luflosi
Copy link
Contributor

Luflosi commented Feb 17, 2020

According to https://sw.kovidgoyal.net/kitty/conf.html#keyboard-shortcuts, one should be able to use raw system key codes but when I tested it, I couldn't get it to work.

@kovidgoyal
Copy link
Owner

raw system codes only apply if the key is unknown to glfw which cyrillic
keys no longer are.

@Luflosi
Copy link
Contributor

Luflosi commented Feb 17, 2020

Ok. I think that should be mentioned in the docs.

@tertium
Copy link

tertium commented Feb 17, 2020

@Luflosi Independently of the big effort in #2000, I am not sure what is the benefit of having Cyrillic characters in xkb_glfw.c in e619eb9. Why should they be known to GLFW?

@ctrlcctrlv
Copy link
Contributor

The discussion in the PR, #1928, seems to suggest that this was not accepted by the upstream GLFW project, and is a Kitty innovation, so I share @tertium's skepticism. However, I haven't read the entire thread in #1928, so there might be good reasons for it.

@Luflosi
Copy link
Contributor

Luflosi commented Feb 17, 2020

@tertium It all started when I wanted to be able to bind any key on my German keyboard in kitty. On German keyboards, there are additional characters not found on the English layout like äöüß and basically all of the non-alphanumeric characters are in different places. Since many other non-English keyboard layouts were also not fully supported, I just added them too while I was at it. The addition of Cyrillic characters might be debatable in terms of its usefulness but I saw no reason not to add them. Feel free to remove them again in your fork if they bother you. I am even willing to provide you with a patch if you find it too difficult to do yourself. But the correct way to achieve what you want is not to remove the keys from GLFW but to do what is described in #2000.

@ctrlcctrlv Yes, keyboard handling is very different in kitty's version of GLFW compared to the original GLFW because the original keyboard handling was insufficient for kitty, see for example glfw/glfw#1140.

@tertium
Copy link

tertium commented Feb 17, 2020

To make myself clear, I do see the point of adding the characters like ä or é which are part of the primary layout in national keyboards. So a user of a German or Swedish keyboard may indeed want to assign a keybinding to Ctrl-ä, and for that, GLFW must know the symbol.

However, I don't think it makes sense for alternate alphabets like Cyrillic, since these are usually delegated to a separate ISO group: pretty much every Russian-speaking user would have us,ru as their XKB layout. In this case, I think it is better to keep the cyrillic characters unknown, so that the fix for #606 could work.

Edit: @Luflosi I posted my comment before seeing yours. Removing the cyrillic symbols from xkb_glfw.c is exactly what I did, so right now I am a happy camper :) Thank you for offering a patch.

@Luflosi
Copy link
Contributor

Luflosi commented Feb 17, 2020

In #606 (comment), @maximbaz asked for keyboard bindings with Cryllic letters, so there seems to be at least some use case for supporting them.

@tertium
Copy link

tertium commented Feb 17, 2020

In #606 (comment), @maximbaz asked for keyboard bindings with Cryllic letters, so there seems to be at least some use case for supporting them.

Well, he asked for this because the standard shortcuts (Ctrl-C, Ctrl-D, copy-paste) didn't work for him out of the box, and so he looked for a workaround. But it is a very inconvenient workaround, since you would have to add a lot of such bindings to make everything work. Instead, 4711746 fixed his original problem without requiring him to do anything at all — until e619eb9, which invalidated the fix.

(Not trying to start an argument, nor waste your time. My problem is solved, so now I just want to explain my reasoning. I do understand your position, too.)

@kovidgoyal
Copy link
Owner

Personally, I have no opinion on the appropriateness of adding cyrillic
keys or not. I am interested in solving this and all the keyboard issues
properly by having GLFW pass all relevant information to kitty so it can
decide for itself. That will mean layout-ed key in the current layout
and in the default layout. Clean key shifted key, etc etc.

In the meantime I suggest simply adding the mappings for the shortcuts
you need to kitty.conf or patching out the cyrillic keys.

@Galicarnax
Copy link

Galicarnax commented May 21, 2020

Rather surprising to see an advanced terminal emulator (graphics protocol, hinting, remote control, etc) has issues with such a basic thing as keyboard layouts :) Ok, I can add additional shortcuts to kitty.conf with Russian letters for kitty-specific actions. Do I understand it right that there is currently no way to deal with shell keybindings (like Ctrl-C, Ctrl-D, Ctrl-Z) in kitty with Russian layout? (without digging into the code, to be sure).

@kovidgoyal
Copy link
Owner

No, you understand wrong. See send_text.

@Galicarnax
Copy link

Works, thanks.

@akaWolf
Copy link

akaWolf commented Jul 12, 2021

so how can I use now kitty hotkeys in non-us layout without a long list of each in config?

@Felixoid
Copy link

@kovidgoyal hey, AFAIS, this ticket is about hotkeys sent to the terminal itself. But what about the kitty hotkeys?

Here I try to open the new tab. It works in EN layout, but failed in RU:

kitty --config NONE --debug-input
Loading new XKB keymaps
Modifier indices alt: 0x3 super: 0x6 hyper: 0xffffffff meta: 0xffffffff numlock: 0x4 shift: 0x0 capslock: 0x1
Move mouse_button: -1 mods: none grabbed: 0
Press xkb_keycode: 0x25 clean_sym: Control_L composed_sym: Control_L mods: numlock glfw_key: 57442 (LEFT_CONTROL) xkb_key: 65507 (Control_L)
on_key_input: glfw key: 0xe062 native_code: 0xffe3 action: PRESS mods: numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event
Press xkb_keycode: 0x32 clean_sym: Shift_L composed_sym: Shift_L mods: ctrl+numlock glfw_key: 57441 (LEFT_SHIFT) xkb_key: 65505 (Shift_L)
on_key_input: glfw key: 0xe061 native_code: 0xffe1 action: PRESS mods: ctrl+numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event
Press xkb_keycode: 0x1c clean_sym: Cyrillic_ie composed_sym: Cyrillic_IE mods: ctrl+shift+numlock glfw_key: 1077 (е) xkb_key: 1733 (Cyrillic_ie) shifted_key: 1045 (Е) alternate_key: 116 (t)
on_key_input: glfw key: 0x435 native_code: 0x6c5 action: PRESS mods: ctrl+shift+numlock text: '' state: 0 sent key to child
Release xkb_keycode: 0x1c clean_sym: Cyrillic_ie mods: ctrl+shift+numlock glfw_key: 1077 (е) xkb_key: 1733 (Cyrillic_ie) shifted_key: 1045 (Е) alternate_key: 116 (t)
on_key_input: glfw key: 0x435 native_code: 0x6c5 action: RELEASE mods: ctrl+shift+numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event
Release xkb_keycode: 0x32 clean_sym: Shift_L mods: ctrl+shift+numlock glfw_key: 57441 (LEFT_SHIFT) xkb_key: 65505 (Shift_L)
on_key_input: glfw key: 0xe061 native_code: 0xffe1 action: RELEASE mods: ctrl+shift+numlock text: '' state: 0 ignoring as keyboard mode does not support encoding this event
Press xkb_keycode: 0x28 clean_sym: Cyrillic_ve composed_sym: Cyrillic_ve mods: ctrl+numlock glfw_key: 1074 (в) xkb_key: 1751 (Cyrillic_ve) alternate_key: 100 (d)
on_key_input: glfw key: 0x432 native_code: 0x6d7 action: PRESS mods: ctrl+numlock text: '' state: 0 sent key to child

^d works for EOL, as you can see.

wez added a commit to wez/wezterm that referenced this issue Apr 19, 2023
For eg: RU layout, CTRL-S shouldn't result in ы in the context
of a terminal.

The approach taken here is similar to kitty; when the key combination
doesn't produce a definitive composed output, and when any of
ctrl/alt/super are present, we treat the keypress as though it were
the same as the one from the system default keymap.

The result is that ctrl-c now works like ctrl-c and alt-b and alt-f work
like their latin counterparts.

Hopefully there are no downsides to this!

refs: #2845
refs: kovidgoyal/kitty#606
@Jakeroid
Copy link

Jakeroid commented Jun 22, 2023

I have same issues with all Cyrillic layouts (Ukrainian, Bulgarian, etc). Looks like if you have active layout with non-Latin characters you can't use shortcuts.

Probably the solution is adding additional mapping for each your non-Latin keyboard layout.

@Jakeroid
Copy link

I created the script to automate the process, check the last part of the article here: https://jakeroid.com/blog/kitty-shortcuts-work-only-with-latin-characters-how-to-fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants