如何在X11/Linux/Gnome上“锁定键盘”以防止发送更多的按键?

4
我正在用Python为Ubuntu Linux编写一款反RSI/打字休息程序。我希望能够“锁定键盘”,以便在“解锁”之前忽略所有按键。我想强制用户进行打字休息。
我希望有一种编程方法可以“关闭”键盘(几乎瞬间),直到我的程序稍后释放它(可能是0.1秒→10秒后)。当我“关闭键盘”时,不应将任何按键发送到任何窗口、窗口管理器等。最好,屏幕仍然显示相同的内容。即使此程序不在前台并且没有焦点,也应锁定键盘。
已经有一些程序可以做到这一点(例如Work Rave)。
如何在Linux/X11上实现此功能?(最好使用Python)

我认为VB.NET不能在Linux上运行...它可以吗?如果可以的话,那么我可能能够自己解决问题,所以是的,这会很有帮助。 - Amandasaurus
你能把VB.NET转换成Python吗?我从未使用过Python编程,对此感到抱歉。 - user959631
我可以理解你是如何让 X 停止键盘的,所以如果它在Linux/X11上起作用,那么这个有帮助的答案我可以学习一下,请添加进来。 - Amandasaurus
在Ddg上搜索“关闭x11键盘”,我得到了这个。它看起来很有希望,试着看看是否有帮助,我也会尝试弄清楚的。 - jadkik94
我不认为0.1秒的锁定时间会强制用户休息(可能会错过一个按键,更像是一种烦恼而不是帮助)。即使是10秒对此也没有太大作用。 - Kevin
我不能代表VB.NET说话,但是C#可以在Linux上使用Mono运行(但我认为使用Linux和/或X11接口的Python程序更有可能实现您想要的功能)。 - Foon
3个回答

4

参考这个,这是我想出来的代码:

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?")

测试环境为Linux Mint 12,X11,HP笔记本电脑,Gnome桌面环境。不确定这些是否有影响 :)

更新 添加了一个选项来更改路径,例如“serio0”或“serio1”。并打印描述信息,对于我而言,“serio0”给出的是:i8042 KBD端口,如果你的端口中有“KBD”,那么很可能是正确的,请继续操作,否则我无法保证结果的准确性 :)


2
这个问题的规范解决方法是获取输入。为此,不需要实际显示任何窗口。一个只有输入框的窗口通常能起到作用。但是您应该给用户一些反馈,告诉他为什么他的输入不再起作用。将其作为焦点抓取的方式具有一个优势,即程序崩溃时不会使系统无响应。
顺便说一下:我认为强制打断用户,甚至在关键操作中间打断用户,是一个巨大的No-Go!我从来没有理解过这些程序的目的。用户将坐在屏幕前发呆,也许会失去思路。这只是我的个人看法。

1
我知道禁用键盘是一种奇怪的用户界面操作,但这是为了健康原因。许多反RSI程序都会这样做。当然,我会有一个通知告诉用户,并可能会有一个“让我输入”按钮。然而,我希望在用户在其他地方输入时禁用键盘,即会有可见和聚焦的窗口。 - Amandasaurus
@Rory:窗口的可见性和焦点与设备抓取无关。即使窗口不可见,您也可以使用任何窗口来抓取输入设备。 - datenwolf
我曾经提出过一个问题,关于如何获取输入https://dev59.com/gmTWa4cB1Zd3GeqPCVvO。任何帮助将不胜感激。 - Amandasaurus
@Pryftan:我不仅年龄足够大以记得键盘锁的使用,而且曾经积极地使用过它们。顺便说一下,这些锁开关的工作原理是通过强制将键盘数据线拉到地线来实现的。我曾经被一个有故障的键盘锁开关捉弄,花了一整个晚上切换键盘。 - datenwolf
@Pryftan:而且这不是“狭隘”的想法。只是因为在计算机术语中,我是一个“老古董”,并且通过经验知道某些事情可能会让你陷入困境(通往地狱的路是由善意铺成的),所以我建议好好考虑一下。在现代计算机上,键盘是一种“任意”的输入设备,不太清楚什么是“键盘”,什么不是。假设用户戴着耳机,正在休息观看视频,突然出现一个“大声”的警告:用户如何降低音量?音量键?它们也被注册为键盘。 - datenwolf
@datenwolf 是的,我足够老了,能够理解你的意思。但是,当我说“有限制或狭窄”时,我是指锁定键盘实际上有其原因。现在,如果你想争论它被过度使用了——以及许多其他事情——我完全同意你的观点。我只是想说,有时候它确实有价值。换句话说,这不是一个二元的事情。 - Pryftan

1

使用 shell 脚本和 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

这个逻辑可以很容易地在Python中重写。如果安装xinput有问题,可以尝试获取xinput的源代码,并使用类似python-xlib的库在Python中重新实现它。


这是一个很棒、快速、有效和简单的方法来完成它。它似乎也是正确的方式™。 - Amandasaurus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接