diff --git a/desktop_control_interface.py b/desktop_control_interface.py index 4037f34..8d54f05 100644 --- a/desktop_control_interface.py +++ b/desktop_control_interface.py @@ -1,41 +1,85 @@ -import pyautogui import numpy -import evdev import keymap - -pyautogui.FAILSAFE = False +import libevdev +from libevdev import InputEvent, InputAbsInfo class DesktopControlInterface(): def __init__(self, resolution): + global uinput self.resolution = resolution - self.ui = evdev.UInput() - self.valid_actions = ["keyboard", "click", "rightclick", "mousemove", "joystick", "paste"] + self.dev = libevdev.Device() + self.dev.name = 'virtual mouse and keyboard' + x_info = InputAbsInfo(minimum=0, maximum=resolution.width, resolution=200) + self.dev.enable(libevdev.EV_ABS.ABS_X, data=x_info) + y_info = InputAbsInfo(minimum=0, maximum=resolution.height, resolution=200) + self.dev.enable(libevdev.EV_ABS.ABS_Y, data=y_info) + self.dev.enable(libevdev.EV_KEY.BTN_LEFT) + self.dev.enable(libevdev.EV_KEY.BTN_MIDDLE) + self.dev.enable(libevdev.EV_KEY.BTN_RIGHT) + self.uinput = self.dev.create_uinput_device() def handle_action(self, action, data): if action == "mousemove": x = numpy.interp(data["cursorPositionX"], (0, data["displayWidth"]), (0, self.resolution.width)) y = numpy.interp(data["cursorPositionY"], (0, data["displayHeight"]), (0, self.resolution.height)) - pyautogui.moveTo(x, y, _pause=False) - # elif action == "joystick": - # x = numpy.interp(data["x"], (-38, 38), (0, self.resolution.width)) - # y = numpy.interp(data["y"], (-38, 38), (self.resolution.height, 0)) - # print(f'{data["y"]} {self.resolution.height} {y}') - # pyautogui.moveTo(x, y, _pause=False) - elif action == "click": - pyautogui.click() + print(f"mousemove {x} {y}") + events = [InputEvent(libevdev.EV_ABS.ABS_X, int(x)), + InputEvent(libevdev.EV_ABS.ABS_Y, int(y)), + InputEvent(libevdev.EV_SYN.SYN_REPORT, 0)] + self.uinput.send_events(events) + + elif action == "mousedown": + pass + elif action == "mouseup": + pass elif action == "rightclick": - pyautogui.rightClick() + pass elif action == "keyboard": try: # keymap.reload() osKey = keymap.iOStoLinux[data["key"]] - self.ui.write(evdev.ecodes.EV_KEY, osKey, data["direction"]) - self.ui.syn() + print(osKey) + # self.ui.write(e.EV_KEY, osKey, data["direction"]) + # self.ui.syn() except KeyError: print(f"Unknown key: {data['key']}") elif action == "paste": + pass # might as well support the secureput protocol completely - pyautogui.write(data["payload"]["string"]) - + # pyautogui.write(data["payload"]["string"]) + + def supports(self, action): + return action in ["keyboard", "click", "rightclick", "mousemove", "joystick", "paste"] + def stop(self): - self.ui.close() \ No newline at end of file + pass + # self.ui.close() + + +if __name__ == "__main__": + import time + import libevdev + from libevdev import InputEvent, InputAbsInfo + dev = libevdev.Device() + dev.name = 'some test device' + a = InputAbsInfo(minimum=0, maximum=1920, resolution=200) + dev.enable(libevdev.EV_ABS.ABS_X, data=a) + a = InputAbsInfo(minimum=0, maximum=1080, resolution=200) + dev.enable(libevdev.EV_ABS.ABS_Y, data=a) + dev.enable(libevdev.EV_KEY.BTN_LEFT) + dev.enable(libevdev.EV_KEY.BTN_MIDDLE) + dev.enable(libevdev.EV_KEY.BTN_RIGHT) + + uinput = dev.create_uinput_device() + print("New device at {} ({})".format(uinput.devnode, uinput.syspath)) + + # Sleep for a bit so udev, libinput, Xorg, Wayland, ... all have had + # a chance to see the device and initialize it. Otherwise the event + # will be sent by the kernel but nothing is ready to listen to the + # device yet. + time.sleep(1) + + + events = [InputEvent(libevdev.EV_ABS.ABS_X, 1900), + InputEvent(libevdev.EV_ABS.ABS_Y, 1000), + InputEvent(libevdev.EV_SYN.SYN_REPORT, 0)] diff --git a/desktop_stream_track.py b/desktop_stream_track.py index c6a8d38..02310b0 100755 --- a/desktop_stream_track.py +++ b/desktop_stream_track.py @@ -12,7 +12,7 @@ class DesktopStreamTrack(VideoStreamTrack): def __init__(self): super().__init__() self.resolution = Xlib.display.Display(os.environ["DISPLAY"]).screen().root.get_geometry() - self.control_interface = DesktopControlInterface(self.resolution) + self.input = DesktopControlInterface(self.resolution) options = { 'draw_mouse': '1', 'i':':0.0+0,0', @@ -30,13 +30,10 @@ class DesktopStreamTrack(VideoStreamTrack): frame.pts = pts frame.time_base = time_base return frame - - def handle_action(self, action, data): - self.control_interface.handle_action(action, data) def stop(self) -> None: super().stop() - self.control_interface.stop() + self.input.stop() if __name__ == "__main__": from time import time_ns diff --git a/server.py b/server.py index 1ac6e1f..9efbca3 100755 --- a/server.py +++ b/server.py @@ -164,8 +164,8 @@ async def signal(signaling): print(data) elif data["type"] == "joystick": webjoystick(data["x"], data["y"]) - elif desktop_track and data["type"] in desktop_track.control_interface.valid_actions: - desktop_track.handle_action(data["type"], data) + elif desktop_track and desktop_track.input.supports(data["type"]): + desktop_track.input.handle_action(data["type"], data) else: print("ignored message") print(data)