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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# -*- coding: utf-8 -*-
import struct
from subprocess import check_output
import re
from ._nixcommon import EV_KEY, EV_REL, EV_MSC, EV_SYN, EV_ABS, aggregate_devices, ensure_root
from ._mouse_event import ButtonEvent, WheelEvent, MoveEvent, LEFT, RIGHT, MIDDLE, X, X2, UP, DOWN
import ctypes
import ctypes.util
from ctypes import c_uint32, c_uint, c_int, byref
display = None
window = None
x11 = None
def build_display():
global display, window, x11
if display and window and x11: return
x11 = ctypes.cdll.LoadLibrary(ctypes.util.find_library('X11'))
# Required because we will have multiple threads calling x11,
# such as the listener thread and then main using "move_to".
x11.XInitThreads()
display = x11.XOpenDisplay(None)
# Known to cause segfault in Fedora 23 64bits, no known workarounds.
# http://stackoverflow.com/questions/35137007/get-mouse-position-on-linux-pure-python
window = x11.XDefaultRootWindow(display)
def get_position():
build_display()
root_id, child_id = c_uint32(), c_uint32()
root_x, root_y, win_x, win_y = c_int(), c_int(), c_int(), c_int()
mask = c_uint()
ret = x11.XQueryPointer(display, c_uint32(window), byref(root_id), byref(child_id),
byref(root_x), byref(root_y),
byref(win_x), byref(win_y), byref(mask))
return root_x.value, root_y.value
def move_to(x, y):
build_display()
x11.XWarpPointer(display, None, window, 0, 0, 0, 0, x, y)
x11.XFlush(display)
REL_X = 0x00
REL_Y = 0x01
REL_Z = 0x02
REL_HWHEEL = 0x06
REL_WHEEL = 0x08
ABS_X = 0x00
ABS_Y = 0x01
BTN_MOUSE = 0x110
BTN_LEFT = 0x110
BTN_RIGHT = 0x111
BTN_MIDDLE = 0x112
BTN_SIDE = 0x113
BTN_EXTRA = 0x114
button_by_code = {
BTN_LEFT: LEFT,
BTN_RIGHT: RIGHT,
BTN_MIDDLE: MIDDLE,
BTN_SIDE: X,
BTN_EXTRA: X2,
}
code_by_button = {button: code for code, button in button_by_code.items()}
device = None
def build_device():
global device
if device: return
ensure_root()
device = aggregate_devices('mouse')
init = build_device
def listen(queue):
build_device()
while True:
time, type, code, value, device_id = device.read_event()
if type == EV_SYN or type == EV_MSC:
continue
event = None
arg = None
if type == EV_KEY:
event = ButtonEvent(DOWN if value else UP, button_by_code.get(code, '?'), time)
elif type == EV_REL:
value, = struct.unpack('i', struct.pack('I', value))
if code == REL_WHEEL:
event = WheelEvent(value, time)
elif code in (REL_X, REL_Y):
x, y = get_position()
event = MoveEvent(x, y, time)
if event is None:
# Unknown event type.
continue
queue.put(event)
def press(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x01)
def release(button=LEFT):
build_device()
device.write_event(EV_KEY, code_by_button[button], 0x00)
def move_relative(x, y):
build_device()
# Note relative events are not in terms of pixels, but millimeters.
if x < 0:
x += 2**32
if y < 0:
y += 2**32
device.write_event(EV_REL, REL_X, x)
device.write_event(EV_REL, REL_Y, y)
def wheel(delta=1):
build_device()
if delta < 0:
delta += 2**32
device.write_event(EV_REL, REL_WHEEL, delta)
if __name__ == '__main__':
#listen(print)
move_to(100, 200)
|