forked from nvaccess/nvda
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwinInputHook.py
executable file
·101 lines (90 loc) · 3.2 KB
/
winInputHook.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#winInputHook.py
#A part of NonVisual Desktop Access (NVDA)
#Copyright (C) 2006-2008 NVDA Contributors <http://www.nvda-project.org/>
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
import threading
import comtypes.client
import time
from ctypes import *
from ctypes.wintypes import *
from win32con import WM_QUIT, HC_ACTION, WH_KEYBOARD_LL, LLKHF_UP, LLKHF_EXTENDED, LLKHF_INJECTED, WH_MOUSE_LL, LLMHF_INJECTED
class KBDLLHOOKSTRUCT(Structure):
_fields_=[
('vkCode',DWORD),
('scanCode',DWORD),
('flags',DWORD),
('time',DWORD),
('dwExtraInfo',DWORD),
]
class MSLLHOOKSTRUCT(Structure):
_fields_=[
('pt',POINT),
('mouseData',DWORD),
('flags',DWORD),
('time',DWORD),
('dwExtraInfo',DWORD),
]
keyDownCallback=None
keyUpCallback=None
mouseCallback=None
@WINFUNCTYPE(c_long,c_int,WPARAM,LPARAM)
def keyboardHook(code,wParam,lParam):
if code!=HC_ACTION:
return windll.user32.CallNextHookEx(0,code,wParam,lParam)
kbd=KBDLLHOOKSTRUCT.from_address(lParam)
if keyUpCallback and kbd.flags&LLKHF_UP:
if not keyUpCallback(kbd.vkCode,kbd.scanCode,bool(kbd.flags&LLKHF_EXTENDED),bool(kbd.flags&LLKHF_INJECTED)):
return 1
elif keyDownCallback:
if not keyDownCallback(kbd.vkCode,kbd.scanCode,bool(kbd.flags&LLKHF_EXTENDED),bool(kbd.flags&LLKHF_INJECTED)):
return 1
return windll.user32.CallNextHookEx(0,code,wParam,lParam)
@WINFUNCTYPE(c_long,c_int,WPARAM,LPARAM)
def mouseHook(code,wParam,lParam):
if code!=HC_ACTION:
return windll.user32.CallNextHookEx(0,code,wParam,lParam)
msll=MSLLHOOKSTRUCT.from_address(lParam)
if mouseCallback:
if not mouseCallback(wParam,msll.pt.x,msll.pt.y,msll.flags&LLMHF_INJECTED):
return 1
return windll.user32.CallNextHookEx(0,code,wParam,lParam)
hookThread=None
hookThreadRefCount=0
def hookThreadFunc():
keyHookID=windll.user32.SetWindowsHookExW(WH_KEYBOARD_LL,keyboardHook,windll.kernel32.GetModuleHandleW(None),0)
if keyHookID==0:
raise OSError("Could not register keyboard hook")
mouseHookID=windll.user32.SetWindowsHookExW(WH_MOUSE_LL,mouseHook,windll.kernel32.GetModuleHandleW(None),0)
if mouseHookID==0:
raise OSError("Could not register mouse hook")
msg=MSG()
while windll.user32.GetMessageW(byref(msg),None,0,0):
pass
if windll.user32.UnhookWindowsHookEx(keyHookID)==0:
raise OSError("could not unregister key hook %s"%keyHookID)
if windll.user32.UnhookWindowsHookEx(mouseHookID)==0:
raise OSError("could not unregister mouse hook %s"%mouseHookID)
def initialize():
global hookThread, hookThreadRefCount
hookThreadRefCount+=1
if hookThreadRefCount==1:
hookThread=threading.Thread(target=hookThreadFunc)
hookThread.start()
def setCallbacks(keyUp=None,keyDown=None,mouse=None):
global keyUpCallback, keyDownCallback, mouseCallback
if keyUp:
keyUpCallback=keyUp
if keyDown:
keyDownCallback=keyDown
if mouse:
mouseCallback=mouse
def terminate():
global hookThread, hookThreadRefCount
if not hookThread:
raise RuntimeError("winInputHook not running")
hookThreadRefCount-=1
if hookThreadRefCount==0:
windll.user32.PostThreadMessageW(hookThread.ident,WM_QUIT,0,0)
hookThread.join()
hookThread=None