aboutsummaryrefslogtreecommitdiff
path: root/Python/venv1/Lib/site-packages/keyboard/_nixmouse.py
blob: 6b02c57d8639c28bb867b62fe66d6da680eb533f (plain) (blame)
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)