10

I am trying to force the capslock led on. xset does not work for me, so I am trying to use setleds.

In a graphical console, this command returns:

> LANG=C setleds -L +caps
KDGKBLED: Inappropriate ioctl for device
Error reading current flags setting. Maybe you are not on the console?

In a virtual terminal, it works, however the effect is local to that virtual terminal. From what I understand, running

> setleds -L +caps < /dev/tty1

from a virtual terminal (my X server is sitting on tty1) should work. However, this requires root access.

Is there a way to send a command to the console underlying a X server, be it from the said xserver or from another VT, without root?

Edit: From a suggestion from Mark Plotnik, and based on code found here, I wrote and compiled the following:

#include <X11/Xlib.h>
#include <X11/XKBlib.h>

#define SCROLLLOCK 1
#define CAPSLOCK 2
#define NUMLOCK 16

void setLeds(int leds) {
   Display *dpy = XOpenDisplay(0);
   XKeyboardControl values;
   values.led_mode = leds & SCROLLLOCK ? LedModeOn : LedModeOff;
   values.led = 3;
   XChangeKeyboardControl(dpy, KBLedMode, &values);
   XkbLockModifiers(dpy, XkbUseCoreKbd, CAPSLOCK | NUMLOCK,
                    leds & (CAPSLOCK | NUMLOCK) );
   XFlush(dpy);
   XCloseDisplay(dpy);
}

int main() {
   setLeds(CAPSLOCK);
   return 0;
}

From what Gilles wrote about xset, I did not expect it to work, but it does... in some sense: it sets the led, but it also sets the capslock status. I do not fully understand all the code above, so I may have done a silly mistake. Apparently, the line XChangeKeyboardControl... does not change the behavior of the program, and XkbLockModifiers is what sets the led and the capslock status.

