Keyboard LEDs with KMS/DRM backend

I’m using the KMSDRM backend of SDL2 for a Linux console application.Most of the things work as expected but the Keyboard LEDs (NumLock, CapsLock, SrollLock) don’t.

So I looked at the souce code in SDL_evdev_kbd.c and found an ioctl() with KDGKBLED to read the keyboard LED states, but I couldn’t find anything which sets the LED state. Therefore I naively tried adding another ioctl() whenever the “ledflagstate” is changed:

diff -r c70cf178aacb src/core/linux/SDL_evdev_kbd.c
--- a/src/core/linux/SDL_evdev_kbd.c    Sun Dec 10 09:17:33 2017 -0800
+++ b/src/core/linux/SDL_evdev_kbd.c    Mon Dec 11 11:54:45 2017 +0100
@@ -350,17 +350,19 @@
 
 static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
 {
-    return ((kbd->ledflagstate >> flag) & 1);
+    return (kbd->ledflagstate & flag) != 0;
 }
 
 static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
 {
-    kbd->ledflagstate |= 1 <ledflagstate |= flag;
+    ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
 }
 
 static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
 {
-    kbd->ledflagstate &= ~(1 <ledflagstate &= ~flag;
+    ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
 }
 
 static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
@@ -375,7 +377,8 @@
 
 static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
 {
-    kbd->ledflagstate ^= 1 <ledflagstate ^= flag;
+    ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
 }

Note, that I also changed replaced “1<<flag” with “flag”. I think the left shift is not necessary because the LED flag values are powers of two already.

With this change I got the NumLock LED working, but CapsLock still doesn’t.

What am I missing here?

-Rainer

Since this post got no reply yet, I assume that other people don’t experience a problem with the Numlock LED using the KMS/DRM backend, or this is not that important to them.

If you are using SDL2 with KMS/DRM, can you please hit NumLock and post a “Works for me” if your keyboard LED flashes up?

No, you are correct. The current code never calls ioctl with KDSETLED.

I think KDSETLED expects LED_SCR,LED_NUM, and LED_CAP instead of K_SCROLLLOCK, K_NUMLOCK, and K_CAPSLOCK, but they seem to have the same values anyway.

I can get caps lock and num lock working when I put the ioctl call in chg_vc_kbd_led. I get no scroll lock events for some reason and I don’t think the other functions interacting with that state variable get called right now, but I’m not very familiar with this SDL code or evdev.

static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
    unsigned long ioflags = 0;
    kbd->ledflagstate ^= 1 << flag;

    if (vc_kbd_led(kbd, K_SCROLLLOCK))
        ioflags |= LED_SCR;
    if (vc_kbd_led(kbd, K_NUMLOCK))
        ioflags |= LED_NUM;
    if (vc_kbd_led(kbd, K_CAPSLOCK))
        ioflags |= LED_CAP;

    ioctl(kbd->console_fd, KDSETLED, ioflags);
}

However, this code gets the LEDs stuck when exiting SDL. Annoying state stuff that has to be reset, I guess. (Edit: Oh, a value above 7 to KDSETLED resets the LEDs. That has to be done on shutdown.)

Since this has the LED state saving already in it, it probably was meant to be improved at some point.