Timeout for sticky keys

accessibilitykeyboardxkb

Context

I use xkbset to enable sticky keys:

xkbset sticky -twokey latchlock ## set sticky keys, don't disable via twokey
xkbset exp 1 =sticky ## don't expire sticky keys

That does exactly what I want, allowing me to tap and release the Shift key, and then press another key and get the 'shifted' value. Double-tapping Shift gives me CapsLock, and the same works for Ctrl, Alt, Hyper.

However, I sometimes get stuck with one or more of the modifiers in the 'locked' setting, and it can be difficult to figure out which ones are triggered in order to release them.

Question: Is there a way to 'timeout' the sticky keys?

Meaning, if I've pressed a sticky modifier, or locked a modifier, to have it revert to normal after 5 seconds or so without any further key presses.

I know that I can use xkbset to expire a setting after a set time, but that turns off the sticky keys entirely. What I want is to release all modifiers after a few seconds of inactivity, but to keep the sticky keys behaviour when I next press a modifier key.

EDIT

To clarify the difference, if I use the expire options, what I would get is:

  • I turn on shift lock by tapping Shift twice.
  • I accidentally lock control by tapping Ctrl twice.
  • confusion follows, as pressing A results in CtrlShiftA being entered.
  • After the expire period, the 'stuck' shift and control modifiers are removed, but modifiers are no longer sticky – tapping Shift and then pressing A, I get a regular a, not a shifted A

Instead, I would like the following behavior after the "confusion follows" point:

  • I wait three seconds, and then the 'stuck' shift and control modifiers are removed (i.e., pressing a produces an a), but modifiers are still sticky – tapping Shift and then pressing a, I get a shifted A.

I'm using the i3 window manager, so ideally I'd like a solution that doesn't depend on a full desktop manager suite.

Alternative: automatically call a script (once) after a period of keyboard inactivity?

As a workaround, I've defined a keyboard shortcut that will reset my xkbset configuration regardless of which modifiers are pressed (i.e., PrintScr, Shift+PrintScr, Ctrl+Shift+PrintScr etc are all bound to the same script). Running this script automatically after 5 seconds of keyboard inactivity would do what I'm after.

Best Answer

The solution to the question seems to be a script like the following using xprintidle to work out when to reset the lock state. Note that it has a polling loop, so it needs to keep running continually.

#!/bin/bash

# Sets sticky keys, but has them reset state (e.g. latchlock goes back to normal) after
# a few seconds

IDLE_RESET=3000 # 3 seconds

# Set up sticky keys and double tap to lock
xkbset sticky -twokey latchlock
# Disable XAccess managed sticky mode timeout
xkbset exp =sticky =latchlock

# Sentinel so we only run the reset once every idle period
sentinel=0
while true;do
    if [ $(xprintidle) -gt $IDLE_RESET ];then
        if [ $sentinel = 0 ];then
            # Reset the state
            xkbset -sticky -twokey -latchlock;xkbset sticky -twokey latchlock
            sentinel=1
        fi
    else
        sentinel=0
    fi
    sleep 1
done
Related Question