4

I am writing an anti-RSI/typing break programme for Ubuntu Linux in python. I would like to be able to "lock the keyboard" so that all keypresses are ignored until I "unlock" it. I want to be able to force the user to take a typing break.

I would like some programmatic way to "turn off" the keyboard (near instantaneously) until my programme releases it later (which could be 0.1 sec → 10 sec later). While I have "turned off the keyboard", no key presses should be sent to any windows, window managers, etc. Preferably, the screen should still show the same content. The keyboard should be locked even if this programme is not at the forefont and does not have focus.

Some programmes are able to do this already (e.g. Work Rave)

How do I do this on Linux/X11? (Preferable in Python)

Amandasaurus
  • 58,203
  • 71
  • 188
  • 248
  • I do not think VB.NET works on Linux… Does it? If it does, then I might be able to figure it out myself, so yes that would be helpful. – Amandasaurus May 24 '12 at 15:10
  • Can you convert VB.NET to Python? I've never programmed with Python, sorry about that. – user959631 May 24 '12 at 15:12
  • I could probably see how you're telling X to stop the keyboard, so yes, if it works on Linux/X11 then it's a helpful answer that I could learn from, so please add it. – Amandasaurus May 24 '12 at 15:12
  • A search for "turn off keyboard x11" on Ddg gave me [this](https://niteria.wordpress.com/2009/05/11/how-to-turn-off-laptop-keyboard/). It looks promising, see if it helps, I'll try to figure it out too. – jadkik94 May 24 '12 at 15:23
  • I don't think a lock of 0.1 seconds is likely to force a user to take a break (possibly miss a single keystroke, which would be more of an annoyance than a help). Even 10s probably wouldn't do much for that. – Kevin May 24 '12 at 15:40
  • I can't speak for VB.NET but C# will run on Linux with Mono (but I expect something in Python using Linux and/or X11 interfaces is going to have a much higher chance of being able to do what you want) – Foon May 24 '12 at 20:49

3 Answers3

4

Based on that, here's a code I came up with:

class KeyboardLocker:

    def __init__(self, serio=0):
        self._on = False
        self.serio = serio

    def on(self):
        return self._on

    def write_value(self,path, value):
        with open(path, "a") as f:
            f.write(value)

    def toggle(self):
        if self.on():
            self.turn_off()
        else:
            self.turn_on()

    def description(self):
        path = '/sys/devices/platform/i8042/serio%d/description' % (self.serio,)
        with open(path, "r") as f:
            description = f.read()
        return description

    def turn_on(self):
        try:
            self.write_value('/sys/devices/platform/i8042/serio%d/bind_mode' % (self.serio,),
                            'auto')
        except IOError, e:
            self._on = False
            raise
        else:
            self._on = True
        return self.on()

    def turn_off(self):
        try:
            self.write_value('/sys/devices/platform/i8042/serio%d/bind_mode' % (self.serio,),
                            'manual')
            self.write_value('/sys/devices/platform/i8042/serio%d/drvctl' % (self.serio,),
                            'psmouse')
        except IOError, e:
            self._on = True
            raise
        else:
            self._on = False
        return self.on()

if __name__ == "__main__":
    kl = KeyboardLocker(serio=0)

    device = kl.description()
    print "We got a lock on", device

    proceed = raw_input("Do you want to proceed? (y/n)").lower().startswith("y")
    import sys
    if not proceed: sys.exit(1)

    kl.turn_off()

    import time
    wait = 5
    print "Sleeping few seconds...", wait
    time.sleep(wait)
    print "Voila!"

    kl.turn_on()

    raw_input("Does it work now?")

Tested on Linux Mint 12, X11, HP Laptop, Gnome. Not sure if any of that matters though :)

UPDATE Added an option to change the path, e.g. "serio0" or "serio1". And prints the description, for me serio0 gave me: i8042 KBD port, most likely if you have "KBD" in it, it's right, continue, otherwise I give you no guarantee :)

jadkik94
  • 7,000
  • 2
  • 30
  • 39
2

The canonical way to do this is by grabbing the input. For this no window must be actually visible. A input only window usually does the trick. However you should give the user some sort of feedback, why his input no longer works. Doing this as a focus grab has the advantage that a crash of the program won't turn the system unresponsive.

BTW: I think forcibly interrupting the user, maybe in the middle of a critical operations is a huge No-Go! I never understood the purpose of those programs. The user will sit in front of the screen idling, maybe loosing his thoughts. Just my 2 cents.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 1
    I know disablying the keyboard is a weird UI move, but it's for heath reasons. Lots of anti-RSI programmes do it. I would of course have a notification that would tell the user and maybe have a "let me type" button. However I want to disable the keyboard while the user is typing somewhere else, i.e. there will be windows visible & focussed. – Amandasaurus May 27 '12 at 20:30
  • @Rory: Window visibility and focus are independent of device grabbing. You can grab the input device with any window, even if it's invisible. – datenwolf May 27 '12 at 23:20
  • I have asked a question about how to grab the input http://stackoverflow.com/questions/10796363/simple-linux-x11-programme-to-grab-and-keep-the-keyboard-focus Any help would be appreciated. – Amandasaurus May 29 '12 at 09:25
  • @Pryftan: I'm not only old enough to remember keyboard locks: I actively used them. These lock switches, BTW, worked by forcibly pulling the data line of the keyboard to GND. And I once got trolled by a faulty keyboard lock switch, into spending a whole evening switching keyboards. – datenwolf Dec 13 '19 at 17:23
  • @Pryftan: Also it's not a "narrow" mindset. It's just that I'm an "old-fart" in computer terms, and out of **experience** how certain things can blow up in your face (the road to hell is paved with good intentions) I advise to take a good and hard "think" about it. On modern computers keyboards are an "arbitrary" input device and it's not so clear cut what a "keyboard" is, and what not. Say the user has headphones on, is taking a break watching videos and a "LOUD" warning comes up: How is the user going to turn down the volume? Volume keys? They're also registered as keyboard. – datenwolf Dec 13 '19 at 17:27
  • @datenwolf Yes and I am old enough to understand what you're saying. But by limited or narrow I am saying that there are actually reasons to lock the keyboard. Now if you want to argue that it is overused - that and many other things - I would agree with you completely. I'm just saying that there are occasions that it has value. In other words it's not a binary thing. – Pryftan Dec 14 '19 at 20:35
1

This can be done easily with a shell script using xinput :

 #!/bin/sh

 do_it() {
     # need error checking there. We should also restrict which device gets
     # deactivated, by checking other properties.
     keyboard_ids="$(xinput list | sed -rn 's/.*id=([0-9]+).*slave\s+keyboard.*/\1/p')"

     for keyboard_id in $keyboard_ids; do
         # 121 is "Device Active".
         # use xinput watch-props $device_id to see some properties.
         xinput set-int-prop $keyboard_id 121 8 $1;
     done;
 }
 # you maybe don't want to exit in case of failure there.
 do_it 0 ; sleep 5; do_it 1

This logic is easily rewritable in Python. If installing xinput is problematic, it might be a good idea to fetch the source of xinput and try to reimplement it in Python using a library like python-xlib.

BatchyX
  • 4,986
  • 2
  • 18
  • 17