24 мая 2012 г., 17:10 отRory

Как «заблокировать клавиатуру», чтобы предотвратить дальнейшее нажатие клавиш в X11 / Linux / Gnome?

Я пишу анти-RSI / программу прерывания печати для Ubuntu Linux на python. Я хотел бы иметь возможность "заблокировать клавиатуру" так что все нажатия клавиш игнорируются до тех пор, пока я не "разблокирую" Это. Я хочу заставить пользователя сделать перерыв при наборе текста.

Я хотел бы, чтобы какой-то программный способ "выключить" клавиатуре (почти мгновенно), пока моя программа не выпустит ее позже (что может занять 0,1 с и 10 секунд спустя). Несмотря на то, что я «выключил клавиатуру», никакие нажатия клавиш не следует отправлять ни в какие окна, в оконные менеджеры и т. Д. Предпочтительно на экране все равно должно отображаться то же содержимое. Клавиатура должна быть заблокирована, даже если эта программа не находится на передней панели и не имеет фокуса.

Некоторые программы уже могут это сделать (например, Work Rave)

Как мне сделать это на Linux / X11? (Предпочтительно в Python)

Ответы на вопрос(4)

27 мая 2012 г., 02:55 отdatenwolf

но не должно быть фактически видимым. Окно только для ввода обычно делает свое дело. Однако вы должны дать пользователю своего рода обратную связь, почему его ввод больше не работает. Делать это в качестве захвата фокуса имеет то преимущество, что сбой программы не сделает систему безразличной.

BTW: я думаю, что насильственное прерывание пользователя, может быть, в середине критических операций огромн No-Go! Я никогда не понимал цели этих программ. Пользователь будет сидеть перед экраном на холостом ходу, возможно, теряя свои мысли. Просто мои 2 цента.

25 мая 2012 г., 02:43 отBatchyX

 #!/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, используя такую библиотеку, как python-xlib.

24 мая 2012 г., 21:41 отjadkik94

На основаниичт, вот код, который я придумал:

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 port, скорее всего, если у вас есть «KBD», это правильно, продолжайте, в противном случае я не даю вам никакой гарантии:)

24 мая 2012 г., 21:20 отuser959631

Это останавливает пользователя от нажатия клавиш 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()

ВАШ ОТВЕТ НА ВОПРОС