hyprwm / Hyprland

Hyprland is an independent, highly customizable, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
https://hyprland.org
BSD 3-Clause "New" or "Revised" License
20.93k stars 879 forks source link

Make left and right modifiers distinguishable #5517

Closed VladP812 closed 4 months ago

VladP812 commented 6 months ago

Description

Hi, hope you all doing great <3

First of all, want to thank every contributor for such a wonderful window manager, it looks amazing!

However, one thing I would like to be adjusted, is the way modifier keys are treated. For now, both left and right modifiers (such as Shift_L and Shift_R) are mapped to a single modifier. It is a big flaw for me, and, probably, for other people who want to map their main modifier specifically to right/left modifier, not both.

For example, I want my main modifier to be right shift as it is the most convenient choice for me. My left pinky is overloaded because of constantly pressing shift and control, and my right pinky is almost atrophied because of not pressing anything at all. So I want to make them equal. Emacs pinky is not a good thing! Joking of course, that's not the real reason :) There are many other applications I can see in having left and right modifiers distinguishable.

One of them is to have left shift acting as a modifier in only one case - when switching between layouts. Right shift can be used as the main modifier for the rest of key bindings.

All in all, treating left and right modifiers as a single virtual modifier seems to be quite unreasonable, if on keyboards they are different keys with different key codes, why shouldn't we let them be so in our input handling libraries?

Just do demonstrate this, lets compare how many key bindings is possible to map with Shift, Ctrl and Alt when they are combined into a single modifier, and having Shift_L, Shift_R and the rest of them separately. On my keyboard there is 45 keys including digit keys.

*I do not consider key bindings with multiple modifiers (such as Ctrl + Shift + a), for the sake of simplicity. Having only Alt, Shift and Ctrl gives us: (45 for alt, 45 for ctrl, 45 for shift) 45 + 45 + 45 = 135 Having them distinguishable gives us twice more, 270. And that's only in case of mapping single modifier to a key.

You must be thinking - who on earth would have so many keybindings? :) And I agree, not so many people would.

But my main point is that we should not reduce the functionality of our keyboards without explicit reasons for this. I've seen couple posts on Reddit addressing this issue. I am sure many people like me would find it useful to have left and right modifiers distinguishable.

vaxerski commented 6 months ago

not possible with XKB, AFAIK, but, I think with rules you can rebind one of the alts to like mod5... ish?

fortbis commented 5 months ago

I just ran into this problem. Having this feature would be really great, that way you can separate the bindings into multiple categories. Hopefully in the future, thanks!

The-Briel-Deal commented 5 months ago

This is something that has confused me for a bit, I've also been told that its not possible with XKB. But my confusion is that if I test inputs with xev, and press keys like left and right control/alt. The Keycode and Keysym are distinct. For example:

# Event on Left Alt Down.
KeyPress event, serial 28, synthetic NO, window 0x400001,
    root 0x401, subw 0x0, time 313137102, (702,350), root:(735,1421),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

# Event on Right Alt Down.
KeyPress event, serial 28, synthetic NO, window 0x400001,
    root 0x401, subw 0x0, time 313134945, (702,350), root:(735,1421),
    state 0x0, keycode 108 (keysym 0xffea, Alt_R), same_screen YES,
    XLookupString gives 0 bytes: 
    XmbLookupString gives 0 bytes: 
    XFilterEvent returns: False

So this left me a bit confused as XKB does distinguish between the left and right modifier keys. But when I looked into Hyprland source it did seem that there was only an ENUM of 8 (iirc) modifier keys that consumed these inputs and only stored a single alt/ctrl. I'm interested to look deeper into this as its been a minute but I feel like there should be a way as Hyprland can identify the difference in the mod keys.

I'm guessing that mod keys may be treated uniquely though? I'm not sure, it would be super nice though! I'll look a little deeper into this though and hopefully report back. I'm curious though if anyone knows what i'm missing here?

vaxerski commented 5 months ago

Yeah I forgot you get key events. You can do that with the events, yes.

The-Briel-Deal commented 5 months ago

I got a POC working pretty well over the last few days. It also lets you use up to 8 arbitrary keys combined. Feel free to try it out here. Will create a PR in a day or two after some cleanup and testing.

https://github.com/The-Briel-Deal/Hyprland/tree/multi-key-binds-v2

VladP812 commented 5 months ago

I got a POC working pretty well over the last few days. It also lets you use up to 8 arbitrary keys combined. Feel free to try it out here. Will create a PR in a day or two after some cleanup and testing.

https://github.com/The-Briel-Deal/Hyprland/tree/multi-key-binds-v2

