# -*- 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)