Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linux-scrolllock-keep-on

Small Linux daemon that keeps the Scroll Lock LED of every keyboard lit at all times — even when you press CapsLock or NumLock.

Tested on Fedora 44 Workstation (GNOME / Wayland), but works on any distro with systemd and a modern Linux kernel.


The problem

In graphical sessions (especially Wayland + gnome-shell), every time the Caps/Num Lock state changes the compositor re-pushes the state of all three LEDs (num, caps, scroll) to the keyboard via libinput. Since Scroll Lock is normally off, the LED is turned off too.

Common workarounds don't help:

  • xset led named "Scroll Lock" — X11 only.
  • brightnessctl --device='inputXX::scrolllock' set 1 — turns it on, but the next CapsLock press turns it back off.
  • xmodmap -e 'add mod3 = Scroll_Lock' — X11 only, no effect on Wayland.
  • Changing /sys/class/leds/.../trigger to none — doesn't help, because the override comes from libinput via EV_LED, not from the kernel trigger.

The solution

A daemon that:

  1. Finds every input device that exposes an inputXX::scrolllock LED in /sys/class/leds/.
  2. Opens the matching /dev/input/eventXX read-write.
  3. Injects an EV_LED scrolllock=1 event on startup.
  4. Listens for events. If it sees an EV_LED scrolllock=0 (libinput/gnome-shell turning it off), it re-injects =1 immediately.
  5. Re-scans every 3 seconds to catch USB keyboards plugged in after boot.

The reaction is event-driven and sub-millisecond — visually the LED doesn't blink.

Install

sudo ./install.sh

This copies:

  • scrolllock-keep-on.py/usr/local/bin/
  • scrolllock-keep-on.service/etc/systemd/system/

And runs systemctl enable --now, so the service comes up on boot.

Uninstall

sudo ./uninstall.sh

Diagnostics

Service status:

systemctl status scrolllock-keep-on.service
journalctl -u scrolllock-keep-on.service -f

Inspect the raw LED state:

for f in /sys/class/leds/input*::scrolllock; do
    echo -n "$f: "; cat "$f/brightness"
done

List which keyboards the daemon is watching:

journalctl -u scrolllock-keep-on.service | grep watching

Dependencies

Python 3 stdlib only. No evdev, pyudev, pyinotify, etc. — all calls to /dev/uinput and /dev/input/event* use raw os.read/os.write with struct.

Why not just a udev rule?

Tried. Setting ATTR{trigger}="none" and ATTR{brightness}="1" via a udev rule works for the initial state, but gnome-shell overrides it via EV_LED on the first CapsLock press. Something reactive listening on the event stream is required.

Files

File What it is
scrolllock-keep-on.py The daemon
scrolllock-keep-on.service systemd unit
install.sh Installer (needs root)
uninstall.sh Remover (needs root)

linux-scrolllock-keep-on (PT-BR)

Pequeno daemon Linux que mantém os LEDs de Scroll Lock de todos os teclados acesos o tempo todo, mesmo quando você aperta CapsLock ou NumLock.

Testado em Fedora 44 Workstation (GNOME / Wayland), mas funciona em qualquer distro com systemd e kernel Linux moderno.

O problema

Em sessões gráficas (especialmente Wayland + gnome-shell), toda vez que o estado de Caps/Num Lock muda, o compositor re-empurra o estado dos três LEDs (num, caps, scroll) para o teclado via libinput. Como o Scroll Lock normalmente está "desligado", o LED apaga.

Soluções comuns não resolvem:

  • xset led named "Scroll Lock" — só funciona em X11.
  • brightnessctl --device='inputXX::scrolllock' set 1 — acende, mas o próximo CapsLock apaga de novo.
  • xmodmap -e 'add mod3 = Scroll_Lock' — X11 only, não tem efeito em Wayland.
  • Mudar /sys/class/leds/.../trigger para none — não resolve, porque o caminho de override vem do libinput via EV_LED, não do trigger do kernel.

A solução

Um daemon que:

  1. Localiza todo input device que tem um LED inputXX::scrolllock em /sys/class/leds/.
  2. Abre o /dev/input/eventXX correspondente em modo leitura/escrita.
  3. Injeta um evento EV_LED scrolllock=1 ao iniciar.
  4. Fica escutando eventos. Se vê um EV_LED scrolllock=0 (libinput/gnome-shell apagando), reinjeta =1 imediatamente.
  5. Re-escaneia a cada 3 segundos pra pegar teclados USB plugados depois do boot.

A reação é event-driven e sub-milissegundo — visualmente o LED não pisca.

Instalação

sudo ./install.sh

Isso copia:

  • scrolllock-keep-on.py/usr/local/bin/
  • scrolllock-keep-on.service/etc/systemd/system/

E faz systemctl enable --now, então o serviço sobe sozinho no boot.

Desinstalação

sudo ./uninstall.sh

Diagnóstico

Status do serviço:

systemctl status scrolllock-keep-on.service
journalctl -u scrolllock-keep-on.service -f

Inspecionar o estado bruto dos LEDs:

for f in /sys/class/leds/input*::scrolllock; do
    echo -n "$f: "; cat "$f/brightness"
done

Listar os teclados que o daemon está vigiando:

journalctl -u scrolllock-keep-on.service | grep watching

Dependências

Só Python 3 da stdlib. Nada de evdev, pyudev, pyinotify etc. — todas as chamadas para /dev/uinput e /dev/input/event* usam os.read/os.write direto com struct.

Por que não um udev rule só?

Tentado. Setar ATTR{trigger}="none" e ATTR{brightness}="1" via udev rule funciona pro estado inicial, mas o gnome-shell sobrescreve via EV_LED no primeiro CapsLock. Precisa de algo reativo escutando o stream de eventos.

Arquivos

Arquivo O que é
scrolllock-keep-on.py O daemon
scrolllock-keep-on.service Unit do systemd
install.sh Instalador (precisa de root)
uninstall.sh Removedor (precisa de root)

About

Keep keyboard scroll-lock LEDs lit at all times.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages