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
21.09k stars 882 forks source link

Option to apply keybinds after `kb_*` options #1881

Closed CobaltCause closed 7 months ago

CobaltCause commented 1 year ago

My desktop's keyboard has custom firmware for the workman layout, and all my Hyprland keybinds are designed as such. For example:

# Move focus
bind = $main, N, movefocus, l
bind = $main, E, movefocus, d
bind = $main, O, movefocus, u
bind = $main, I, movefocus, r

On my laptop, however, I'm not so lucky, and I have to set kb_variant = workman. Unfortunately this means that, with the same configuration shown above, I need to press the physical NEOI keys rather than the ones mapped by setting the kb_variant, which are all over the place instead of on the home row like I want.

vaxerski commented 1 year ago

there is no "after" kb_ options. Hyprland has to pick up the layout from somewhere, it doesn't pull it out of thin air.

image

ref: https://wiki.hyprland.org/Configuring/Uncommon-tips--tricks/#switchable-keyboard-layouts

pretty sure you can just

input {
    kb_layout = us,us
    kb_variant = ,workman
}

and then

exec-once = hyprctl switchxkblayout [kbname] next
CobaltCause commented 1 year ago

Ah okay, thanks. I tried it with an input section as you showed and that did work, so now I can press the physical U key and get the behavior I have bound to F for example.

The issue I ran into then is that this doesn't work for device-specific configurations. I have an input section that just changes some mouse settings, and then this:

# Laptop keyboard isn't workman at the firmware level
device:at-translated-set-2-keyboard {
    kb_variant = workman
}

I guess Hyprland doesn't look at this for keybinds. If this is intentional, I can work around it on my end.

vaxerski commented 1 year ago

Ah yeah sorry for my poor cognitive abilities atm it's 3am and I am about to hang myself after having to work with dbus, sd_bus and xdp's absolutely abhorrent docs.

hl picks up the global settings for the keymap, so you can of course set

input {
    kb_layout = us
    kb_variant = 
}

and use

device:somekeeb {
    kb_variant = workman
}

and keybinds will work as on qwerty

CobaltCause commented 1 year ago

Ah yeah sorry for my poor cognitive abilities atm it's 3am and I am about to hang myself after having to work with dbus, sd_bus and xdp's absolutely abhorrent docs.

lmao, understandable. I tried writing a wayland compositor for about two hours and now I'm here instead.


Uhhh, maybe I wasn't clear. The goal is to be able to press the same location on the keyboard, ignoring layouts, on both the laptop and the desktop, so I can reuse muscle memory across machines. I have this configuration:

bind = SUPER, F, fullscreen

input {
    # Mouse acceleration bad
    accel_profile = flat

    # Default is too high
    sensitivity = -0.225
}

device:at-translated-set-2-keyboard {
    kb_variant = workman
}

On the computer where the keyboard has workman firmware, this works great since there's no global kb_variant and the physical workman key F is also logical F. On the laptop though, this means I have to press the physical QWERTY key F (don't want), rather than physical U which is where logical workman F is (do want).

bind = SUPER, F, fullscreen

input {
    # Mouse acceleration bad
    accel_profile = flat

    # Default is too high
    sensitivity = -0.225

    # New!
    kb_layout = us
    kb_variant =
}

device:at-translated-set-2-keyboard {
    kb_variant = workman
}

This configuration appears to work exactly the same as the previous one.

CobaltCause commented 1 year ago

Here's a NixOS-based workaround that does what I want

vaxerski commented 1 year ago

well then swap them. workman in global, qwerty (empty) in per-device.

CobaltCause commented 1 year ago

Just tried that and it works on the laptop, but it makes the keybinds on the workman-firmware keyboard backwards instead. I think I'll have to stick with my NixOS trick.

Maybe Hyprland should be acting on keybinds per-device based on its kb_* settings instead of using the global one for everything? I obviously don't know Hyprland internals though.

vale981 commented 1 year ago

I have kind of a similar issue. My laptop's internal keyboard uses the workman variant in software and the external keyboard uses workman in hardware.

I can't use both of them at the same time to control hyprland with the correct bindings, which becomes pretty annoying when disconnecting the docking station.

Edit: I could hack around this by using udev, but that feels a little Byzantine...

Edit: I finally did work around it with udev, but it /is/ very byzanthine.

M1cha commented 1 year ago

Since I have the same issue: Would it be possible to make keybinds get evaluated after applying the keyboard layout of the device they were pressed on instead of the default layout? That would make bindings refer to logical/printed keys rather than their physical location. To me personally, that's more intuitive.

LiGoldragon commented 11 months ago

Is this being looked at? Does hyprland plan to support modern keyboard setups? Thank you :pray:

LiGoldragon commented 11 months ago

Assigning a "kb_variant" to anything but a keyboard is a type error.

Cu3PO42 commented 9 months ago

@vale981 would you mind sharing your workaround? I'm facing the same issue (albeit with two other layouts). I hope you're not rewriting the scancode-to-keycode translation table?

vale981 commented 9 months ago

@vale981 would you mind sharing your workaround? I'm facing the same issue (albeit with two other layouts). I hope you're not rewriting the scancode-to-keycode translation table?

It's an ugly hack, but I can slap a gist together later. Basically what happens is: I include a config file from a fixed path in my hyprland config. To this path I link the appropriate config for the current situation and force-reload hyprland. The symlinking and reloading is then hooked into udev, which detects the docking station being plugged in.

Cu3PO42 commented 9 months ago

I see! I was thinking of doing something similar, albeit controlled manually rather than using udev. I appreciate the offer, but there's no need to write up a Gist on my behalf. It's been a year or so since I wrote udev rules, but I'm confident I can hack that up.

blastrock commented 8 months ago

well then swap them. workman in global, qwerty (empty) in per-device.

I'm not sure this issue has been understood by the maintainers. I'll try to re-explain it differently.

Let's imagine two layouts set up like:

input {
    kb_layout = us
}

device:at-translated-set-2-keyboard {
    kb_layout = fr
}

So that all keyboards are qwerty, except the one on my laptop which will be azerty. If I bind something on Super+Q, it won't be bound to Super+Q, but to Super+the_top_left_letter_of_the_keyboard, regardless of the layout. So on my azerty layout, it will be bound to Super+A, which is not what we want. Btw, sway implements the correct behavior of binding Super+Q, whatever the layout is on each keyboard.

Cu3PO42 commented 7 months ago

@blastrock describes the exact behavior I (and I believe the other commenters in this thread) want. I'd like to expand on why I care about this:

I have defined modal mnemonic keybinds (a bit like LazyVim, LunarVim, NvChad, ...) for Hyprland. For example: to open a new terminal window, I press leader l t. I really want to always press l and t even if I use different keyboard layouts on different input devices. Right now, Hyprland requires workarounds to make that happen.

I understand that just changing the current behavior might be a breaking change you do not want, but implementing the new behavior via an additional flag on bind seems reasonable to me. If the maintainers are open to such a change, I might try and tackle it.

Cu3PO42 commented 7 months ago

This patch implements the behavior I believe we are all asking for. (At least it's the one I was asking for...) It changes the behavior unconditionally, so it's nothing that can be upstreamed, but if a config option can be agreed on, it shouldn't be difficult to implement.

Update: Got feedback from vaxry on Discord and will add a device property to control this behavior. PR soon-ish, hopefully.