我正在为python中的Ubuntu Linux编写一个反RSI /打字中断程序。我希望能够“锁定键盘”,以便忽略所有按键,直到我“解锁”它。我希望能够强迫用户打字输入。
我想要一些程序化的方法来“关闭”键盘(接近瞬间),直到我的程序稍后释放它(可能是0.1秒→10秒后)。当我“关掉键盘”时,不应该向任何窗口,窗口管理器等发送按键。优选地,屏幕仍然应该显示相同的内容。即使该程序不在前面并且没有焦点,键盘也应该被锁定。
有些程序已经可以执行此操作(例如Work Rave)
如何在Linux / X11上执行此操作? (在Python中更好)
答案 0 :(得分:4)
基于that,这是我提出的代码:
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”,它是正确的,继续,否则我不能保证:)
答案 1 :(得分:2)
这样做的规范方法是抓住输入。为此,必须实际看不到窗口。仅输入窗口通常可以解决问题。但是你应该给用户一些反馈,为什么他的输入不再起作用。将此作为焦点抓取具有以下优点:程序崩溃不会使系统无响应。
BTW:我认为强行打断用户,可能在关键操作过程中是一个巨大的 No-Go!我从来不理解这些程序的目的。用户将坐在屏幕前空转,可能会失去他的想法。我的2美分。答案 2 :(得分:1)
使用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中重新实现它可能是个好主意。
答案 3 :(得分:-1)
顺便说一下,这不是我的代码
这会阻止用户按下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()