Ubuntu – How to turn off Caps Lock (the lock, not the key) by command line

capslockcommand linexmodmap

For some reason my laptop is stuck in Caps Lock. I have the Caps Lock key mapped by xmodmap to hyper_l, so I don't have a caps_lock key to turn it off. Is there a way I can turn it off by command line? It would be nice if I could reset the lock state without resetting my computer, especially for future reference. This has happened before, but I would like to know now how to do it properly this time.

Best Answer

  • I don't know of any command line tool for that in Ubuntu. (For Num Lock, there is numlockx Install numlockx.) Here's a one-liner that you can copy-paste into a terminal window:

    python -c 'from ctypes import *; X11 = cdll.LoadLibrary("libX11.so.6"); display = X11.XOpenDisplay(None); X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2), c_uint(0)); X11.XCloseDisplay(display)'
    

    Here it is again in a more expanded form. We use the Python ctypes library to call C functions from the X library directly. The function XkbLockModifiers changes the state of the keyboard locks, on the core keyboard (XkbUseCoreKbd = 0x0100), affecting Caps Lock (2), setting it to 0 (off).

    #!/usr/bin/env python
    from ctypes import *
    X11 = cdll.LoadLibrary("libX11.so.6")
    display = X11.XOpenDisplay(None)
    X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2), c_uint(0))
    X11.XCloseDisplay(display)
    

    If you have a stuck modifier, change 2 to the mask of the modifiers you want to turn off. The modifiers are 1=Shift, 2=Lock (Caps Lock), 4=Control, 8=Mod1, 16=Mod2, 32=Mod3, 64=Mod4, 128=Mod5. Run xmodmap -pm to see what Mod1 through Mod5 correspond to. For example, to turn off all modifiers, call X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(255), c_uint(0)). To turn on Num Lock which is on Mod2 and at the same time turn off Caps Lock, call X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2 | 16), c_uint(16)).


    Here's a C version if you want to make a small binary instead of invoking Python. Compile with gcc -O -Wall -o caps_lock_off caps_lock_off.c -lX11, with the packages build-essentials and libx11-dev installed.

    #include <stdio.h>
    #include <X11/X.h>
    #include <X11/XKBlib.h>
    int main()
    {
        Display *display = XOpenDisplay(NULL);
        if (display == NULL) {
            fprintf(stderr, "Couldn't open display\n");
            return 2;
        }
        Bool sent = XkbLockModifiers(display, XkbUseCoreKbd, LockMask, 0);
        if (!sent) {
            fprintf(stderr, "Couldn't send LatchLockState\n");
            return 1;
        }
    #ifdef REPORT_STATE
        XkbStateRec xkb_state;
        Status status = XkbGetState(display, XkbUseCoreKbd, &xkb_state);
        if (status) {
            fprintf(stderr, "XkbGetState returned %d\n", status);
            return 1;
        }
        printf("state.group=%02x\n", xkb_state.group);
        printf("state.locked_group=%02x\n", xkb_state.locked_group);
        printf("state.base_group=%02x\n", xkb_state.base_group);
        printf("state.latched_group=%02x\n", xkb_state.latched_group);
        printf("state.mods=%02x\n", xkb_state.mods);
        printf("state.base_mods=%02x\n", xkb_state.base_mods);
        printf("state.latched_mods=%02x\n", xkb_state.latched_mods);
        printf("state.locked_mods=%02x\n", xkb_state.locked_mods);
        printf("state.compat_state=%02x\n", xkb_state.compat_state);
        printf("state.grab_mods=%02x\n", xkb_state.grab_mods);
        printf("state.compat_grab_mods=%02x\n", xkb_state.compat_grab_mods);
        printf("state.lookup_mods=%02x\n", xkb_state.lookup_mods);
        printf("state.compat_lookup_mods=%02x\n", xkb_state.compat_lookup_mods);
        printf("state.ptr_buttons=%02x\n", xkb_state.ptr_buttons);
    #endif
        int err = XCloseDisplay(display);
        if (err) {
            fprintf(stderr, "XCloseDisplay returned %d\n", err);
            return 1;
        }
        return 0;
    }
    

    Also possibly of interest is a way to temporarily ignore Caps Lock:

    xkbset nullify lock
    

    After this, Caps Lock will effectively be permanently off, until you reenable it with xkbset nullify -lock.