T. Verron
  • 265
  • You can do something like xdotool key Caps_Lock from an authorized X client, although this will actually turn on caps lock. – Mark Plotnick Jan 15 '15 at 18:53
  • @MarkPlotnick The point is indeed not to turn CapsLock on. Is there a way to turn CapsLock off, without touching the led? – T. Verron Jan 15 '15 at 19:06
  • I looked at the xterm source, and it uses a call to XChangeKeyboardControl() to set or unset the LEDs without affecting the state of caps lock etc. So if you can compile C code, that's one approach. – Mark Plotnick Jan 15 '15 at 20:43
  • @MarkPlotnick Does xterm affect the leds? It sounds like a good idea, I will edit the question with my results. – T. Verron Jan 16 '15 at 08:58
  • I got xterm to light up ScrollLock LED by sending the escape sequence ESC [ 3 q , as per the file ctlseqs.txt that comes with the source, but couldn't get the Num or CapsLock LEDs to light up with parameters 1 and 2. Maybe I need to do the XKB configuration mentioned in the answer. xterm calls XChangeKeyboardControl in xtermShowLED and xtermClearLEDs, but doesn't call XkbLockModifiers anywhere at all. – Mark Plotnick Jan 16 '15 at 15:48

3 Answers3

9

In principle, you should be able to do it with the venerable xset command.

xset led named 'Caps Lock'

or xset led 4 to set LED number 4, if your system doesn't recognize the LEDs by name.

However, this doesn't seem to work reliably. On my machine, I can only set Scroll Lock this way, and I'm not the only one. This seems to be a matter of XKB configuration.

The following user-level work-around should work (for the most part):

  1. Extract your current xkb configuration:

    xkbcomp $DISPLAY myconf.xkb
    
  2. Edit the file myconf.xkb, replacing !allowExplicit with allowExplicit in the relevant blocks:

    indicator "Caps Lock" {
        allowExplicit;
        whichModState= locked;
        modifiers= Lock;
    };
    indicator "Num Lock" {
        allowExplicit;
        whichModState= locked;
        modifiers= NumLock;
    };
    
  3. Load the new file

    xkbcomp myconf.xkb $DISPLAY
    

Now setting the leds on and off with xset should work. According to the bug report, you will not be able to switch the leds off when they are supposed to be on (for example if CapsLock is enabled).

  • Thanks! I had tried xset before, and indeed it does not work. I had not seen this bug report though. Anyway, "Status: Resolved Wontfix" is not really encouraging... The allowExplicit work-around would probably work for me (I don't need to turn the led off), but changing it still requires root. – T. Verron Jan 16 '15 at 09:16
  • @T.Verron You don't need to be root to change the XKB configuration. You can call xkbcomp at any time. I'm not familiar enough with XKB to tell you exactly what you need to change (setting a specific aspect rather than a full predefined map with XKB is a bit of a pain), but http://unix.stackexchange.com/questions/166844/mapping-key-bindings/166913#166913 should have a few pointers. – Gilles 'SO- stop being evil' Jan 16 '15 at 09:30
  • Oh, good point. Well, as a first attempt, I tried: xkbcomp $DISPLAY output.xkb, then replacing !allowExplicit by allowExplicit in the indicator "Caps Lock" section, then reloading the file with xkbcomp output.xkb. There is a lot of warnings, and xset doesn't work any better afterwards. I will read some more about xkb. – T. Verron Jan 16 '15 at 12:49
  • 1
    This kind of worked for me. After I imported the modified file I got some error messages and I could light the LEDs but other things got messed up, plus it did not survive a restart. So I went ahead an edited /usr/share/X11/xkb/compat/ledcaps and .../lednum and this made it permanent. – jtgd Jun 26 '18 at 00:47
2

Using sed

$ sudo sed -i 's|\!allowExplicit|allowExplicit|g' /usr/share/X11/xkb/compat/ledcaps

After logging out and in again, the Caps Lock LED can now be controlled without any root privileges using the commands:

$ xset led named 'Caps Lock'
$ xset -led named 'Caps Lock'
  • But this requires root. – T. Verron Nov 04 '18 at 20:07
  • @T.Verron Only once to change a configuration file with sudo and then never again. To gain an understanding why this might be so important to certain users, see this vim application. – Serge Stroobandt Nov 04 '18 at 21:31
  • Being the one who asked the question 3 years ago, I definitely understand why it can be important to some users (in my case, it was to work around the stupid delay apple keyboards have when activating capslock, after remapping capslock to control). But back then, I specifically needed a solution without any root access at all, because it was for a work computer. The accepted answer involves a few more steps, but it does work without sudo. – T. Verron Nov 05 '18 at 06:38
  • @T.Verron I understand. Shared systems are another case where this would not work. Notwithstanding, I liked the straightforwardness of the last commenter on the accepted answer and made a sed one-liner out of it. – Serge Stroobandt Nov 05 '18 at 11:00
0

A combination of the root-less approach by @Gilles with the idea of full automation by @Serge_Stroobandt.

To enable control of the Caps Lock, Num Lock and Shift Lock LEDs:

#!/bin/bash
# Enables to control keyboard LEDs that are not available for control by default
xkbcomp $DISPLAY /tmp/my_conf.xkb
cat /tmp/my_conf.xkb | awk -e '
    BEGIN {
        change = 0
    }

    {
        if (change == 1) {
            if ($1 == "!allowExplicit;") {
                gsub("!", "", $0)
            }
            change = 0
        }
        print $0

    }

    /indicator "Caps Lock"/ {
        change = 1
    }
    /indicator "Num Lock"/ {
        change = 1
    }
    /indicator "Shift Lock"/ {
        change = 1
    }
    ' > /tmp/my_conf_modified.xkb
xkbcomp /tmp/my_conf_modified.xkb $DISPLAY

To turn a LED on and off:

# Turns the LED on
xset led named 'Caps Lock'

# wait 1s
sleep 1

# Resets the LED to the actual state,
# so it might still be on, if Caps Lock is activated.
xset -led named 'Caps Lock'
hoijui
  • 731