From 5dab7bd9a218caf48ae2ae9f1fa63a827e19d8c1 Mon Sep 17 00:00:00 2001 From: Asura <todaymofish@gmail.com> Date: Sun, 17 Jul 2022 20:34:08 -0700 Subject: [PATCH] Refactor simulate to support switching keyboard modes --- libs/enigo/src/linux.rs | 43 +++----------- libs/enigo/src/macos/macos_impl.rs | 32 ----------- libs/enigo/src/win/win_impl.rs | 32 ----------- src/server/connection.rs | 9 +-- src/server/input_service.rs | 90 +++++++++++++++++++++++++----- 5 files changed, 84 insertions(+), 122 deletions(-) diff --git a/libs/enigo/src/linux.rs b/libs/enigo/src/linux.rs index 7f2afc3dc..67af71a62 100644 --- a/libs/enigo/src/linux.rs +++ b/libs/enigo/src/linux.rs @@ -3,7 +3,6 @@ use libc; use crate::{Key, KeyboardControllable, MouseButton, MouseControllable}; use self::libc::{c_char, c_int, c_void, useconds_t}; -use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError}; use std::{borrow::Cow, ffi::CString, io::prelude::*, ptr, sync::mpsc, thread, time}; const CURRENT_WINDOW: c_int = 0; const DEFAULT_DELAY: u64 = 12000; @@ -104,27 +103,7 @@ impl Enigo { self.tx.send((PyMsg::Char('\0'), true)).ok(); } - fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool { - if let Key::Raw(keycode) = key { - let event_type = match is_press { - // todo: Acccodding to client type - true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown( - (*keycode).into(), - )))), - false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown( - (*keycode).into(), - )))), - }; - - match simulate(event_type) { - Ok(()) => true, - Err(SimulateError) => false, - } - } else { - false - } - } - + #[inline] fn send_pynput(&mut self, key: &Key, is_press: bool) -> bool { if unsafe { PYNPUT_EXIT || !PYNPUT_REDAY } { @@ -459,12 +438,9 @@ impl KeyboardControllable for Enigo { if self.xdo.is_null() { return Ok(()); } - if self.send_rdev(&key, true) { - return Ok(()); - } - if self.send_pynput(&key, true) { - return Ok(()); - } + // if self.send_pynput(&key, true) { + // return Ok(()); + // } let string = CString::new(&*keysequence(key))?; unsafe { xdo_send_keysequence_window_down( @@ -480,14 +456,9 @@ impl KeyboardControllable for Enigo { if self.xdo.is_null() { return; } - // todo - let keyboard_mode = 1; - if keyboard_mode == 1 && self.send_rdev(&key, false) { - return; - } - if self.send_pynput(&key, false) { - return; - } + // if self.send_pynput(&key, false) { + // return; + // } if let Ok(string) = CString::new(&*keysequence(key)) { unsafe { xdo_send_keysequence_window_up( diff --git a/libs/enigo/src/macos/macos_impl.rs b/libs/enigo/src/macos/macos_impl.rs index df494b9cb..520c9dca1 100644 --- a/libs/enigo/src/macos/macos_impl.rs +++ b/libs/enigo/src/macos/macos_impl.rs @@ -1,5 +1,4 @@ use core_graphics; -use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError}; // TODO(dustin): use only the things i need use self::core_graphics::display::*; @@ -354,11 +353,6 @@ impl KeyboardControllable for Enigo { } fn key_down(&mut self, key: Key) -> crate::ResultType { - let keyboard_mode = 1; - if keyboard_mode == 1 { - self.send_rdev(&key, true); - return Ok(()); - }; let code = self.key_to_keycode(key); if code == u16::MAX { return Err("".into()); @@ -374,11 +368,6 @@ impl KeyboardControllable for Enigo { } fn key_up(&mut self, key: Key) { - let keyboard_mode = 1; - if keyboard_mode == 1 { - self.send_rdev(&key, true); - return Ok(()); - }; if let Some(src) = self.event_source.as_ref() { if let Ok(event) = CGEvent::new_keyboard_event(src.clone(), self.key_to_keycode(key), false) @@ -431,27 +420,6 @@ impl Enigo { (x, (display_height as i32) - y_inv) } - fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool { - if let Key::Raw(keycode) = key { - let event_type = match is_press { - // todo: Acccodding to client type - true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown( - (*keycode).into(), - )))), - false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown( - (*keycode).into(), - )))), - }; - - match simulate(event_type) { - Ok(()) => true, - Err(SimulateError) => false, - } - } else { - false - } - } - fn key_to_keycode(&mut self, key: Key) -> CGKeyCode { #[allow(deprecated)] // I mean duh, we still need to support deprecated keys until they're removed diff --git a/libs/enigo/src/win/win_impl.rs b/libs/enigo/src/win/win_impl.rs index b8f3d0fa3..56fc4caef 100644 --- a/libs/enigo/src/win/win_impl.rs +++ b/libs/enigo/src/win/win_impl.rs @@ -2,7 +2,6 @@ use self::winapi::ctypes::c_int; use self::winapi::shared::{basetsd::ULONG_PTR, minwindef::*, windef::*}; use self::winapi::um::winbase::*; use self::winapi::um::winuser::*; -use rdev::{simulate, EventType, Key as RdevKey, SimulateError}; use winapi; use crate::win::keycodes::*; @@ -198,11 +197,6 @@ impl KeyboardControllable for Enigo { } fn key_down(&mut self, key: Key) -> crate::ResultType { - let keyboard_mode = 1; - if keyboard_mode == 1 { - self.send_rdev(&key, true); - return Ok(()); - }; let code = self.key_to_keycode(key); if code == 0 || code == 65535 { return Err("".into()); @@ -218,11 +212,6 @@ impl KeyboardControllable for Enigo { } fn key_up(&mut self, key: Key) { - let keyboard_mode = 1; - if keyboard_mode == 1 { - self.send_rdev(&key, false); - return; - }; keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0); } @@ -283,27 +272,6 @@ impl Enigo { keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char); } - fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool { - if let Key::Raw(keycode) = key { - let event_type = match is_press { - // todo: Acccodding to client type - true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown( - (*keycode).into(), - )))), - false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown( - (*keycode).into(), - )))), - }; - - match simulate(event_type) { - Ok(()) => true, - Err(SimulateError) => false, - } - } else { - false - } - } - fn key_to_keycode(&self, key: Key) -> u16 { unsafe { LAYOUT = std::ptr::null_mut(); diff --git a/src/server/connection.rs b/src/server/connection.rs index 682c7d928..48fab0c2d 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -419,15 +419,8 @@ impl Connection { handle_mouse(&msg, id); } MessageInput::Key((mut msg, press)) => { - if press { - msg.down = true; - } + // todo: press and down have similar meanings. handle_key(&msg); - let keyboard_mode = 1; - if press && keyboard_mode != 1{ - msg.down = false; - handle_key(&msg); - } } MessageInput::BlockOn => { if crate::platform::block_input(true) { diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 8e8e2abb4..f041b7e86 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -3,6 +3,7 @@ use super::*; use dispatch::Queue; use enigo::{Enigo, Key, KeyboardControllable, MouseButton, MouseControllable}; use hbb_common::{config::COMPRESS_LEVEL, protobuf::ProtobufEnumOrUnknown}; +use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError}; use std::{ convert::TryFrom, sync::atomic::{AtomicBool, Ordering}, @@ -578,24 +579,27 @@ pub fn handle_key(evt: &KeyEvent) { handle_key_(evt); } -fn handle_key_(evt: &KeyEvent) { - if EXITING.load(Ordering::SeqCst) { - return; +fn map_keyboard_map(evt: &KeyEvent) { + // map mode(1): Send keycode according to the peer platform. + let event_type = match evt.down { + true => EventType::KeyPress(RdevKey::Unknown(evt.get_chr())), + false => EventType::KeyRelease(RdevKey::Unknown(evt.get_chr())), + }; + + match simulate(&event_type) { + Ok(()) => (), + Err(_simulate_error) => { + // todo + log::error!("rdev could not send {:?}", event_type); + } } + return; +} + +fn legacy_keyboard_map(evt: &KeyEvent) { #[cfg(windows)] crate::platform::windows::try_change_desktop(); let mut en = ENIGO.lock().unwrap(); - let keyboard_mode = 1; - if keyboard_mode == 1 { - if let Some(key_event::Union::chr(chr)) = evt.union { - if evt.down { - en.key_down(Key::Raw(chr.try_into().unwrap())); - } else { - en.key_up(Key::Raw(chr.try_into().unwrap())); - } - } - return; - } // disable numlock if press home etc when numlock is on, // because we will get numpad value (7,8,9 etc) if not #[cfg(windows)] @@ -740,9 +744,67 @@ fn handle_key_(evt: &KeyEvent) { } } +fn handle_key_(evt: &KeyEvent) { + if EXITING.load(Ordering::SeqCst) { + return; + } + + match evt.mode { + 1 => { + map_keyboard_map(evt); + } + 3 => { + legacy_keyboard_map(evt); + } + _ => { + map_keyboard_map(evt); + } + } +} + #[tokio::main(flavor = "current_thread")] async fn send_sas() -> ResultType<()> { let mut stream = crate::ipc::connect(1000, crate::POSTFIX_SERVICE).await?; timeout(1000, stream.send(&crate::ipc::Data::SAS)).await??; Ok(()) } + +#[cfg(test)] +mod test { + use super::*; + use rdev::{listen, simulate, Event, EventType, Key}; + use std::sync::mpsc; + use std::thread; + + #[test] + fn test_handle_key() { + // listen + let (tx, rx) = mpsc::channel(); + std::thread::spawn(move || { + std::env::set_var("KEYBOARD_ONLY", "y"); + let func = move |event: Event| { + tx.send(event).ok(); + }; + if let Err(error) = listen(func) { + println!("Error: {:?}", error); + } + }); + // set key/char base on char + let mut evt = KeyEvent::new(); + evt.set_chr(49); + evt.mode = 3; + + // press + evt.down = true; + handle_key(&evt); + if let Ok(listen_evt) = rx.recv() { + assert_eq!(listen_evt.event_type, EventType::KeyPress(Key::Num1)) + } + // release + evt.down = false; + handle_key(&evt); + if let Ok(listen_evt) = rx.recv() { + assert_eq!(listen_evt.event_type, EventType::KeyRelease(Key::Num1)) + } + } +}