How do I turn off Caps Lock (the lock, not the key) by command line?

57,163

Solution 1

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.

Solution 2

Using Xorg automation

Xorg automation tools could be used for sending the required key events.

Note:

For first use, This solution needs you to tape the correct password to install new tool, if your CAPS is currently active:

  • Use SHIFT key to type lowercase letters.
  • Enable accessibility, overlay virtual keyboard.
  • Re-plug an external keyboard. (Thanks to chris455)
  • Open office writer, write password there, change the letter case, copy it, then paste it to password dialog.

If all previous options are not possible or don't work, Go with Gilles' answer / python script. It does not need to install any additional tool, it uses only python & libX11 shared lib which are pre-installed.

Using xdotool

  1. Install it

    sudo apt-get install xdotool
    
  2. Send a CAPS down/up event

    xdotool key Caps_Lock
    

Another tool is xte

  1. Install it

    sudo apt-get install xautomation
    
  2. Send a CAPS lock down/up event

    xte "key Caps_Lock"
    

References:

Solution 3

As for Gilles' Python version not working in newer Ubuntus, setting the correct return for the open display seems to do the trick:

#!/usr/bin/env python

from ctypes import *

class Display(Structure):
    """ opaque struct """

X11 = cdll.LoadLibrary("libX11.so.6")
X11.XOpenDisplay.restype = POINTER(Display)

display = X11.XOpenDisplay(c_int(0))
X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2), c_uint(0))
X11.XCloseDisplay(display)

(Code adapted from https://stackoverflow.com/questions/29638210/how-can-i-use-python-xlib-to-generate-a-single-keypress)

Solution 4

If you can't access CAPS because you remapped it in .bashrc, like I did, then simply switching to a virtual terminal (alt+ctl+fN) and then switching back worked for me.

Solution 5

I had this problem and was able to fix it by using the OnBoard keyboard (in Ubuntu Mate, under Universal Access).

Once turned on you should see the CapsLock key is red, or somehow indicated that it is locked on. Then you can press to toggle off.

Share:
57,163

Related videos on Youtube

Echogene
Author by

Echogene

Updated on September 18, 2022

Comments

  • Echogene
    Echogene almost 2 years

    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.

    • One Zero
      One Zero over 12 years
      [echo -e "$(dumpkeys | grep ^keymaps)\nkeycode 58 = Escape" | sudo loadkeys][1] [Adding the following line to .profile or .bash_profile should disable caps lock:][2] [xmodmap -e "remove lock = Caps_Lock"][3] [1]: askubuntu.com/questions/43986/… [2]: askubuntu.com/questions/43986/… [3]: askubuntu.com/questions/43986/…
    • Pavlos Theodorou
      Pavlos Theodorou over 7 years
      setxkbmap -option caps:none
    • user.dz
      user.dz over 7 years
      @PavlosTheodorou, that will disable CAPS key, it will not toggle its status as the OP requirement.
    • Pavlos Theodorou
      Pavlos Theodorou over 7 years
      there is a bug there. there is no command currently to do that. you could use setleds +caps or -caps but its not working. the only thing u can do is already answered. you can remap caps
  • Echogene
    Echogene over 12 years
    I'll have a go when I'm next on my laptop. I'm on my desktop for now.
  • quant_dev
    quant_dev about 9 years
    What if this doesn't work?
  • user.dz
    user.dz almost 9 years
    @quant_dev, I've added another tool xte could you give it a try.
  • Gringo Suave
    Gringo Suave over 8 years
    CAN'T INSTALL, PASSWORD NOT ACCEPTED. :(
  • user.dz
    user.dz over 8 years
    @GringoSuave, open Office writer, write password there, change the letter case, copy it, then paste it to password dialog. Have you tried Gilles's answer, i think it does not need to install any additional tool.
  • Gringo Suave
    Gringo Suave over 7 years
    Hmm, the python method used to work for me, but after upgrading to Yakkety it does not. The bug where caps lock gets stuck persists of course!
  • h3.
    h3. over 7 years
    @GringoSuave I have no idea why that could be. Please install xtrace and run xtrace python -c 'from ctypes import *; X11 = cdll.LoadLibrary("libX11.so.6"); buf = (c_char*16)(); display = X11.XOpenDisplay(None); X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2), c_uint(0)); X11.XkbGetState(display, 0x0100, buf); X11.XCloseDisplay(display)' and post the last few lines, starting with the one containing QueryExtension name='XKEYBOARD'. I don't claim that I'll understand the output but I'll try.
  • Gringo Suave
    Gringo Suave over 7 years
    I get a segfault: terminated by signal SIGSEGV (Address boundary error) Segmentation fault…
  • Gringo Suave
    Gringo Suave over 7 years
    000:<:0005: 20: Request(98): QueryExtension name='XKEYBOARD' 000:>:0005:32: Reply to QueryExtension: present=true(0x01) major-opcode=135 first-event=85 first-error=137 000:<:0006: 8: XKEYBOARD-Request(135,0): UseExtension major=1 minor=0 000:>:0006:32: Reply to UseExtension: major=1 minor=0
  • h3.
    h3. over 7 years
    @GringoSuave Does it work (as in, get to the end of the program) without xtrace? Add ; from binascii import *; print hexlify(buf.raw) at the end of the program to display the state. If this still crashes, what if you change c_char*16 to c_char*100?
  • h3.
    h3. over 7 years
    @GringoSuave And please try the C version as well, compiled with gcc -O -Wall -DREPORT_STATE -o caps_lock_off caps_lock_off.c -lX11 as well as without -DREPORT_STATE
  • Gringo Suave
    Gringo Suave over 7 years
    It runs fine however the problem happens rarely so not easy to check. I use the caps lock key as ctrl.
  • user.dz
    user.dz over 7 years
    @Gilles, Still your python script is the best, That C program have same drawback like my answer. It requires dependency installation and password entry. However, python solution is copy/paste/run solution quick and easy. I want to give my already collected rep in this post for that to your answer. :) I can't stop going back to your answer to see how you implemented it, it is really a nice snip to learn from.
  • Mark K Cowan
    Mark K Cowan over 7 years
    +1 for xkbset nullify lock, that worked (after installing from AUR) where the Python script just segfaulted. Now added to X startup script.
  • Daniel H
    Daniel H almost 7 years
    I kept getting a return of 1 from the libx11 stuff, but the very last part about xkbset worked perfectly.
  • labyrinth
    labyrinth over 6 years
    Switching didn't quite do it, but it did get me to a point where I could press caps lock to get thing right.
  • chris544
    chris544 over 6 years
    You can use Shift keys for inputting lowercase letters while Caps Lock is enabled.
  • chris544
    chris544 over 6 years
    If you use an external keyboard another option could be re-plugging it; Caps Lock modifier might get reset, so you can input lowercase letters.
  • Håken Lid
    Håken Lid almost 6 years
    I tried running the python script, but this line gives me a segfault: >>> X11.XkbLockModifiers(display, c_uint(0x0100), c_uint(2), c_uint(0)) Error: Segmentation fault (core dumped). Any idea what's wrong?
  • h3.
    h3. almost 6 years
    @HåkenLid The Python script calls low-level code directly in a way that requires very little code, but the downside is that there's nothing to validate that it's calling the code correctly. However the low-level interfaces that this script uses are pretty much set in stone. What version of Ubuntu are you using? On what processor architecture? Do other GUI applications start — can you run e.g. xterm? This proof-of-concept script does crash if it can't connect to the X server. Add print display under the line display = …, what does it print?
  • Caleb
    Caleb almost 6 years
    The python version used to work for me too but stopped doing so a while back on all my Archlinux machines. Connecting to the X server is not the issue. The C version here compiled and works.
  • gtrak
    gtrak about 5 years
    I had a segfault on python (2) but it worked on python3
  • Garret Gang
    Garret Gang about 5 years
    This works really well, is a life saviour
  • Seth Robertson
    Seth Robertson almost 5 years
    The python code used to work but now does not. See the @diegogs answer below for one that still does. xset nullify lock fixed the problem on some applications (emacs) but not others (terminator). It does not work either before or after. xdotool works.
  • Alfe
    Alfe over 4 years
    I also got the SegFault using Python2, and it also worked for me using Python3, so my immediate problem is solved. Nevertheless, I wanted to know what's going on in Python2. Inserting some printf-debugging showed that the segfault appears on the XbdLockModifiers() call. X11 is shown as <CDLL 'libX11.so.6', handle 55a04db6bd00 at 7f7f6573e110>, display as some arbitrary int (changes with every call). I also had a look at what the c_uint()s returns, but that was unobtrusive. I don't know why Python2 fucks up, but I propose to change the answer to use Python3. What do you think?
  • h3.
    h3. over 4 years
    @Alfe Right now I'm on an Ubuntu 16.04 machine and the oneliner works for me with both python2 and python3. I have an Ubuntu 18.04 chroot on this machine and the oneliner segfaults with both python2 and python3. I don't know why it behaves differently for different people.
  • Javi
    Javi about 4 years
    Great solution, thank you. I installed "onboard" which is a very simple onscreen keyboard and that solved it.
  • TFuto
    TFuto about 4 years
    Stuck Caps-Lock in VMWare 15.5, Ubuntu 20.04 LTS. Only worked xautomation so far.