I've looked at the your source and it did not seem to me that it's addressing the issue I described. Can you confirm that your version indeed can treat left and right modifier separately? For example can I create a bind with left shift only? So the bind only triggers on left shift + some char but not on right shift + some char.

I will compile and try it when I have some spare time. But I would be glad if you can answer it here directly.

The-Briel-Deal commented 5 months ago

Yea! To do what you want with how it is now, you'll use the following:

bind = CTRL, Control_R&K, exec, kitty
or just:
bind = ,Control_R&K, exec, kitty

(You can get the specific keynames like Control_R by using xev, you'll also be able to use keycodes but I'll document that along with the PR)

Also you can specify up to 8 specific simultaneous keybinds using the Keyname is XKB.

I would just wait until the PR is up later today though, I'm still actively working on it so things may break.

The-Briel-Deal commented 5 months ago

Explained more in the PR: https://github.com/hyprwm/Hyprland/pull/5966.

The-Briel-Deal commented 5 months ago

Hey @VladP812, its in a pretty workable state now in theory! It would be awesome if you could try it out and let me know if you would do anything different.

The last thing I'm working on is figuring out an intuitive way to consume keys. So currently if you press Ctrl_R, then K, and then S for a bind it will still pass K through because the keybind wasn't completed yet.

I think I'm just going to hold that intermediate event until its clear if the bind is completed or not, and then I'll use the nonConsume flag to bring it back to this behavior.

VladP812 commented 5 months ago

@The-Briel-Deal just tried to compile your repo, got the following error:

[109/172] Building CXX object CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o
FAILED: CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o
/usr/bin/c++ -DHAS_EXECINFO -DHyprland_EXPORTS -DUSES_SYSTEMD -DWLR_USE_UNSTABLE -I/home/inri/Downloads/Hyprland2/. -I/home/inri/Downloads/Hyprland2/src -I/home/inri/Downloads/Hyprland2/subprojects/wlroots-hyprland/include -I/home/inri/Downloads/Hyprland2/subprojects/wlroots-hyprland/build/include -I/home/inri/Downloads/Hyprland2/subprojects/udis86 -I/home/inri/Downloads/Hyprland2/protocols -I/home/inri/Downloads/Hyprland2/subprojects/udis86/libudis86 -isystem /usr/include/uuid -isystem /usr/include/pango-1.0 -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib/glib-2.0/include -isystem /usr/include/harfbuzz -isystem /usr/include/freetype2 -isystem /usr/include/pixman-1 -isystem /usr/include/libdrm -isystem /usr/include/libpng16 -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/sysprof-6 -isystem /usr/include/fribidi -O3 -DNDEBUG -std=gnu++23 -O3 -Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -pthread -Winvalid-pch -include /home/inri/Downloads/Hyprland2/build/CMakeFiles/Hyprland.dir/cmake_pch.hxx -MD -MT CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o -MF CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o.d -o CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o -c /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp
/home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp: In member function ‘void COutputHead::sendAllData()’:
/home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:169:64: **error: cannot convert ‘wl_resource*’ to ‘CZwlrOutputModeV1*’**
  169 |                 resource->sendCurrentMode(m->resource->resource());
      |                                           ~~~~~~~~~~~~~~~~~~~~~^~
      |                                                                |
      |                                                                wl_resource*
In file included from /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.hpp:7,
                 from /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:1:
/home/inri/Downloads/Hyprland2/protocols/wlr-output-management-unstable-v1.hpp:213:26: note:   initializing argument 1 of ‘void CZwlrOutputHeadV1::sendCurrentMode(CZwlrOutputModeV1*)’
  213 |     void sendCurrentMode(CZwlrOutputModeV1*);
      |                          ^~~~~~~~~~~~~~~~~~
/home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp: In member function ‘void COutputHead::updateMode()’:
/home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:200:64: error: cannot convert ‘wl_resource*’ to ‘CZwlrOutputModeV1*’
  200 |                 resource->sendCurrentMode(m->resource->resource());
      |                                           ~~~~~~~~~~~~~~~~~~~~~^~
      |                                                                |
      |                                                                wl_resource*
/home/inri/Downloads/Hyprland2/protocols/wlr-output-management-unstable-v1.hpp:213:26: note:   initializing argument 1 of ‘void CZwlrOutputHeadV1::sendCurrentMode(CZwlrOutputModeV1*)’
  213 |     void sendCurrentMode(CZwlrOutputModeV1*);
      |                          ^~~~~~~~~~~~~~~~~~

Main repository compiles with no errors, any ideas what causes / how to fix it?

The-Briel-Deal commented 5 months ago

Thats most likely because you don't have the latest AUR packages necessary. Also make sure you do git submodules sync and git submodules update. Take a look at the wiki installation page and make sure you install all the necessary AUR packages before building. (This looks like an issue with having an older version of wayland-protocols https://aur.archlinux.org/packages/wayland-protocols-git). Try running:

