繁体   English   中英

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

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

我正在为python中的Ubuntu Linux编写一个反RSI /打字中断程序。 我希望能够“锁定键盘”,以便忽略所有按键,直到我“解锁”它。 我希望能够强制用户进行打字休息。

我想要一些程序化的方法来“关闭”键盘(接近瞬间),直到我的程序稍后释放它(可能是0.1秒→10秒后)。 当我“关掉键盘”时,不应该向任何窗口,窗口管理器等发送按键。优选地,屏幕仍然应该显示相同的内容。 即使此程序不在前面并且没有焦点,键盘也应该被锁定。

有些程序已经能够做到这一点(例如Work Rave)

我如何在Linux / X11上执行此操作? (在Python中优先)

基于 ,这是我提出的代码:

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 Laptop,Gnome上测试过。 不确定是否有任何重要但:)

更新添加了更改路径的选项,例如“serio0”或“serio1”。 并打印描述,对我来说serio0给了我: i8042 KBD port ,很可能如果你有“KBD”,它是对的,继续,否则我不保证你:)

这样做的规范方法是抓住输入。 为此,必须实际看不到窗口。 仅输入窗口通常可以解决问题。 但是你应该给用户一些反馈,为什么他的输入不再起作用。 将此作为焦点抓取具有以下优点:程序崩溃不会使系统无响应。

顺便说一句:我认为强行打断用户,也许在关键操作中间是一个巨大的禁忌! 我从未明白这些计划的目的。 用户将坐在屏幕前空转,可能会失去他的想法。 只需2美分。

使用xinput的shell脚本可以轻松完成此操作:

 #!/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中重新实现它可能是个好主意。

顺便说一句,这不是我的代码

这会阻止用户按下Win键,Shift键或Alt键,但我相信您也可以应用其他键。

Public Class KeyboardJammer
Private Delegate Function HookCallback(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
Private Shared HookDelegate As HookCallback
Private Shared HookId As Integer
Private Const Wh_Keyboard_LL As Integer = 13
Private Const Vk_Tab As Integer = 9
Private Const Vk_Escape As Integer = 27
Private Const Vk_LWinKey As Integer = 91
Private Const Vk_RWinkKey As Integer = 92

Private Shared Function KeyBoardHookProc(ByVal nCode As Integer, ByVal wParam As Integer, ByVal lParam As IntPtr) As Integer
    'All keyboard events will be sent here.'

    'Dont process just pass along.'
    If nCode < 0 Then
        Return CallNextHookEx(HookId, nCode, wParam, lParam)
    End If

    'Extract the keyboard structure from the lparam'
    'This will contain the virtual key and any flags.'
    'This is using the my.computer.keyboard to get the'
    'flags instead'
    Dim KeyboardSruct As KBDLLHOOKSTRUCT = Marshal.PtrToStructure(lParam, GetType(KBDLLHOOKSTRUCT))

    If KeyboardSruct.vkCode = Vk_Tab And My.Computer.Keyboard.AltKeyDown Then
        'Alt Tab'
        Return 1
    ElseIf KeyboardSruct.vkCode = Vk_Escape And My.Computer.Keyboard.CtrlKeyDown Then
        'Control Escape'
        Return 1
    ElseIf KeyboardSruct.vkCode = Vk_LWinKey Or KeyboardSruct.vkCode = Vk_RWinkKey Then
        If KeyboardSruct.vkCode = Vk_Tab Then
            'Winkey Tab'
            Return 1
        Else
            'Winkey'
            Return 1
        End If
    ElseIf KeyboardSruct.vkCode = Vk_Escape And My.Computer.Keyboard.AltKeyDown Then
        'Alt Escape'
        Return 1
    End If

    'Send the message along'
    Return CallNextHookEx(HookId, nCode, wParam, lParam)

End Function

Public Shared Sub Jam()
    'Add the low level keyboard hook'
    If HookId = 0 Then
        HookDelegate = AddressOf KeyBoardHookProc
        HookId = SetWindowsHookEx(Wh_Keyboard_LL, HookDelegate, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly.GetModules()(0)), 0)

        If HookId = 0 Then
            'error'
        End If

    End If
End Sub

Public Shared Sub UnJam()
    'Remove the hook'
    UnhookWindowsHookEx(HookId)
End Sub

<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall)> _
Private Shared Function CallNextHookEx( _
   ByVal idHook As Integer, _
   ByVal nCode As Integer, _
   ByVal wParam As IntPtr, _
   ByVal lParam As IntPtr) As Integer
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)> _
Private Shared Function SetWindowsHookEx( _
       ByVal idHook As Integer, _
       ByVal HookProc As HookCallback, _
       ByVal hInstance As IntPtr, _
       ByVal wParam As Integer) As Integer
End Function

<DllImport("user32.dll", CharSet:=CharSet.Auto, CallingConvention:=CallingConvention.StdCall, SetLastError:=True)> _
Private Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Integer
End Function

Private Structure KBDLLHOOKSTRUCT
    Public vkCode As Integer
    Public scanCode As Integer
    Public flags As Integer
    Public time As Integer
    Public dwExtraInfo As IntPtr
End Structure
End Class

用法:

KeyboardJammer.Jam()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM