#!/usr/bin/env python3 """Narzędzie DEV: wstrzykiwanie zdarzeń myszy przez XTest (X11). PO CO: pozwala automatycznie przetestować interakcje kompozytora (przeciąganie okna, doklejanie do krawędzi, resize za rogi) bez ręcznego machania myszką. Działa na backendzie `winit`, bo ten tworzy zwykłe okno X11. Użycie (`DISPLAY` musi wskazywać na X z uruchomionym kompozytorem): python3 tools/x11_mouse.py move X Y python3 tools/x11_mouse.py click X Y python3 tools/x11_mouse.py drag X1 Y1 X2 Y2 [kroki] To NIE jest część PaganDE — zwykły skrypt pomocniczy. """ import ctypes import ctypes.util import sys import time x11 = ctypes.CDLL(ctypes.util.find_library("X11")) xtst = ctypes.CDLL(ctypes.util.find_library("Xtst")) x11.XOpenDisplay.restype = ctypes.c_void_p x11.XOpenDisplay.argtypes = [ctypes.c_char_p] x11.XDefaultScreen.restype = ctypes.c_int x11.XDefaultScreen.argtypes = [ctypes.c_void_p] x11.XFlush.argtypes = [ctypes.c_void_p] xtst.XTestFakeMotionEvent.argtypes = [ ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_ulong ] xtst.XTestFakeButtonEvent.argtypes = [ ctypes.c_void_p, ctypes.c_uint, ctypes.c_int, ctypes.c_ulong ] # BTN_LEFT w numeracji X11. BUTTON_LEFT = 1 _display = None _screen = 0 def open_display(): global _display, _screen _display = x11.XOpenDisplay(None) if not _display: raise SystemExit("nie mogę otworzyć DISPLAY (ustaw DISPLAY=:N)") _screen = x11.XDefaultScreen(_display) def move(x, y): xtst.XTestFakeMotionEvent(_display, _screen, int(x), int(y), 0) x11.XFlush(_display) def button(pressed): xtst.XTestFakeButtonEvent(_display, BUTTON_LEFT, 1 if pressed else 0, 0) x11.XFlush(_display) def click(x, y): move(x, y) time.sleep(0.05) button(True) time.sleep(0.08) button(False) time.sleep(0.05) def drag(x1, y1, x2, y2, steps=24): """Płynne przeciągnięcie: kompozytor dostaje wiele zdarzeń `motion`, dzięki czemu widzi wjazd w strefę doklejania, a nie jeden skok.""" move(x1, y1) time.sleep(0.1) button(True) time.sleep(0.15) for i in range(1, steps + 1): t = i / steps move(x1 + (x2 - x1) * t, y1 + (y2 - y1) * t) time.sleep(0.02) time.sleep(0.15) button(False) time.sleep(0.15) def main(argv): open_display() if len(argv) < 2: raise SystemExit(__doc__) cmd = argv[1] if cmd == "move": move(int(argv[2]), int(argv[3])) elif cmd == "click": click(int(argv[2]), int(argv[3])) elif cmd == "drag": steps = int(argv[6]) if len(argv) > 6 else 24 drag(int(argv[2]), int(argv[3]), int(argv[4]), int(argv[5]), steps) else: raise SystemExit(f"nieznane polecenie: {cmd}") if __name__ == "__main__": main(sys.argv)