From eaeceeac29172d4e562b379217e1b1b1656062d7 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 15 Mar 2022 12:13:46 +0800 Subject: [PATCH] https://github.com/rustdesk/rustdesk/issues/406#issuecomment-1064011977 --- libs/enigo/src/linux.rs | 10 +++++-- pynput_service.py | 62 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/libs/enigo/src/linux.rs b/libs/enigo/src/linux.rs index 5393bbd07..456c207ec 100644 --- a/libs/enigo/src/linux.rs +++ b/libs/enigo/src/linux.rs @@ -505,7 +505,9 @@ fn start_pynput_service(rx: mpsc::Receiver<(PyMsg, bool)>) { } else { let mut status = Ok(true); for i in 0..100 { - log::info!("#{} try to start pynput server", i); + if i % 10 == 0 { + log::info!("#{} try to start pynput server", i); + } status = std::process::Command::new("sudo") .args(vec![ &format!("XDG_RUNTIME_DIR=/run/user/{}", userid) as &str, @@ -536,12 +538,14 @@ fn start_pynput_service(rx: mpsc::Receiver<(PyMsg, bool)>) { } }); std::thread::spawn(move || { - for _ in 0..300 { + for i in 0..300 { std::thread::sleep(std::time::Duration::from_millis(100)); let mut conn = match std::os::unix::net::UnixStream::connect(IPC_FILE) { Ok(conn) => conn, Err(err) => { - log::error!("Failed to connect to {}: {}", IPC_FILE, err); + if i % 15 == 0 { + log::warn!("Failed to connect to {}: {}", IPC_FILE, err); + } continue; } }; diff --git a/pynput_service.py b/pynput_service.py index 9df7f974f..cec0080ee 100644 --- a/pynput_service.py +++ b/pynput_service.py @@ -1,12 +1,67 @@ from pynput.keyboard import Key, Controller from pynput.keyboard._xorg import KeyCode +from pynput._util.xorg import display_manager +import Xlib import os import sys import socket -INVALID = KeyCode._from_symbol("\0") # test +KeyCode._from_symbol("\0") # test -keyboard = Controller() +class MyController(Controller): + def _handle(self, key, is_press): + """Resolves a key identifier and sends a keyboard event. + :param event: The *X* keyboard event. + :param int keysym: The keysym to handle. + """ + event = Xlib.display.event.KeyPress if is_press \ + else Xlib.display.event.KeyRelease + keysym = self._keysym(key) + + # Make sure to verify that the key was resolved + if keysym is None: + raise self.InvalidKeyException(key) + + # If the key has a virtual key code, use that immediately with + # fake_input; fake input,being an X server extension, has access to + # more internal state that we do + if key.vk is not None: + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input( + dm, + Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, + dm.keysym_to_keycode(key.vk)) + + # Otherwise use XSendEvent; we need to use this in the general case to + # work around problems with keyboard layouts + else: + try: + keycode, shift_state = self.keyboard_mapping[keysym] + with self.modifiers as modifiers: + alt_gr = Key.alt_gr in modifiers + if alt_gr: + self._send_key(event, keycode, shift_state) + else: + with display_manager(self._display) as dm: + Xlib.ext.xtest.fake_input( + dm, + Xlib.X.KeyPress if is_press else Xlib.X.KeyRelease, + keycode) + + except KeyError: + with self._borrow_lock: + keycode, index, count = self._borrows[keysym] + self._send_key( + event, + keycode, + index_to_shift(self._display, index)) + count += 1 if is_press else -1 + self._borrows[keysym] = (keycode, index, count) + + # Notify any running listeners + self._emit('_on_fake_event', key, is_press) + +keyboard = MyController() server_address = sys.argv[1] if not os.path.exists(os.path.dirname(server_address)): @@ -52,7 +107,7 @@ def loop(): name = msg[1] else: name = KeyCode._from_symbol(msg[1:]) - if name == INVALID: + if str(name) == "<0>": continue try: if msg[0] == "p": @@ -66,3 +121,4 @@ def loop(): loop() clientsocket.close() server.close() +