How do I 'lock the keyboard' to prevent any more keypresses being sent on X11/Linux/Gnome?

Solution 1:

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 :)

Solution 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.

Solution 3:

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.