_winmouse.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. # -*- coding: utf-8 -*-
  2. import ctypes
  3. import time
  4. from ctypes import c_short, c_char, c_uint8, c_int32, c_int, c_uint, c_uint32, c_long, byref, Structure, CFUNCTYPE, POINTER
  5. from ctypes.wintypes import DWORD, BOOL, HHOOK, MSG, LPWSTR, WCHAR, WPARAM, LPARAM
  6. LPMSG = POINTER(MSG)
  7. import atexit
  8. from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN, DOUBLE, WHEEL, HORIZONTAL, VERTICAL
  9. #https://github.com/boppreh/mouse/issues/1
  10. #user32 = ctypes.windll.user32
  11. user32 = ctypes.WinDLL('user32', use_last_error = True)
  12. class MSLLHOOKSTRUCT(Structure):
  13. _fields_ = [("x", c_long),
  14. ("y", c_long),
  15. ('data', c_int32),
  16. ('reserved', c_int32),
  17. ("flags", DWORD),
  18. ("time", c_int),
  19. ]
  20. LowLevelMouseProc = CFUNCTYPE(c_int, WPARAM, LPARAM, POINTER(MSLLHOOKSTRUCT))
  21. SetWindowsHookEx = user32.SetWindowsHookExA
  22. #SetWindowsHookEx.argtypes = [c_int, LowLevelMouseProc, c_int, c_int]
  23. SetWindowsHookEx.restype = HHOOK
  24. CallNextHookEx = user32.CallNextHookEx
  25. #CallNextHookEx.argtypes = [c_int , c_int, c_int, POINTER(MSLLHOOKSTRUCT)]
  26. CallNextHookEx.restype = c_int
  27. UnhookWindowsHookEx = user32.UnhookWindowsHookEx
  28. UnhookWindowsHookEx.argtypes = [HHOOK]
  29. UnhookWindowsHookEx.restype = BOOL
  30. GetMessage = user32.GetMessageW
  31. GetMessage.argtypes = [LPMSG, c_int, c_int, c_int]
  32. GetMessage.restype = BOOL
  33. TranslateMessage = user32.TranslateMessage
  34. TranslateMessage.argtypes = [LPMSG]
  35. TranslateMessage.restype = BOOL
  36. DispatchMessage = user32.DispatchMessageA
  37. DispatchMessage.argtypes = [LPMSG]
  38. # Beware, as of 2016-01-30 the official docs have a very incomplete list.
  39. # This one was compiled from experience and may be incomplete.
  40. WM_MOUSEMOVE = 0x200
  41. WM_LBUTTONDOWN = 0x201
  42. WM_LBUTTONUP = 0x202
  43. WM_LBUTTONDBLCLK = 0x203
  44. WM_RBUTTONDOWN = 0x204
  45. WM_RBUTTONUP = 0x205
  46. WM_RBUTTONDBLCLK = 0x206
  47. WM_MBUTTONDOWN = 0x207
  48. WM_MBUTTONUP = 0x208
  49. WM_MBUTTONDBLCLK = 0x209
  50. WM_MOUSEWHEEL = 0x20A
  51. WM_XBUTTONDOWN = 0x20B
  52. WM_XBUTTONUP = 0x20C
  53. WM_XBUTTONDBLCLK = 0x20D
  54. WM_NCXBUTTONDOWN = 0x00AB
  55. WM_NCXBUTTONUP = 0x00AC
  56. WM_NCXBUTTONDBLCLK = 0x00AD
  57. WM_MOUSEHWHEEL = 0x20E
  58. WM_LBUTTONDOWN = 0x0201
  59. WM_LBUTTONUP = 0x0202
  60. WM_MOUSEMOVE = 0x0200
  61. WM_MOUSEWHEEL = 0x020A
  62. WM_MOUSEHWHEEL = 0x020E
  63. WM_RBUTTONDOWN = 0x0204
  64. WM_RBUTTONUP = 0x0205
  65. buttons_by_wm_code = {
  66. WM_LBUTTONDOWN: (DOWN, LEFT),
  67. WM_LBUTTONUP: (UP, LEFT),
  68. WM_LBUTTONDBLCLK: (DOUBLE, LEFT),
  69. WM_RBUTTONDOWN: (DOWN, RIGHT),
  70. WM_RBUTTONUP: (UP, RIGHT),
  71. WM_RBUTTONDBLCLK: (DOUBLE, RIGHT),
  72. WM_MBUTTONDOWN: (DOWN, MIDDLE),
  73. WM_MBUTTONUP: (UP, MIDDLE),
  74. WM_MBUTTONDBLCLK: (DOUBLE, MIDDLE),
  75. WM_XBUTTONDOWN: (DOWN, X),
  76. WM_XBUTTONUP: (UP, X),
  77. WM_XBUTTONDBLCLK: (DOUBLE, X),
  78. }
  79. MOUSEEVENTF_ABSOLUTE = 0x8000
  80. MOUSEEVENTF_MOVE = 0x1
  81. MOUSEEVENTF_WHEEL = 0x800
  82. MOUSEEVENTF_HWHEEL = 0x1000
  83. MOUSEEVENTF_LEFTDOWN = 0x2
  84. MOUSEEVENTF_LEFTUP = 0x4
  85. MOUSEEVENTF_RIGHTDOWN = 0x8
  86. MOUSEEVENTF_RIGHTUP = 0x10
  87. MOUSEEVENTF_MIDDLEDOWN = 0x20
  88. MOUSEEVENTF_MIDDLEUP = 0x40
  89. MOUSEEVENTF_XDOWN = 0x0080
  90. MOUSEEVENTF_XUP = 0x0100
  91. simulated_mouse_codes = {
  92. (WHEEL, HORIZONTAL): MOUSEEVENTF_HWHEEL,
  93. (WHEEL, VERTICAL): MOUSEEVENTF_WHEEL,
  94. (DOWN, LEFT): MOUSEEVENTF_LEFTDOWN,
  95. (UP, LEFT): MOUSEEVENTF_LEFTUP,
  96. (DOWN, RIGHT): MOUSEEVENTF_RIGHTDOWN,
  97. (UP, RIGHT): MOUSEEVENTF_RIGHTUP,
  98. (DOWN, MIDDLE): MOUSEEVENTF_MIDDLEDOWN,
  99. (UP, MIDDLE): MOUSEEVENTF_MIDDLEUP,
  100. (DOWN, X): MOUSEEVENTF_XDOWN,
  101. (UP, X): MOUSEEVENTF_XUP,
  102. }
  103. NULL = c_int(0)
  104. WHEEL_DELTA = 120
  105. init = lambda: None
  106. def listen(queue):
  107. def low_level_mouse_handler(nCode, wParam, lParam):
  108. struct = lParam.contents
  109. # Can't use struct.time because it's usually zero.
  110. t = time.time()
  111. if wParam == WM_MOUSEMOVE:
  112. event = MoveEvent(struct.x, struct.y, t)
  113. elif wParam == WM_MOUSEWHEEL:
  114. event = WheelEvent(struct.data / (WHEEL_DELTA * (2<<15)), t)
  115. elif wParam in buttons_by_wm_code:
  116. type, button = buttons_by_wm_code.get(wParam, ('?', '?'))
  117. if wParam >= WM_XBUTTONDOWN:
  118. button = {0x10000: X, 0x20000: X2}[struct.data]
  119. event = ButtonEvent(type, button, t)
  120. queue.put(event)
  121. return CallNextHookEx(NULL, nCode, wParam, lParam)
  122. WH_MOUSE_LL = c_int(14)
  123. mouse_callback = LowLevelMouseProc(low_level_mouse_handler)
  124. mouse_hook = SetWindowsHookEx(WH_MOUSE_LL, mouse_callback, NULL, NULL)
  125. # Register to remove the hook when the interpreter exits. Unfortunately a
  126. # try/finally block doesn't seem to work here.
  127. atexit.register(UnhookWindowsHookEx, mouse_hook)
  128. msg = LPMSG()
  129. while not GetMessage(msg, NULL, NULL, NULL):
  130. TranslateMessage(msg)
  131. DispatchMessage(msg)
  132. def _translate_button(button):
  133. if button == X or button == X2:
  134. return X, {X: 0x10000, X2: 0x20000}[button]
  135. else:
  136. return button, 0
  137. def press(button=LEFT):
  138. button, data = _translate_button(button)
  139. code = simulated_mouse_codes[(DOWN, button)]
  140. user32.mouse_event(code, 0, 0, data, 0)
  141. def release(button=LEFT):
  142. button, data = _translate_button(button)
  143. code = simulated_mouse_codes[(UP, button)]
  144. user32.mouse_event(code, 0, 0, data, 0)
  145. def wheel(delta=1):
  146. code = simulated_mouse_codes[(WHEEL, VERTICAL)]
  147. user32.mouse_event(code, 0, 0, int(delta * WHEEL_DELTA), 0)
  148. def move_to(x, y):
  149. user32.SetCursorPos(int(x), int(y))
  150. def move_relative(x, y):
  151. user32.mouse_event(MOUSEEVENTF_MOVE, int(x), int(y), 0, 0)
  152. class POINT(Structure):
  153. _fields_ = [("x", c_long), ("y", c_long)]
  154. def get_position():
  155. point = POINT()
  156. user32.GetCursorPos(byref(point))
  157. return (point.x, point.y)
  158. if __name__ == '__main__':
  159. def p(e):
  160. print(e)
  161. listen(p)