Waybar
Waybar copied to clipboard
Keyboard-state module not detecting capslock status correctly
I'm using a moonlander. Waybar does not seem to be detecting the capslock state correctly. Starting waybar with my user as a member of the input group and the keyboard-state module enabled yields:
But, the capslock state in the bar behaves a bit weirdly:
- On bar start it's correct (shows the unlocked icon when capslock is off)
- When pressing capslock it responds correctly as well (shows the lock icon when capslock is on)
- But after that it no longer responds to capslock changes. So it keeps showing the lock icon, no matter if capslock is on or off (i.e. it no longer responds to the actual capslock state).
The following script (as a custom module, based on the suggestion here: https://github.com/swaywm/sway/issues/4512#issuecomment-526898845) does work correctly:
#!/bin/bash
capslock=$(cat /sys/class/leds/input17::capslock/brightness)
if [[ "${capslock}" == "1" ]]; then
echo ''
echo ''
echo "locked"
exit 0
fi
echo ''
echo ''
echo "unlocked"
This is the (truncated) output of swaymsg -t get_inputs:
[...]
Input device: ZSA Technology Labs Moonlander Mark I Keyboard
Type: Keyboard
Identifier: 12951:6505:ZSA_Technology_Labs_Moonlander_Mark_I_Keyboard
Product ID: 6505
Vendor ID: 12951
Active Keyboard Layout: English (US)
Libinput Send Events: enabled
Input device: ZSA Technology Labs Moonlander Mark I Consumer Control
Type: Mouse
Identifier: 12951:6505:ZSA_Technology_Labs_Moonlander_Mark_I_Consumer_Control
Product ID: 6505
Vendor ID: 12951
Libinput Send Events: enabled
Input device: ZSA Technology Labs Moonlander Mark I Consumer Control
Type: Keyboard
Identifier: 12951:6505:ZSA_Technology_Labs_Moonlander_Mark_I_Consumer_Control
Product ID: 6505
Vendor ID: 12951
Active Keyboard Layout: English (US)
Libinput Send Events: enabled
Input device: ZSA Technology Labs Moonlander Mark I System Control
Type: Keyboard
Identifier: 12951:6505:ZSA_Technology_Labs_Moonlander_Mark_I_System_Control
Product ID: 6505
Vendor ID: 12951
Active Keyboard Layout: English (US)
Libinput Send Events: enabled
Input device: ZSA Technology Labs Moonlander Mark I
Type: Keyboard
Identifier: 12951:6505:ZSA_Technology_Labs_Moonlander_Mark_I
Product ID: 6505
Vendor ID: 12951
Active Keyboard Layout: English (US)
Libinput Send Events: enabled
[...]
As you see the moonlander is in there multiple times. I wonder if waybar is just listening to the wrong device. And if so, can we specify in the config what device it should listen to? It doesn't seem like it from the docs.
Might be related to this: https://github.com/Alexays/Waybar/issues/2082, https://github.com/Alexays/Waybar/issues/2137
The keyboard-state module was invisible/broken until today, I just noticed that it isn't working correctly for me either; I detest the physical Caps Lock key because 99% of the time I hit it unintentionally, so I've remapped that key to be Left Control, and I toggle Caps Lock by pressing both Shift keys at the same time, using the Sway config input "type:keyboard" xkb_options "shift:both_capslock". The keyboard-state module does not respond when I toggle Caps Lock like this.
The keyboard-state module was invisible/broken until today, I just noticed that it isn't working correctly for me either; I detest the physical Caps Lock key because 99% of the time I hit it unintentionally, so I've remapped that key to be Left Control, and I toggle Caps Lock by pressing both Shift keys at the same time, using the Sway config
input "type:keyboard" xkb_options "shift:both_capslock". The keyboard-state module does not respond when I toggle Caps Lock like this.
Same here, if you change using both shifts it will not update, unless you tap caps lock. So I guess the update is hardcoded to the capslock key
Hi all, I'm the one who changed the keyboard-state module recently, if you have any questions, please ask me. In the last change, I introduced libinput for better interaction, but I didn't realize that it caused the bugs you encountered above.
First of all, I'm going to submit a patch to fix the problem that @krompus encountered.
And @ismay , can you provide me the result after running sudo libinput debug-events --show-keycodes with Caps Lock?
Hi @asas1asas200, yeah as long as it's not waybar specific I'd be happy to help (I'm no longer using waybar). This is the output:
-event2 DEVICE_ADDED Power Button seat0 default group1 cap:k
-event1 DEVICE_ADDED Power Button seat0 default group2 cap:k
-event0 DEVICE_ADDED Sleep Button seat0 default group3 cap:k
-event3 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I seat0 default group4 cap:k
-event4 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I System Control seat0 default group4 cap:k
-event5 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I Consumer Control seat0 default group4 cap:kp scroll-nat
-event6 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I Keyboard seat0 default group4 cap:k
-event7 DEVICE_ADDED Logitech MX Vertical seat0 default group5 cap:kp left scroll-nat scroll-button
-event9 DEVICE_ADDED Eee PC WMI hotkeys seat0 default group7 cap:k
-event3 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event3 KEYBOARD_KEY +0.125s KEY_CAPSLOCK (58) released
event3 KEYBOARD_KEY +1.225s KEY_CAPSLOCK (58) pressed
event3 KEYBOARD_KEY +1.337s KEY_CAPSLOCK (58) released
Hi @asas1asas200, yeah as long as it's not waybar specific I'd be happy to help (I'm no longer using waybar). This is the output:
-event2 DEVICE_ADDED Power Button seat0 default group1 cap:k -event1 DEVICE_ADDED Power Button seat0 default group2 cap:k -event0 DEVICE_ADDED Sleep Button seat0 default group3 cap:k -event3 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I seat0 default group4 cap:k -event4 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I System Control seat0 default group4 cap:k -event5 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I Consumer Control seat0 default group4 cap:kp scroll-nat -event6 DEVICE_ADDED ZSA Technology Labs Moonlander Mark I Keyboard seat0 default group4 cap:k -event7 DEVICE_ADDED Logitech MX Vertical seat0 default group5 cap:kp left scroll-nat scroll-button -event9 DEVICE_ADDED Eee PC WMI hotkeys seat0 default group7 cap:k -event3 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed event3 KEYBOARD_KEY +0.125s KEY_CAPSLOCK (58) released event3 KEYBOARD_KEY +1.225s KEY_CAPSLOCK (58) pressed event3 KEYBOARD_KEY +1.337s KEY_CAPSLOCK (58) released
@ismay The results from libinput don't seem to have any problems, I can't troubleshoot your problem at the moment, if you still want to try to fix it then contact me.
Sincerely,
@asas1asas200 Exactly same problem as OP describes. Vanilla waybar config, no keys being swapped. An update broke something.
I introduced libinput for better interaction
Maybe this is the issue, given that:
$ libinput
Command 'libinput' not found, but can be installed with:
sudo apt install libinput-tools
Using latest Ubuntu.
@Friptick Which WM does you use.
Most wayland compositors use libinput backend, such as wlroots and weston, but it is not required.
The libinput command in shell cannot indicate your compositor doesn't use libinput, the command is just a client tool of libinput.
OK thanks for the explanation @asas1asas200. Using sway. What should I try?
You can install libinput-tools or goto /usr/include/linux/input-event-codes.h to find event code. And build waybar from source or wait for the update then change the config to customize your num/caps/scroll lock trigger key.
wait for the update then change the config to customize your num/caps/scroll lock trigger key
To be clear, I don't want to customize the key, I'm using the caps lock key as normal, with normal waybar config. So it does seem to be a straight-up bug. Do you mean a fix is coming in the update?
What the result does your sudo libinput debug-events --show-keycodes show.
(Please install the tool and click caps lock)
$ sudo libinput debug-events --show-keycodes
-event4 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event4 KEYBOARD_KEY +0.168s KEY_CAPSLOCK (58) released
Using Wayfire, and this happens periodically. Restarting my session doesn't seem to fix it. It seems to stick at least until I reboot. Also using uwsm to launch my session.
> sudo libinput debug-events --show-keycodes
-event1 DEVICE_ADDED Power Button seat0 default group1 cap:k
-event0 DEVICE_ADDED Power Button seat0 default group2 cap:k
-event5 DEVICE_ADDED Apple Inc. Magic Keyboard with Numeric Keypad seat0 default group3 cap:k
-event8 DEVICE_ADDED Logitech MX Master 3 seat0 default group4 cap:kp left scroll-nat scroll-button
-event2 DEVICE_ADDED Blue Microphones Yeti Stereo Microphone Consumer Control seat0 default group5 cap:k
-event5 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event5 KEYBOARD_KEY +0.112s KEY_CAPSLOCK (58) released
@Alexays I think it's fair to reopen this. Several people have confirmed that this is an issue for them as well.
I am facing the same issue, but I am using https://github.com/k0kubun/xremap to remap certain keys. However, no function is assigned to the caps lock key.
Without xremap (it works):
-event6 KEYBOARD_KEY +8.881s KEY_CAPSLOCK (58) pressed
event6 KEYBOARD_KEY +8.934s KEY_CAPSLOCK (58) released
With xremap (doesn't):
event11 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event11 KEYBOARD_KEY +0.069s KEY_CAPSLOCK (58) released
Thanks @Alexays
I'm having a similar Issue, for me it's never updating the state, no matter what I do. libinput output:
-event1 DEVICE_ADDED Power Button seat0 default group1 cap:k
-event0 DEVICE_ADDED Power Button seat0 default group2 cap:k
-event4 DEVICE_ADDED Razer Razer Ornata V3 seat0 default group3 cap:k
-event14 DEVICE_ADDED Razer Razer Ornata V3 seat0 default group3 cap:kp scroll-nat
-event16 DEVICE_ADDED Razer Razer Ornata V3 seat0 default group3 cap:kp left scroll-nat scroll-button
-event7 DEVICE_ADDED Razer Razer Viper Ultimate Dongle seat0 default group4 cap:p left scroll-nat scroll-button
-event13 DEVICE_ADDED Razer Razer Viper Ultimate Dongle seat0 default group4 cap:kp scroll-nat
-event19 DEVICE_ADDED Razer Razer Viper Ultimate Dongle seat0 default group4 cap:k
-event4 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event4 KEYBOARD_KEY +0.067s KEY_CAPSLOCK (58) released
event4 KEYBOARD_KEY +0.179s KEY_CAPSLOCK (58) pressed
event4 KEYBOARD_KEY +0.242s KEY_CAPSLOCK (58) released
event4 KEYBOARD_KEY +1.306s KEY_NUMLOCK (69) pressed
event4 KEYBOARD_KEY +1.367s KEY_NUMLOCK (69) released
event4 KEYBOARD_KEY +1.495s KEY_NUMLOCK (69) pressed
event4 KEYBOARD_KEY +1.561s KEY_NUMLOCK (69) released
event4 KEYBOARD_KEY +1.931s KEY_SCROLLLOCK (70) pressed
event4 KEYBOARD_KEY +1.979s KEY_SCROLLLOCK (70) released
event4 KEYBOARD_KEY +2.086s KEY_SCROLLLOCK (70) pressed
event4 KEYBOARD_KEY +2.149s KEY_SCROLLLOCK (70) released
I guess following is what is happening (at least with me).
Working
- The trigger for the module is CAPS-LOCK.
- Waybar infers CAPS LOCK state by some equivalent of reading CAPS LOCK LED's state from
/sys/class/leds/(I guessed this from the behaviour: see below). - Now I have mapped CAPS-LOCK LED's state to secondary input language (Marathi in my case).
So,
Behaviour
-
When CAPS-LOCK is pressed with primay output (English), the module is triggerred, but said LED
OFFbecause I am still using English. -
When I switch to secondary input language (mapping: both shifts together), the LED turns
ON, but the module is NOT triggerred, since CAPS-LOCK was never pressed for switching to the secondary input language. -
When I switch to the secondary input language (using both shifts together), the LED turns
ON. Now, when I press the CAPS-LOCK, the module is correctly triggerred and the icon changes to LOCKED icon state. -
Reciprocally, when I switch back from secondary to English (hence, turn
OFFthe CAPS LOCK LED) and then hit CAPS-LOCK, the state icon state gets UNLOCKED.
Solution?
I guess a solution would be for waybar to infer CAPS LOCK's state from the system rather than inferring from LED STATE.
I found that under X11, one would achieve that by running xset q. I couldn't find an equivalent for wayland though.
Chiming in to say that I'm seeing this behavior as well. The module correctly detects the state of numlock/capslock when launching, but does not react to key further key activations.
Key press is indeed detected by the system:
sudo libinput debug-events --show-keycodes
-event1 DEVICE_ADDED Power Button seat0 default group1 cap:k
-event0 DEVICE_ADDED Power Button seat0 default group2 cap:k
-event15 DEVICE_ADDED BenQ ZOWIE BenQ ZOWIE Gaming Mouse seat0 default group3 cap:p left scroll-nat scroll-button
-event16 DEVICE_ADDED BenQ ZOWIE BenQ ZOWIE Gaming Mouse seat0 default group3 cap:k
-event17 DEVICE_ADDED ATEN ATEN 2/4-PORT 4K HDMI KVM SWITCH seat0 default group4 cap:k
-event18 DEVICE_ADDED ATEN ATEN 2/4-PORT 4K HDMI KVM SWITCH seat0 default group4 cap:p left scroll-nat scroll-button
-event19 DEVICE_ADDED ATEN ATEN 2/4-PORT 4K HDMI KVM SWITCH Keyboard seat0 default group4 cap:kp scroll-nat
-event20 DEVICE_ADDED ATEN ATEN 2/4-PORT 4K HDMI KVM SWITCH seat0 default group4 cap:p left scroll-nat calib
-event19 KEYBOARD_KEY +0.000s KEY_CAPSLOCK (58) pressed
event19 KEYBOARD_KEY +0.123s KEY_CAPSLOCK (58) released
This is the module configuration, showing the the correct device is expliticly listed under device-path:
"keyboard-state": {
"numlock": true,
"capslock": true,
"format": "{name} {icon}",
"format-icons": {
"locked": "",
"unlocked": ""
},
"device-path": "/dev/input/event19"
},
I am experiencing the same on FreeBSD 14.2 under Sway.
I have noticed that the module does update the state of the Lock keys but only after you press at least two different lock keys (e.g. caps lock, and num lock).
I will try to look into the source code of waybar-keyboard-state module. The breaking change must have been happened when the "interval" property has been deprecated in favour of event polling via libevdev.
I'm also having this problem. I couldn't find a solution so instead I put together this custom module.
config:
"custom/keyboard-state": {
"interval": 1,
"exec": "$HOME/.config/waybar/keyboard-state.py",
"return-type": "json",
"format": "{}",
"hide-empty-text": true
},
keyboard-state.py:
#!/usr/bin/python3
syscaps = open('/sys/class/leds/input4::capslock/brightness')
sysnum = open('/sys/class/leds/input4::numlock/brightness')
sysscroll = open('/sys/class/leds/input4::scrolllock/brightness')
capslock = bool(int(syscaps.read()))
numlock = bool(int(sysnum.read()))
scrolllock = bool(int(sysscroll.read()))
syscaps.close()
sysnum.close()
sysscroll.close()
text = ""
if capslock:
text += " C "
if numlock:
text += " N "
if scrolllock:
text += " S "
print(f'{{"text": "{text}"}}')
Thanks for sharing, @elidoz
Not gonna lie, personally I prefer to continue doing without capslock status than to have a Python script running at a 1 second interval.
Maybe this will serve as inspiration to the maintainers for a native fix.
I use Waybar with Hyprland and here's my current solution.
waybar config
"custom/capslock": {
"exec": "~/capslock.sh",
"format": "{}",
"interval": "once",
"return-type": "json",
"signal": 1
}
capslock.sh
#!/bin/bash
capslock=$(cat /sys/class/leds/input*::capslock/brightness | head -c 1)
if [[ "${capslock}" == "1" ]]; then
echo '{"class": "locked", "text": ""}'
else
echo '{"class": "unlocked", "text": ""}'
fi
hyprland.conf
bindirt = , Caps_Lock, exec, pkill -SIGRTMIN+1 waybar
style.css
#custom-capslock.locked {
background: rgba(0, 255, 0, 1);
}
On Mon Apr 21, 2025 at 4:54 AM PDT, elidoz wrote:
elidoz left a comment (Alexays/Waybar#2215)
I'm also having this problem. I couldn't find a solution so instead I put together this custom module.
config:
"custom/keyboard-state": { "interval": 1, "exec": "$HOME/.config/waybar/keyboard-state.py", "return-type": "json", "format": "{}", "hide-empty-text": true },keyboard-state.py:
#!/usr/bin/python3 syscaps = open('/sys/class/leds/input4::capslock/brightness') sysnum = open('/sys/class/leds/input4::numlock/brightness') sysscroll = open('/sys/class/leds/input4::scrolllock/brightness')
Still not much better than the built-in module, if it can't auto detect the input# device path to use, since they can change with each reboot or device hotplug.
capslock = bool(int(syscaps.read())) numlock = bool(int(sysnum.read())) scrolllock = bool(int(sysscroll.read()))
syscaps.close() sysnum.close() sysscroll.close()
text = "" if capslock: text += " C " if numlock: text += " N " if scrolllock: text += " S "
print(f'{{"text": "{text}"}}')
That is a pretty elegant fix @codestothestars and I can confirm it works!
For others: instead of the hyprland config, put the following in .config/sway/config:
bindsym --release Caps_Lock exec pkill -SIGRTMIN+1 waybar
Or another SIGRTMIN value as appropriate, just make sure it matches the one in the waybar config.
Thanks @codestothestars for sharing.
Update. Discovered a minor bug: using capslock with shift or control modifier, although nonsensical, does actually change the state. So best add this to config:
bindsym --release Shift+Caps_Lock exec pkill -SIGRTMIN+1 waybar
bindsym --release Control+Caps_Lock exec pkill -SIGRTMIN+1 waybar