yay -Syu --devel
yay -S --devel wayland-protocols-git

From: VladP812 @.> Sent: Friday, May 10, 2024 4:49 AM To: hyprwm/Hyprland @.> Cc: Gabriel Ford @.>; Mention @.> Subject: Re: [hyprwm/Hyprland] Make left and right modifiers distinguishable (Issue #5517)

@The-Briel-Dealhttps://github.com/The-Briel-Deal just tried to compile your repo, got the following error:

[109/172] Building CXX object CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o FAILED: CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o /usr/bin/c++ -DHAS_EXECINFO -DHyprland_EXPORTS -DUSES_SYSTEMD -DWLR_USE_UNSTABLE -I/home/inri/Downloads/Hyprland2/. -I/home/inri/Downloads/Hyprland2/src -I/home/inri/Downloads/Hyprland2/subprojects/wlroots-hyprland/include -I/home/inri/Downloads/Hyprland2/subprojects/wlroots-hyprland/build/include -I/home/inri/Downloads/Hyprland2/subprojects/udis86 -I/home/inri/Downloads/Hyprland2/protocols -I/home/inri/Downloads/Hyprland2/subprojects/udis86/libudis86 -isystem /usr/include/uuid -isystem /usr/include/pango-1.0 -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib/glib-2.0/include -isystem /usr/include/harfbuzz -isystem /usr/include/freetype2 -isystem /usr/include/pixman-1 -isystem /usr/include/libdrm -isystem /usr/include/libpng16 -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/sysprof-6 -isystem /usr/include/fribidi -O3 -DNDEBUG -std=gnu++23 -O3 -Wall -Wextra -Wno-unused-parameter -Wno-unused-value -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith -pthread -Winvalid-pch -include /home/inri/Downloads/Hyprland2/build/CMakeFiles/Hyprland.dir/cmake_pch.hxx -MD -MT CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o -MF CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o.d -o CMakeFiles/Hyprland.dir/src/protocols/OutputManagement.cpp.o -c /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp: In member function ‘void COutputHead::sendAllData()’: /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:169:64: error: cannot convert ‘wl_resource’ to ‘CZwlrOutputModeV1 169 resource->sendCurrentMode(m->resource->resource()); ~~~~~^~
wl_resource*
In file included from /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.hpp:7, from /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:1: /home/inri/Downloads/Hyprland2/protocols/wlr-output-management-unstable-v1.hpp:213:26: note: initializing argument 1 of ‘void CZwlrOutputHeadV1::sendCurrentMode(CZwlrOutputModeV1*)’ 213 void sendCurrentMode(CZwlrOutputModeV1*); ^~~~~~ /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp: In member function ‘void COutputHead::updateMode()’: /home/inri/Downloads/Hyprland2/src/protocols/OutputManagement.cpp:200:64: error: cannot convert ‘wl_resource’ to ‘CZwlrOutputModeV1’ 200 resource->sendCurrentMode(m->resource->resource()); ~~~~~^~
wl_resource*

/home/inri/Downloads/Hyprland2/protocols/wlr-output-management-unstable-v1.hpp:213:26: note: initializing argument 1 of ‘void CZwlrOutputHeadV1::sendCurrentMode(CZwlrOutputModeV1)’ 213 | void sendCurrentMode(CZwlrOutputModeV1); | ^~~~~~

Main repository compiles with no errors, any ideas what causes this?

— Reply to this email directly, view it on GitHubhttps://github.com/hyprwm/Hyprland/issues/5517#issuecomment-2104211301, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AUWWCHCYWVUH45FMLO46V43ZBSC3DAVCNFSM6AAAAABF6PFJOWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBUGIYTCMZQGE. You are receiving this because you were mentioned.Message ID: @.***>

VladP812 commented 5 months ago

Thats most likely because you don't have the latest AUR packages necessary. Also make sure you do git submodules sync and git submodules update. Take a look at the wiki installation page and make sure you install all the necessary AUR packages before building. (This looks like an issue with having an older version of wayland-protocols https://aur.archlinux.org/packages/wayland-protocols-git). Try running: yay -Syu --devel yay -S --devel wayland-protocols-git

That was he first thing I did, but I updated from regular arch repository - it did not help. Then, following your suggestion I updated from user repository, but it did not help either. :(

The-Briel-Deal commented 5 months ago

Its alright, it should be merged soon enough. It needed some cleanup and testing for some edge cases before merging. Hopefully will have it in in the next few days if all goes well! Just doing some final checks.

The-Briel-Deal commented 4 months ago

Its merged btw, are we good to close this?