From ec47c3f8947a71b6ef69b3b605656fe923aa07a3 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 25 Mar 2023 17:47:39 +0800 Subject: [PATCH 01/12] refact, keyboard lock modifiers Signed-off-by: fufesou --- src/keyboard.rs | 72 +++++++++++++++++++++++++++---- src/server/input_service.rs | 85 +++++++++++++++++++++++-------------- 2 files changed, 116 insertions(+), 41 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index ce68657ea..4c2a0a428 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -46,6 +46,35 @@ lazy_static::lazy_static! { m.insert(Key::MetaRight, false); Mutex::new(m) }; + static ref NUMPAD_POSITION_CODES: Arc> = { + let numpad_keys = [ + rdev::Key::KpMinus, + rdev::Key::KpPlus, + rdev::Key::KpMultiply, + rdev::Key::KpDivide, + rdev::Key::KpDecimal, + rdev::Key::KpReturn, + rdev::Key::KpEqual, + rdev::Key::KpComma, + rdev::Key::Kp0, + rdev::Key::Kp1, + rdev::Key::Kp2, + rdev::Key::Kp3, + rdev::Key::Kp4, + rdev::Key::Kp5, + rdev::Key::Kp6, + rdev::Key::Kp7, + rdev::Key::Kp8, + rdev::Key::Kp9, + ]; + #[cfg(target_os = "windows")] + let codes = numpad_keys.iter().filter_map(|k| rdev::win_scancode_from_key(*k)).collect(); + #[cfg(target_os = "linux")] + let codes = numpad_keys.iter().filter_map(|k| rdev::linux_code_from_keycode(*k)).collect(); + #[cfg(target_os = "macos")] + let codes = numpad_keys.iter().filter_map(|k| rdev::macos_code_from_keycode(*k)).collect(); + Arc::new(codes) + }; } pub mod client { @@ -333,19 +362,43 @@ pub fn get_keyboard_mode_enum() -> KeyboardMode { match client::get_keyboard_mode().as_str() { "map" => KeyboardMode::Map, "translate" => KeyboardMode::Translate, - _ => KeyboardMode::Legacy, + "legacy" => KeyboardMode::Legacy, + _ => { + // Set "map" as default mode if version > 1.2.0. + let mut is_peer_version_gt_1_2_0 = false; + + #[cfg(not(any(feature = "flutter", feature = "cli")))] + if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() { + is_peer_version_gt_1_2_0 = + session.get_peer_version() > hbb_common::get_version_number("1.2.0"); + } + #[cfg(feature = "flutter")] + if let Some(session) = SESSIONS + .read() + .unwrap() + .get(&*CUR_SESSION_ID.read().unwrap()) + { + is_peer_version_gt_1_2_0 = + session.get_peer_version() > hbb_common::get_version_number("1.2.0"); + } + if is_peer_version_gt_1_2_0 { + KeyboardMode::Map + } else { + KeyboardMode::Legacy + } + } } } #[cfg(not(any(target_os = "android", target_os = "ios")))] -fn add_numlock_capslock_with_lock_modes(key_event: &mut KeyEvent, lock_modes: i32) { +fn parse_add_lock_modes_modifiers(key_event: &mut KeyEvent, lock_modes: i32, is_numpad_key: bool) { const CAPS_LOCK: i32 = 1; const NUM_LOCK: i32 = 2; // const SCROLL_LOCK: i32 = 3; - if lock_modes & (1 << CAPS_LOCK) != 0 { + if !is_numpad_key && (lock_modes & (1 << CAPS_LOCK) != 0) { key_event.modifiers.push(ControlKey::CapsLock.into()); } - if lock_modes & (1 << NUM_LOCK) != 0 { + if is_numpad_key && (lock_modes & (1 << NUM_LOCK) != 0) { key_event.modifiers.push(ControlKey::NumLock.into()); } // if lock_modes & (1 << SCROLL_LOCK) != 0 { @@ -354,11 +407,11 @@ fn add_numlock_capslock_with_lock_modes(key_event: &mut KeyEvent, lock_modes: i3 } #[cfg(not(any(target_os = "android", target_os = "ios")))] -fn add_numlock_capslock_status(key_event: &mut KeyEvent) { - if get_key_state(enigo::Key::CapsLock) { +fn add_lock_modes_modifiers(key_event: &mut KeyEvent, is_numpad_key: bool) { + if !is_numpad_key && get_key_state(enigo::Key::CapsLock) { key_event.modifiers.push(ControlKey::CapsLock.into()); } - if get_key_state(enigo::Key::NumLock) { + if is_numpad_key && get_key_state(enigo::Key::NumLock) { key_event.modifiers.push(ControlKey::NumLock.into()); } } @@ -443,12 +496,13 @@ pub fn event_to_key_events( }; if keyboard_mode != KeyboardMode::Translate { + let is_numpad_key = NUMPAD_POSITION_CODES.contains(&event.position_code); for key_event in &mut key_events { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Some(lock_modes) = lock_modes { - add_numlock_capslock_with_lock_modes(key_event, lock_modes); + parse_add_lock_modes_modifiers(key_event, lock_modes, is_numpad_key); } else { - add_numlock_capslock_status(key_event); + add_lock_modes_modifiers(key_event, is_numpad_key); } } } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index bb9ba167c..178b26de2 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -113,6 +113,52 @@ impl Subscriber for MouseCursorSub { } } +struct LockModesHandler { + caps_lock_changed: bool, + num_lock_changed: bool, +} + +impl LockModesHandler { + fn new(key_event: &KeyEvent) -> Self { + let mut en = ENIGO.lock().unwrap(); + + let event_caps_enabled = key_event.modifiers.contains(&ControlKey::CapsLock.into()); + let local_caps_enabled = en.get_key_state(enigo::Key::CapsLock); + let caps_lock_changed = event_caps_enabled != local_caps_enabled; + if caps_lock_changed { + click_capslock(&mut en); + } + + let event_num_enabled = key_event.modifiers.contains(&ControlKey::NumLock.into()); + let local_num_enabled = en.get_key_state(enigo::Key::NumLock); + #[cfg(not(target_os = "windows"))] + let disable_numlock = false; + #[cfg(target_os = "windows")] + let disable_numlock = is_numlock_disabled(key_event); + let num_lock_changed = event_num_enabled != local_num_enabled && !disable_numlock; + if num_lock_changed { + click_numlock(&mut en); + } + + Self { + caps_lock_changed, + num_lock_changed, + } + } +} + +impl Drop for LockModesHandler { + fn drop(&mut self) { + let mut en = ENIGO.lock().unwrap(); + if self.caps_lock_changed { + click_capslock(&mut en); + } + if self.num_lock_changed { + click_numlock(&mut en); + } + } +} + pub const NAME_CURSOR: &'static str = "mouse_cursor"; pub const NAME_POS: &'static str = "mouse_pos"; pub type MouseCursorService = ServiceTmpl; @@ -850,10 +896,6 @@ fn char_value_to_key(value: u32) -> Key { Key::Layout(std::char::from_u32(value).unwrap_or('\0')) } -fn is_not_same_status(client_locking: bool, remote_locking: bool) -> bool { - client_locking != remote_locking -} - #[cfg(target_os = "windows")] fn has_numpad_key(key_event: &KeyEvent) -> bool { key_event @@ -900,37 +942,13 @@ fn click_capslock(en: &mut Enigo) { let _ = en.key_down(enigo::Key::CapsLock); } +#[inline] fn click_numlock(_en: &mut Enigo) { // without numlock in macos #[cfg(not(target_os = "macos"))] _en.key_click(enigo::Key::NumLock); } -fn sync_numlock_capslock_status(key_event: &KeyEvent) { - let mut en = ENIGO.lock().unwrap(); - - let client_caps_locking = is_modifier_in_key_event(ControlKey::CapsLock, key_event); - let client_num_locking = is_modifier_in_key_event(ControlKey::NumLock, key_event); - let remote_caps_locking = en.get_key_state(enigo::Key::CapsLock); - let remote_num_locking = en.get_key_state(enigo::Key::NumLock); - - let need_click_capslock = is_not_same_status(client_caps_locking, remote_caps_locking); - let need_click_numlock = is_not_same_status(client_num_locking, remote_num_locking); - - #[cfg(not(target_os = "windows"))] - let disable_numlock = false; - #[cfg(target_os = "windows")] - let disable_numlock = is_numlock_disabled(key_event); - - if need_click_capslock { - click_capslock(&mut en); - } - - if need_click_numlock && !disable_numlock { - click_numlock(&mut en); - } -} - fn map_keyboard_mode(evt: &KeyEvent) { #[cfg(windows)] crate::platform::windows::try_change_desktop(); @@ -1174,9 +1192,12 @@ pub fn handle_key_(evt: &KeyEvent) { return; } - if evt.down { - sync_numlock_capslock_status(evt) - } + let lock_mode_handler = if evt.down { + Some(LockModesHandler::new(&evt)) + } else { + None + }; + match evt.mode.unwrap() { KeyboardMode::Map => { map_keyboard_mode(evt); From fa272273a4f953bf181b6bf3d1c42e1e98670013 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 25 Mar 2023 18:03:46 +0800 Subject: [PATCH 02/12] build Signed-off-by: fufesou --- src/keyboard.rs | 4 ++-- src/server/input_service.rs | 10 +--------- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 4c2a0a428..9c90a8ae3 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -70,9 +70,9 @@ lazy_static::lazy_static! { #[cfg(target_os = "windows")] let codes = numpad_keys.iter().filter_map(|k| rdev::win_scancode_from_key(*k)).collect(); #[cfg(target_os = "linux")] - let codes = numpad_keys.iter().filter_map(|k| rdev::linux_code_from_keycode(*k)).collect(); + let codes = numpad_keys.iter().filter_map(|k| rdev::linux_code_from_code(*k)).collect(); #[cfg(target_os = "macos")] - let codes = numpad_keys.iter().filter_map(|k| rdev::macos_code_from_keycode(*k)).collect(); + let codes = numpad_keys.iter().filter_map(|k| rdev::macos_code_from_code(*k)).collect(); Arc::new(codes) }; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 178b26de2..524e76cea 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -878,14 +878,6 @@ fn simulate_(event_type: &EventType) { } } -fn is_modifier_in_key_event(control_key: ControlKey, key_event: &KeyEvent) -> bool { - key_event - .modifiers - .iter() - .position(|&m| m == control_key.into()) - .is_some() -} - #[inline] fn control_key_value_to_key(value: i32) -> Option { KEY_MAP.get(&value).and_then(|k| Some(*k)) @@ -1192,7 +1184,7 @@ pub fn handle_key_(evt: &KeyEvent) { return; } - let lock_mode_handler = if evt.down { + let _lock_mode_handler = if evt.down { Some(LockModesHandler::new(&evt)) } else { None From c0188c8e073c97dabef8c3ae6bb3cd3592c30bcc Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 25 Mar 2023 18:23:57 +0800 Subject: [PATCH 03/12] debug done Signed-off-by: fufesou --- src/keyboard.rs | 6 ++++-- src/server/input_service.rs | 16 ++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 9c90a8ae3..aaddc9e4f 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -70,9 +70,9 @@ lazy_static::lazy_static! { #[cfg(target_os = "windows")] let codes = numpad_keys.iter().filter_map(|k| rdev::win_scancode_from_key(*k)).collect(); #[cfg(target_os = "linux")] - let codes = numpad_keys.iter().filter_map(|k| rdev::linux_code_from_code(*k)).collect(); + let codes = numpad_keys.iter().filter_map(|k| rdev::linux_keycode_from_key(*k)).collect(); #[cfg(target_os = "macos")] - let codes = numpad_keys.iter().filter_map(|k| rdev::macos_code_from_code(*k)).collect(); + let codes = numpad_keys.iter().filter_map(|k| rdev::macos_keycode_from_key(*k)).collect(); Arc::new(codes) }; } @@ -905,6 +905,8 @@ fn is_altgr(event: &Event) -> bool { } } +#[inline] +#[cfg(any(target_os = "linux", target_os = "windows"))] fn is_press(event: &Event) -> bool { matches!(event.event_type, EventType::KeyPress(_)) } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 524e76cea..e9ffa3b3e 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -1184,20 +1184,24 @@ pub fn handle_key_(evt: &KeyEvent) { return; } - let _lock_mode_handler = if evt.down { - Some(LockModesHandler::new(&evt)) - } else { - None - }; - match evt.mode.unwrap() { KeyboardMode::Map => { + let _lock_mode_handler = if evt.down { + Some(LockModesHandler::new(&evt)) + } else { + None + }; map_keyboard_mode(evt); } KeyboardMode::Translate => { translate_keyboard_mode(evt); } _ => { + let _lock_mode_handler = if evt.down { + Some(LockModesHandler::new(&evt)) + } else { + None + }; legacy_keyboard_mode(evt); } } From d0881cee10b11b715b27abaab28ef2eb110632f8 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 25 Mar 2023 18:37:05 +0800 Subject: [PATCH 04/12] debug Signed-off-by: fufesou --- src/server/input_service.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index e9ffa3b3e..dad98230d 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -1184,24 +1184,27 @@ pub fn handle_key_(evt: &KeyEvent) { return; } - match evt.mode.unwrap() { - KeyboardMode::Map => { - let _lock_mode_handler = if evt.down { + let _lock_mode_handler = match &evt.union { + Some(key_event::Union::Unicode(..)) | Some(key_event::Union::Seq(..)) => { + Some(LockModesHandler::new(&evt)) + }, + _ => { + if evt.down { Some(LockModesHandler::new(&evt)) } else { None - }; + } + } + }; + + match evt.mode.unwrap() { + KeyboardMode::Map => { map_keyboard_mode(evt); } KeyboardMode::Translate => { translate_keyboard_mode(evt); } _ => { - let _lock_mode_handler = if evt.down { - Some(LockModesHandler::new(&evt)) - } else { - None - }; legacy_keyboard_mode(evt); } } From f1e0d647321279395fca0189380ce7342bbd275d Mon Sep 17 00:00:00 2001 From: fufesou Date: Sat, 25 Mar 2023 23:44:20 +0800 Subject: [PATCH 05/12] refact, sync lock modifiers, macOS, not debug yet Signed-off-by: fufesou --- Cargo.lock | 2 +- src/keyboard.rs | 48 +++++++++++----------- src/server/input_service.rs | 80 +++++++++++++++++++++++-------------- src/ui_session_interface.rs | 10 ++--- 4 files changed, 81 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e632114af..a33e523c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4674,7 +4674,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev#eaa35ff9af22891b4aae3a0a5e83472c16177cd8" +source = "git+https://github.com/fufesou/rdev#cd0d6ad907f8fda5cf77487bc962ef4246221d0c" dependencies = [ "cocoa", "core-foundation 0.9.3", diff --git a/src/keyboard.rs b/src/keyboard.rs index aaddc9e4f..8fec0ec3f 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -10,7 +10,7 @@ use crate::ui::CUR_SESSION; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::log; use hbb_common::message_proto::*; -use rdev::{Event, EventType, Key}; +use rdev::{Event, EventType, Key, KeyCode}; #[cfg(any(target_os = "windows", target_os = "macos"))] use std::sync::atomic::{AtomicBool, Ordering}; use std::{ @@ -46,26 +46,26 @@ lazy_static::lazy_static! { m.insert(Key::MetaRight, false); Mutex::new(m) }; - static ref NUMPAD_POSITION_CODES: Arc> = { + static ref NUMPAD_POSITION_CODES: Arc> = { let numpad_keys = [ - rdev::Key::KpMinus, - rdev::Key::KpPlus, - rdev::Key::KpMultiply, - rdev::Key::KpDivide, - rdev::Key::KpDecimal, - rdev::Key::KpReturn, - rdev::Key::KpEqual, - rdev::Key::KpComma, - rdev::Key::Kp0, - rdev::Key::Kp1, - rdev::Key::Kp2, - rdev::Key::Kp3, - rdev::Key::Kp4, - rdev::Key::Kp5, - rdev::Key::Kp6, - rdev::Key::Kp7, - rdev::Key::Kp8, - rdev::Key::Kp9, + Key::KpMinus, + Key::KpPlus, + Key::KpMultiply, + Key::KpDivide, + Key::KpDecimal, + Key::KpReturn, + Key::KpEqual, + Key::KpComma, + Key::Kp0, + Key::Kp1, + Key::Kp2, + Key::Kp3, + Key::Kp4, + Key::Kp5, + Key::Kp6, + Key::Kp7, + Key::Kp8, + Key::Kp9, ]; #[cfg(target_os = "windows")] let codes = numpad_keys.iter().filter_map(|k| rdev::win_scancode_from_key(*k)).collect(); @@ -257,7 +257,7 @@ pub fn start_grab_loop() { let mut _keyboard_mode = KeyboardMode::Map; let _scan_code = event.position_code; - let _code = event.platform_code; + let _code = event.platform_code as KeyCode; let res = if KEYBOARD_HOOKED.load(Ordering::SeqCst) { _keyboard_mode = client::process_event(&event, None); if is_press { @@ -293,7 +293,7 @@ pub fn start_grab_loop() { #[cfg(target_os = "macos")] unsafe { - if _code as u32 == rdev::kVK_Option { + if _code == rdev::kVK_Option { IS_LEFT_OPTION_DOWN = is_press; } } @@ -496,7 +496,7 @@ pub fn event_to_key_events( }; if keyboard_mode != KeyboardMode::Translate { - let is_numpad_key = NUMPAD_POSITION_CODES.contains(&event.position_code); + let is_numpad_key = NUMPAD_POSITION_CODES.contains(&(event.position_code as _)); for key_event in &mut key_events { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Some(lock_modes) = lock_modes { @@ -929,7 +929,7 @@ pub fn translate_keyboard_mode(peer: &str, event: &Event, key_event: KeyEvent) - #[cfg(target_os = "macos")] // ignore right option key - if event.platform_code as u32 == rdev::kVK_RightOption { + if event.platform_code == rdev::kVK_RightOption as u32 { return events; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index dad98230d..85271f168 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -5,7 +5,7 @@ use crate::common::IS_X11; use dispatch::Queue; use enigo::{Enigo, Key, KeyboardControllable, MouseButton, MouseControllable}; use hbb_common::{config::COMPRESS_LEVEL, get_time, protobuf::EnumOrUnknown}; -use rdev::{self, EventType, Key as RdevKey, RawKey}; +use rdev::{self, EventType, Key as RdevKey, KeyCode, RawKey}; #[cfg(target_os = "macos")] use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput}; use std::time::Duration; @@ -113,23 +113,32 @@ impl Subscriber for MouseCursorSub { } } +#[cfg(not(target_os = "macos"))] struct LockModesHandler { caps_lock_changed: bool, num_lock_changed: bool, } +#[cfg(target_os = "macos")] +struct LockModesHandler; + impl LockModesHandler { + #[inline] + fn is_modifier_enabled(key_event: &KeyEvent, modifier: ControlKey) { + key_event.modifiers.contains(&modifier.into()); + } + + #[cfg(not(target_os = "macos"))] fn new(key_event: &KeyEvent) -> Self { let mut en = ENIGO.lock().unwrap(); - - let event_caps_enabled = key_event.modifiers.contains(&ControlKey::CapsLock.into()); + let event_caps_enabled = Self::is_modifier_enabled(key_event, ControlKey::CapsLock); let local_caps_enabled = en.get_key_state(enigo::Key::CapsLock); let caps_lock_changed = event_caps_enabled != local_caps_enabled; if caps_lock_changed { - click_capslock(&mut en); + en.key_click(enigo::Key::CapsLock); } - let event_num_enabled = key_event.modifiers.contains(&ControlKey::NumLock.into()); + let event_num_enabled = Self::is_modifier_enabled(key_event, ControlKey::NumLock); let local_num_enabled = en.get_key_state(enigo::Key::NumLock); #[cfg(not(target_os = "windows"))] let disable_numlock = false; @@ -137,7 +146,7 @@ impl LockModesHandler { let disable_numlock = is_numlock_disabled(key_event); let num_lock_changed = event_num_enabled != local_num_enabled && !disable_numlock; if num_lock_changed { - click_numlock(&mut en); + en.key_click(enigo::Key::NumLock); } Self { @@ -145,16 +154,36 @@ impl LockModesHandler { num_lock_changed, } } + + #[cfg(target_os = "macos")] + fn new(key_event: &KeyEvent) -> Self { + let event_caps_enabled = Self::is_modifier_enabled(key_event, ControlKey::CapsLock); + let local_caps_enabled = VirtualInput::get_key_state( + CGEventSourceStateID::CombinedSessionState, + rdev::kVK_CapsLock, + ); + let caps_key = RdevKey::RawKey(rdev::RawKey::MacVirtualKeycode(rdev::kVK_CapsLock)); + if event_caps_enabled && !local_caps_enabled { + simulate_(&EventType::KeyPress(caps_key)); + key_sleep(); + } else if !event_caps_enabled && local_caps_enabled { + simulate_(&EventType::KeyRelease(caps_key)); + key_sleep(); + } + + Self {} + } } +#[cfg(not(target_os = "macos"))] impl Drop for LockModesHandler { fn drop(&mut self) { let mut en = ENIGO.lock().unwrap(); if self.caps_lock_changed { - click_capslock(&mut en); + en.key_click(enigo::Key::CapsLock); } if self.num_lock_changed { - click_numlock(&mut en); + en.key_click(enigo::Key::NumLock); } } } @@ -391,6 +420,12 @@ fn is_pressed(key: &Key, en: &mut Enigo) -> bool { get_modifier_state(key.clone(), en) } +#[inline] +#[cfg(target_os = "macos")] +fn key_sleep() { + std::thread::sleep(Duration::from_millis(20)); +} + #[inline] fn get_modifier_state(key: Key, en: &mut Enigo) -> bool { // https://github.com/rustdesk/rustdesk/issues/332 @@ -459,6 +494,7 @@ pub fn fix_key_down_timeout_at_exit() { log::info!("fix_key_down_timeout_at_exit"); } +#[inline] #[cfg(target_os = "linux")] pub fn clear_remapped_keycode() { ENIGO.lock().unwrap().tfc_clear_remapped(); @@ -792,7 +828,7 @@ pub fn handle_key(evt: &KeyEvent) { // having GUI, run main GUI thread, otherwise crash let evt = evt.clone(); QUEUE.exec_async(move || handle_key_(&evt)); - std::thread::sleep(Duration::from_millis(20)); + key_sleep(); return; } #[cfg(windows)] @@ -800,7 +836,7 @@ pub fn handle_key(evt: &KeyEvent) { #[cfg(not(windows))] handle_key_(evt); #[cfg(target_os = "macos")] - std::thread::sleep(Duration::from_millis(20)); + key_sleep(); } #[cfg(target_os = "macos")] @@ -822,7 +858,7 @@ pub fn reset_input_ondisconn() { } } -fn sim_rdev_rawkey_position(code: u32, keydown: bool) { +fn sim_rdev_rawkey_position(code: KeyCode, keydown: bool) { #[cfg(target_os = "windows")] let rawkey = RawKey::ScanCode(code); #[cfg(target_os = "linux")] @@ -927,20 +963,6 @@ fn is_numlock_disabled(key_event: &KeyEvent) -> bool { } } -fn click_capslock(en: &mut Enigo) { - #[cfg(not(targe_os = "macos"))] - en.key_click(enigo::Key::CapsLock); - #[cfg(target_os = "macos")] - let _ = en.key_down(enigo::Key::CapsLock); -} - -#[inline] -fn click_numlock(_en: &mut Enigo) { - // without numlock in macos - #[cfg(not(target_os = "macos"))] - _en.key_click(enigo::Key::NumLock); -} - fn map_keyboard_mode(evt: &KeyEvent) { #[cfg(windows)] crate::platform::windows::try_change_desktop(); @@ -959,7 +981,7 @@ fn map_keyboard_mode(evt: &KeyEvent) { return; } - sim_rdev_rawkey_position(evt.chr(), evt.down); + sim_rdev_rawkey_position(evt.chr() as _, evt.down); } #[cfg(target_os = "macos")] @@ -1137,7 +1159,7 @@ fn legacy_keyboard_mode(evt: &KeyEvent) { fn translate_process_code(code: u32, down: bool) { crate::platform::windows::try_change_desktop(); match code >> 16 { - 0 => sim_rdev_rawkey_position(code, down), + 0 => sim_rdev_rawkey_position(code as _, down), vk_code => sim_rdev_rawkey_virtual(vk_code, down), }; } @@ -1168,7 +1190,7 @@ fn translate_keyboard_mode(evt: &KeyEvent) { #[cfg(target_os = "windows")] translate_process_code(evt.chr(), evt.down); #[cfg(not(target_os = "windows"))] - sim_rdev_rawkey_position(evt.chr(), evt.down); + sim_rdev_rawkey_position(evt.chr() as _, evt.down); } Some(key_event::Union::Unicode(..)) => { // Do not handle unicode for now. @@ -1187,7 +1209,7 @@ pub fn handle_key_(evt: &KeyEvent) { let _lock_mode_handler = match &evt.union { Some(key_event::Union::Unicode(..)) | Some(key_event::Union::Seq(..)) => { Some(LockModesHandler::new(&evt)) - }, + } _ => { if evt.down { Some(LockModesHandler::new(&evt)) diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 8a1da6b8f..824f8befa 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -10,7 +10,7 @@ use std::time::{Duration, SystemTime}; use async_trait::async_trait; use bytes::Bytes; -use rdev::{Event, EventType::*}; +use rdev::{Event, EventType::*, KeyCode}; use uuid::Uuid; use hbb_common::config::{Config, LocalConfig, PeerConfig}; @@ -421,7 +421,7 @@ impl Session { rdev::win_scancode_from_key(key).unwrap_or_default() } "macos" => { - let key = rdev::macos_key_from_code(code); + let key = rdev::macos_key_from_code(code as _); let key = match key { rdev::Key::ControlLeft => rdev::Key::MetaLeft, rdev::Key::MetaLeft => rdev::Key::ControlLeft, @@ -429,7 +429,7 @@ impl Session { rdev::Key::MetaRight => rdev::Key::ControlLeft, _ => key, }; - rdev::macos_keycode_from_key(key).unwrap_or_default() + rdev::macos_keycode_from_key(key).unwrap_or_default() as _ } _ => { let key = rdev::linux_key_from_code(code); @@ -545,8 +545,8 @@ impl Session { if scancode < 0 || keycode < 0 { return; } - let keycode: u32 = keycode as u32; - let scancode: u32 = scancode as u32; + let keycode: KeyCode = keycode as _; + let scancode: u32 = scancode as _; #[cfg(not(target_os = "windows"))] let key = rdev::key_from_code(keycode) as rdev::Key; From 8b4370773dad53b96cba64460cd4516eb24b31c8 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 00:02:04 +0800 Subject: [PATCH 06/12] debug, macOS Signed-off-by: fufesou --- src/server/input_service.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 85271f168..902cd3998 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -124,8 +124,8 @@ struct LockModesHandler; impl LockModesHandler { #[inline] - fn is_modifier_enabled(key_event: &KeyEvent, modifier: ControlKey) { - key_event.modifiers.contains(&modifier.into()); + fn is_modifier_enabled(key_event: &KeyEvent, modifier: ControlKey) -> bool { + key_event.modifiers.contains(&modifier.into()) } #[cfg(not(target_os = "macos"))] From 2f7245495d02dfb2c59cbfd50b5ccf14b8ebdaa3 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 00:14:05 +0800 Subject: [PATCH 07/12] fix build Signed-off-by: fufesou --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index a33e523c2..65ae17357 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4674,7 +4674,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev#cd0d6ad907f8fda5cf77487bc962ef4246221d0c" +source = "git+https://github.com/fufesou/rdev#0dad4a59f911fe14934fefc8eed18d58cb057a81" dependencies = [ "cocoa", "core-foundation 0.9.3", From fc98b0355e674526387d8f6625f6f147c6001438 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 12:21:17 +0800 Subject: [PATCH 08/12] derive is_numpad_key from https://github.com/rustdesk/rustdesk/pull/3785/files Signed-off-by: fufesou --- src/keyboard.rs | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 8fec0ec3f..f2a6c6833 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -46,35 +46,6 @@ lazy_static::lazy_static! { m.insert(Key::MetaRight, false); Mutex::new(m) }; - static ref NUMPAD_POSITION_CODES: Arc> = { - let numpad_keys = [ - Key::KpMinus, - Key::KpPlus, - Key::KpMultiply, - Key::KpDivide, - Key::KpDecimal, - Key::KpReturn, - Key::KpEqual, - Key::KpComma, - Key::Kp0, - Key::Kp1, - Key::Kp2, - Key::Kp3, - Key::Kp4, - Key::Kp5, - Key::Kp6, - Key::Kp7, - Key::Kp8, - Key::Kp9, - ]; - #[cfg(target_os = "windows")] - let codes = numpad_keys.iter().filter_map(|k| rdev::win_scancode_from_key(*k)).collect(); - #[cfg(target_os = "linux")] - let codes = numpad_keys.iter().filter_map(|k| rdev::linux_keycode_from_key(*k)).collect(); - #[cfg(target_os = "macos")] - let codes = numpad_keys.iter().filter_map(|k| rdev::macos_keycode_from_key(*k)).collect(); - Arc::new(codes) - }; } pub mod client { @@ -390,6 +361,16 @@ pub fn get_keyboard_mode_enum() -> KeyboardMode { } } +#[inline] +fn is_numpad_key(event: &Event) -> bool { + matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if match key { + Key::Kp0 | Key::Kp1 | Key::Kp2 | Key::Kp3| Key::Kp4| Key::Kp5| Key::Kp6| + Key::Kp7| Key::Kp8| Key::Kp9 | Key::KpMinus | Key::KpMultiply | + Key::KpDivide | Key::KpPlus | Key::KpDecimal => true, + _ => false + }) +} + #[cfg(not(any(target_os = "android", target_os = "ios")))] fn parse_add_lock_modes_modifiers(key_event: &mut KeyEvent, lock_modes: i32, is_numpad_key: bool) { const CAPS_LOCK: i32 = 1; @@ -496,7 +477,7 @@ pub fn event_to_key_events( }; if keyboard_mode != KeyboardMode::Translate { - let is_numpad_key = NUMPAD_POSITION_CODES.contains(&(event.position_code as _)); + let is_numpad_key = is_numpad_key(&event.event_type); for key_event in &mut key_events { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Some(lock_modes) = lock_modes { From 1cbce779953d99abee197494624c66afde708949 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 12:22:13 +0800 Subject: [PATCH 09/12] debug macOS Signed-off-by: fufesou --- src/server/input_service.rs | 88 ++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 902cd3998..797488845 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -158,17 +158,23 @@ impl LockModesHandler { #[cfg(target_os = "macos")] fn new(key_event: &KeyEvent) -> Self { let event_caps_enabled = Self::is_modifier_enabled(key_event, ControlKey::CapsLock); - let local_caps_enabled = VirtualInput::get_key_state( - CGEventSourceStateID::CombinedSessionState, - rdev::kVK_CapsLock, - ); - let caps_key = RdevKey::RawKey(rdev::RawKey::MacVirtualKeycode(rdev::kVK_CapsLock)); + // Do not use the following code to detect `local_caps_enabled`. + // Because the state of get_key_state will not affect simuation of `VIRTUAL_INPUT_STATE` in this file. + // + // let local_caps_enabled = VirtualInput::get_key_state( + // CGEventSourceStateID::CombinedSessionState, + // rdev::kVK_CapsLock, + // ); + let local_caps_enabled = unsafe { + let _lock = VIRTUAL_INPUT_MTX.lock(); + VIRTUAL_INPUT_STATE + .as_ref() + .map_or(false, |input| input.capslock_down) + }; if event_caps_enabled && !local_caps_enabled { - simulate_(&EventType::KeyPress(caps_key)); - key_sleep(); + press_capslock(); } else if !event_caps_enabled && local_caps_enabled { - simulate_(&EventType::KeyRelease(caps_key)); - key_sleep(); + release_capslock(); } Self {} @@ -343,10 +349,33 @@ lazy_static::lazy_static! { static ref IS_SERVER: bool = std::env::args().nth(1) == Some("--server".to_owned()); } +#[cfg(target_os = "macos")] +struct VirtualInputState { + virtual_input: VirtualInput, + capslock_down: bool, +} + +#[cfg(target_os = "macos")] +impl VirtualInputState { + fn new() -> Option { + VirtualInput::new(CGEventSourceStateID::Private, CGEventTapLocation::Session) + .map(|virtual_input| Self { + virtual_input, + capslock_down: false, + }) + .ok() + } + + #[inline] + fn simulate(&self, event_type: &EventType) -> ResultType<()> { + Ok(self.virtual_input.simulate(&event_type)?) + } +} + #[cfg(target_os = "macos")] static mut VIRTUAL_INPUT_MTX: Mutex<()> = Mutex::new(()); #[cfg(target_os = "macos")] -static mut VIRTUAL_INPUT: Option = None; +static mut VIRTUAL_INPUT_STATE: Option = None; // First call set_uinput() will create keyboard and mouse clients. // The clients are ipc connections that must live shorter than tokio runtime. @@ -844,8 +873,7 @@ pub fn handle_key(evt: &KeyEvent) { fn reset_input() { unsafe { let _lock = VIRTUAL_INPUT_MTX.lock(); - VIRTUAL_INPUT = - VirtualInput::new(CGEventSourceStateID::Private, CGEventTapLocation::Session).ok(); + VIRTUAL_INPUT_STATE = VirtualInputState::new(); } } @@ -892,13 +920,43 @@ fn sim_rdev_rawkey_virtual(code: u32, keydown: bool) { simulate_(&event_type); } -#[cfg(target_os = "macos")] #[inline] +#[cfg(target_os = "macos")] fn simulate_(event_type: &EventType) { unsafe { let _lock = VIRTUAL_INPUT_MTX.lock(); - if let Some(virtual_input) = &VIRTUAL_INPUT { - let _ = virtual_input.simulate(&event_type); + if let Some(input) = &VIRTUAL_INPUT_STATE { + let _ = input.simulate(&event_type); + } + } +} + +#[inline] +#[cfg(target_os = "macos")] +fn press_capslock() { + let caps_key = RdevKey::RawKey(rdev::RawKey::MacVirtualKeycode(rdev::kVK_CapsLock)); + unsafe { + let _lock = VIRTUAL_INPUT_MTX.lock(); + if let Some(input) = &mut VIRTUAL_INPUT_STATE { + if input.simulate(&EventType::KeyPress(caps_key)).is_ok() { + input.capslock_down = true; + key_sleep(); + } + } + } +} + +#[cfg(target_os = "macos")] +#[inline] +fn release_capslock() { + let caps_key = RdevKey::RawKey(rdev::RawKey::MacVirtualKeycode(rdev::kVK_CapsLock)); + unsafe { + let _lock = VIRTUAL_INPUT_MTX.lock(); + if let Some(input) = &mut VIRTUAL_INPUT_STATE { + if input.simulate(&EventType::KeyRelease(caps_key)).is_ok() { + input.capslock_down = false; + key_sleep(); + } } } } From 2baf83ce2784fe44d25e3bf91983b0bc174cf9f1 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 12:27:06 +0800 Subject: [PATCH 10/12] fix build Signed-off-by: fufesou --- src/keyboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index f2a6c6833..0cd435cb4 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -477,7 +477,7 @@ pub fn event_to_key_events( }; if keyboard_mode != KeyboardMode::Translate { - let is_numpad_key = is_numpad_key(&event.event_type); + let is_numpad_key = is_numpad_key(&event); for key_event in &mut key_events { #[cfg(not(any(target_os = "android", target_os = "ios")))] if let Some(lock_modes) = lock_modes { From 83deb71ce28bfca89d9cbb75686baeb8fb40e55c Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 12:47:55 +0800 Subject: [PATCH 11/12] update rdev Signed-off-by: fufesou --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 65ae17357..6fdb513e4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4674,7 +4674,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev#0dad4a59f911fe14934fefc8eed18d58cb057a81" +source = "git+https://github.com/fufesou/rdev#89d2cb5c4bac81da4aafaedcf78af6af7c80c9d0" dependencies = [ "cocoa", "core-foundation 0.9.3", From 68eaa9f00013239962d787ce0ab8fa2304f58e01 Mon Sep 17 00:00:00 2001 From: fufesou Date: Sun, 26 Mar 2023 12:57:32 +0800 Subject: [PATCH 12/12] macOS, fix build Signed-off-by: fufesou --- src/keyboard.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 0cd435cb4..dd0fae615 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -811,7 +811,7 @@ pub fn map_keyboard_mode(peer: &str, event: &Event, mut key_event: KeyEvent) -> #[cfg(any(target_os = "android", target_os = "ios"))] let keycode = 0; - key_event.set_chr(keycode); + key_event.set_chr(keycode as _); Some(key_event) }