Skip to content

Conversation

@mangas
Copy link

@mangas mangas commented Nov 9, 2025

The goal of this PR is adding support for remapping key combinations in a global way, avoiding the need for setting up other applications that normally require full access to a device or sudo.

Since all the processing already happens on sway, I only introduced a new configuration and we replace the keys for keyboards that belong to a group.

I'm quite new to the sway codebase so please let me know if there's a better way of achieving this or any modifications so that you'd be willing to accept the PR.

I have tested by starting a nested compositor and trying all the keybinds in either terminals or a text editor, from my testing everything seemed to be working.

@emersion
Copy link
Member

emersion commented Nov 9, 2025

@mangas
Copy link
Author

mangas commented Nov 9, 2025

How does this compare to custom XKB maps? https://github.com/swaywm/sway/wiki#load-a-modified-custom-xkb-keymap-xmodmap-equivalent

As I understand it xkb is designed to handle individual key mappings like changing specific keys in your keyboard layout. What this PR achieves would allow users to quite simply map certain keybinds that will work either globally or tailored for specific apps. One such case would be cmd+c for copy mapping to ctrl+c in most apps but then also allowing the mapping to be adjusted to ctrl+shift+c on the terminal, hence achieving a single keybind across multiple apps.

This is similar to what is supported by Hyprland, xremap and others.

@mangas mangas force-pushed the add-keybind-remap branch from ba566a3 to 6e983f6 Compare November 9, 2025 23:34
Copy link
Member

@kennylevinsen kennylevinsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I do see that this would be practical, I don't see a way to make a feature like this work well. The reason xkb does not support a way to remap key combos is because it is not reconcilable with an interface working on individual key events. Attempts to do so involve unstable hacks like sending storms of synthetic keyboard events to try to coerce a certain application xkb state and revert it afterwards.

A solution that is compatible with how keyboards work is using dedicated keysyms for various actions. For example, there's XF86Cut, XF86Copy and XF86Paste - normally used for dedicated cut/copy/paste multimedia keys - which can be arbitrarily assigned in your keyboard layout. There's also a large number of unused F keys available if you need spares. Given your examples, there are probably already keyboard events available for what you need/want.

Alternatively we'd be looking at a way to abstract "actions" from keyboard events in a separate protocol to give sway control, something similar to global hotkey protocol proposals.

Comment on lines +469 to +471
wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &new_mods);
wlr_seat_keyboard_notify_key(wlr_seat, time_msec, target_keycode, state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct. For an application to register, say, "ctrl+c" correctly, it needs to see something like:

  1. Left ctrl press
  2. Modifiers |= ctrl
  3. "C" press
  4. "C" release
  5. Left ctrl release
  6. Modifiers &= ~ctrl

This, however, is just faking the modifiers and key, which means:

  1. The keys held and the active modifiers are not consistent (say, left super pressed leading to ctrl modifier, no ctrl key held).
  2. The faked modifier and key sticks, so the following keypresses will be on a weird and inconsistent keyboard state, and e.g. the modifier may end up being immediately reset even though the remapped combo has not been released. Modifiers affect other things, such as drag-and-drop, so this is not great.

@mangas
Copy link
Author

mangas commented Nov 11, 2025

While I do see that this would be practical, I don't see a way to make a feature like this work well. The reason xkb does not support a way to remap key combos is because it is not reconcilable with an interface working on individual key events. Attempts to do so involve unstable hacks like sending storms of synthetic keyboard events to try to coerce a certain application xkb state and revert it afterwards.

A solution that is compatible with how keyboards work is using dedicated keysyms for various actions. For example, there's XF86Cut, XF86Copy and XF86Paste - normally used for dedicated cut/copy/paste multimedia keys - which can be arbitrarily assigned in your keyboard layout. There's also a large number of unused F keys available if you need spares. Given your examples, there are probably already keyboard events available for what you need/want.

Alternatively we'd be looking at a way to abstract "actions" from keyboard events in a separate protocol to give sway control, something similar to global hotkey protocol proposals.

Could you help me understand it can't work well?

Detection seems to work well enough right now, all I'm doing is transforming the keys being delivered to the surface when an "expected" key combination is detected. I made a small adjustment because beforehand I wasn't taking into consideration the already translated keys froms xkb so it doesn't add any complexity to the current detection of combinations and it does work well so far I've been running this version backported to v1.11 and so far the only issues were the key translations that I had missed.

I am, however, new to this project and wayland in general so I might be missing something here.

@kennylevinsen
Copy link
Member

kennylevinsen commented Nov 11, 2025

Could you help me understand it can't work well?

Sure. An application does not see you click "ctrl + alt + del", it sees a series of keypresses the gradually change the keyboard state until finally ctrl, alt and del are all held at the same time.

As a random example, imagine you try to map "ctrl + alt + del" to "super + shift + 5". To make this happen, a lot of keyboard events would need to be sent.

First, ctrl and alt get sent because the final part of the keycombo hasn't happened yet:

  • ctrl pressed
  • alt pressed

Then, "del" is pressed and whatever is doing the mapping must start to roll back the real button presses and apply the fake ones:

  • alt released
  • ctrl released
  • super pressed
  • shift pressed

Then the actual "del" press is sent, translated to "5"

  • "5" pressed
  • "5" released

Then we roll back to the real held buttons:

  • shift released
  • super relased
  • ctrl pressed
  • alt pressed

Finally, you let go of the remaining buttons:

  • alt released
  • ctrl released

Throughout this, keyboard state is really weird and inconsistent (what would happen if you pressed "ctrl + alt + del + 1"? would it become "super + shift + 5 + 1" or "ctrl + alt + del + 1"?), and the app sees it as if you are pressing and letting go of keys a lot. Some apps do things when you press and hold modifiers (like highlighting menus, changing cursors, affecting current drag-n-drop/select operation), or even use modifier keys as general keys (e.g. a game using "shift" as a regular button for running/jumping/scope aiming/whatever). Things probably get even hairier if we involve IMEs.

The above would be what something like xremap does. What your PR does is simpler because it "just" sends a fake modifier list before the fake symbol, but I don't think it's valid to have modifiers be completely disconnected from key events like that - at the very least it would be quite surprising for an application. It would be interesting to establish for sure whether that's allowed or not though, as I don't think anyone thought of it, but even if it is allowed it is not guaranteed to work for this usecase.

The main reason we have separate modifier event as opposed to having apps always listen to key events to deduce the modifiers is because we sometimes need to notify a client without keyboard focus of what the current modifiers are, for example during drag-and-drop operations.

On the other hand, if you instead of key combos use keysyms, such as XF86Cut, then you already have full arbitrary remapping capability through your keymap. The issue is that client-side keycombos basically sidestep the keymap to some extent.

@mangas
Copy link
Author

mangas commented Nov 11, 2025

is there an architectural difference between what we're discussing and what is done on xremap or hyprland?

If I understand what you are saying, you think this is the wrogn approach because it will send "fake" modifiers. If instead we were to just send an additional even, that would be ok? Effectively monitoring the stream of keys and when a trigger is detected just send an additional fake "key combination" event ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants