sway
sway copied to clipboard
sway-input: add button_mapping option
libinput(4) has this option which is missing in sway-input
:
Option "ButtonMapping" "string" Sets the logical button mapping for this device, see XSetPointerMapping(3). The string must be a space-separated list of button mappings in the order of the logical buttons on the device, starting with button 1. The default mapping is "1 2 3 ... 32". A mapping of 0 deactivates the button. Multiple buttons can have the same mapping. Invalid mapping strings are discarded and the default mapping is used for all buttons. Buttons not specified in the user's mapping use the default mapping. See section BUTTON MAPPING for more details.
My usecase: my mouse has swapped side buttons for <Back>
and <Forward>
(buttons 8 and 9) so I need to change the mapping.
The ButtonMapping
option is specific to the libinput X.Org driver and is not available via the libinput library. Additionally, Wayland does not use the logical button numbers and uses the raw event codes instead. Sway does provide compatibility mappings for buttons 1-9 in the config for anything that takes a button though for convenience.
The following could be added to your config, which should accomplish the swap without requiring any code changes:
set $MOUSE <id-of-mouse>
bindsym --input-device=$MOUSE --whole-window button8 seat - cursor press button9, seat - cursor release button9
bindsym --input-device=$MOUSE --whole-window button9 seat - cursor press button8, seat - cursor release button8
I'm not sure that I like the idea of implementing a button_mapping
compatible command in Sway though
Thanks, it works as expected. If button_mapping
won't get implemented, I suggest to at least mention the solution in the man page or other documentation.
Actually, the following would probably be better. I think the first version will still results in the surface getting a release event for the wrong button (which it will never get a pressed event for - related to #3063)
bindsym --input-device=$MOUSE --whole-window button8 seat - cursor press button9
bindsym --input-device=$MOUSE --whole-window --release button8 seat - cursor release button9
bindsym --input-device=$MOUSE --whole-window button9 seat - cursor press button8
bindsym --input-device=$MOUSE --whole-window --release button9 seat - cursor release button8
In the same vein as this, is it possible to have Sway revoke or abandon a bindsym? Would that be considered a valid enhancement?
Use case: if I don't bind button8 or button9 at all in the config, applications like nemo correctly process them as "back" and "forward" buttons. If I do create a binding in the config (or with swaymsg 'bindsym bindsym --whole-window button8 exec virsh send-key Arch KEY_LEFTALT KEY_LEFT
bindsym --whole-window button9 exec virsh send-key Arch KEY_LEFTALT KEY_RIGHT
It works exactly as it should- pressing button8 and button9 executes the respective virsh command and virsh sends the keys to my VM. Of course now nemo isn't going to see button8 or button9 since Sway is executing the virsh commands. I can't seem to get button8 and button9 to unmap- I can bindsym them to a different command, but they will not be recognized by nemo again unless I exit sway and start again (again with no bindsym commands for button8 or button9 in the config). xev doesn't even register them being pushed, though libinput events does.
I tried playing with seat - cursor like:
swaymsg 'bindsym --input-device=blahblah --whole-window button8 seat -cursor press button8
...etc
but that doesn't seem to set it back to how it would be if I hadn't bindsym'd button8 or button9 at all.
EDIT- Actually, reading this, Im not sure this is exactly button mapping. If this needs to be made a new issue with the enhancement label, let me know...
Actually, reading this, Im not sure this is exactly button mapping. If this needs to be made a new issue with the enhancement label, let me know.
That is indeed a separate issue. Can you please make a new issue for it?
@RedSoxFan Thanks for posting your workaround. However, it only works for buttons 1-9 (sway complains about config errors if I put button10
), and my mouse manufacturer decided to use button 10 for what should be 8. Is it somehow possible to remap button 10 to button 8?
@msrd0 To use any button, the following steps should work:
- Run
sudo libinput debug-events
- Press the button that you want to create the mapping for
- Locate the button name (it should start with
BTN_
) in the output - Use that button name in the
bindsym
Thanks, that works. I believe this should be documented somewhere.
set $MOUSE <id-of-mouse>
bindsym --input-device=$MOUSE --whole-window BTN_RIGHT seat - cursor press BTN_LEFT, seat - cursor release BTN_LEFT
bindsym --input-device=$MOUSE --whole-window BTN_LEFT seat - cursor press BTN_RIGHT, seat - cursor release BTN_RIGHT
I tried this to revers left/right button of mouse, but then dragging over text with right click (left-mouse-button) does not select
For dragging to work, reference my comment above with the press and release split https://github.com/swaywm/sway/issues/3960#issuecomment-475907290
Also, if you just want to swap left/right, you should be able to just use input $MOUSE left_handed enabled
.
I couldn't get full drag-remapping to work. As far as I can tell the mouse button remappings are applied in seatop_default.c/handle_button
which seems only to trigger on press events. The release event is handled by seatop_down.c/handle_button
. There isn't any mapping logic in this file. This makes it impossible to remap a mouse button release event.
There is a branch in the former function for button release events but I think it might be dead code. At least I only ever saw the function being called with state == WLR_BUTTON_PRESSED
.
In the end I went down to evdev
and remapped the buttons with an hwdb
file.
Hello, @RedSoxFan.
Actually, the following would probably be better. I think the first version will still results in the surface getting a release event for the wrong button (which it will never get a pressed event for - related to #3063)
bindsym --input-device=$MOUSE --whole-window button8 seat - cursor press button9 bindsym --input-device=$MOUSE --whole-window --release button8 seat - cursor release button9 bindsym --input-device=$MOUSE --whole-window button9 seat - cursor press button8 bindsym --input-device=$MOUSE --whole-window --release button9 seat - cursor release button8
The release event is not being generated for some reason, and the "--input-device" flag doesn't work when I use the identifier that I get from swaymsg -t get_inputs
(using type:touchpad
doesn't seem to work either).
Hello, I have a problem related to this, my "Logitec Performance MX" mouse got a button "zoom" who is button13 on x11. However it's currently not mapped to any libinput-event.
> sudo libinput debug-events
event21 POINTER_BUTTON +190.866s ??? (280) pressed, seat count: 1
The ??? indicate that the code 280 is not mapped to any BTN_xxx event. Do I have a way to map it ?
I guess that having a special name in bindsym to use the code directly can be useful, like "BTN_X280" (to directly use code 280) ? That do you think ?
The first suggestion was working well for me so far:
set $MOUSE <id-of-mouse>
bindsym --input-device=$MOUSE --whole-window button8 seat - cursor press button9, seat - cursor release button9
bindsym --input-device=$MOUSE --whole-window button9 seat - cursor press button8, seat - cursor release button8
The only problem is that if I enable the native Wayland support in Chromium with --enable-features=UseOzonePlatform --ozone-platform=wayland
, then the buttons are somewhat "half mixed-up" in Chromium. For example, pressing the <Back>
button works as expected, but releasing it behaves as if I pressed <Forward>
. So I tried the other suggestion, but it does not work at all with the Ozone platform (the buttons are not swapped):
bindsym --input-device=$MOUSE --whole-window button8 seat - cursor press button9
bindsym --input-device=$MOUSE --whole-window --release button8 seat - cursor release button9
bindsym --input-device=$MOUSE --whole-window button9 seat - cursor press button8
bindsym --input-device=$MOUSE --whole-window --release button9 seat - cursor release button8
On the other hand, both suggestions work well in other applications and even if I disable the Ozone platform in Chromium, so it may be actually unrelated to Sway...
How would I swap the axes for scrolling (so veritical scroll scrolls horizontally and horizontal scroll scrolls vertically)?
I think this issue should be renamed to sway-input: handle --release
mouse mappings correctly and be marked as a bug as uncovered here, not an enhancment. The original issue was given a solid solution already possible (if the release events got remapped).
Also, @ragusa87, I think you should be able to use bindcode
for mapping unnamed keys - the only issue is that release still cannot be rebound and it doesn't work with --input-device=
(also a bug mentioned in this issue).
The last time I tried to get this to work (I think about a year ago), I ran into issues, because the binding wouldn't match if a modifier key was held.
So for example, while
bindsym --whole-window {
button4 seat - cursor press button6
button5 seat - cursor press button7
button6 seat - cursor press button4
button7 seat - cursor press button5
}
would sort of work to swap the axes of my scroll wheels. But if held a modifier like control or alt or shift while scrolling, then it wouldn't use the binding. I could of course create bindings for every possible combination of modifiers, but that is a pretty ugly solution.
The seat cursor press
command is now deprecated. Which means the proposed workarounds are now deprecated.
It might be possible to adjust to using a separate executable to use the virtual pointer protocol to send the key event with an exec
action. But that has a number of disadvantages:
- It will add the latency of spawning a child process for every key press.
- It will be more difficult for sway to later solve the problem of modifiers I mentioned in my last comment, with something like hyprland's "i" flag to ignore modifiers), because the modifier state would need to be preserved between sway receiving the press event and the separate program sending a button press.
- It means that in order to remap mouse buttons, you have to install a separate application.
It's possible to remap buttons using udev, and this will be picked up by libinput. I have, in /etc/udev/hwdb.d/70-remap-mouse.hwdb
:
evdev:name:Logitech USB Laser Mouse:*
ID_INPUT_KEY=1
KEYBOARD_KEY_90003=btn_extra
KEYBOARD_KEY_90004=btn_middle
KEYBOARD_KEY_90005=btn_side
evdev:name:HP Wireless Optical Mobile Mouse:*
ID_INPUT_KEY=1
KEYBOARD_KEY_90003=btn_side
KEYBOARD_KEY_90004=btn_middle
However, this is system-wide; it would still be useful to do this in sway's own configuration.
https://wiki.archlinux.org/title/Map_scancodes_to_keycodes is not the reference I got this from, but it's at least close.