From 422f7b53596d9f023717fdbc0b7a29cfeb543937 Mon Sep 17 00:00:00 2001 From: asur4s Date: Tue, 13 Dec 2022 14:40:22 -0800 Subject: [PATCH 1/5] refacotr: sync status --- src/server/input_service.rs | 185 ++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 104 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 695c6f3d5..e1355785d 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -766,55 +766,92 @@ fn rdev_key_down_or_up(key: RdevKey, down_or_up: bool) { std::thread::sleep(Duration::from_millis(20)); } -fn sync_status(evt: &KeyEvent) { +fn is_modifier_in_key_event(modifier: ControlKey, key_event: &KeyEvent) -> bool { + key_event + .modifiers + .iter() + .position(|&m| m == modifier.into()) + .is_some() +} + +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 + .modifiers + .iter() + .filter(|&&ck| NUMPAD_KEY_MAP.get(&ck.value()).is_some()) + .count() + != 0 +} + +#[cfg(target_os = "windows")] +fn is_rdev_numpad_key(key_event: &KeyEvent) -> bool { + let code = key_event.chr(); + let key = rdev::get_win_key(code, 0); + match key { + RdevKey::Home + | RdevKey::UpArrow + | RdevKey::PageUp + | RdevKey::LeftArrow + | RdevKey::RightArrow + | RdevKey::End + | RdevKey::DownArrow + | RdevKey::PageDown + | RdevKey::Insert + | RdevKey::Delete => true, + _ => false, + } +} + +#[cfg(target_os = "windows")] +fn is_numlock_disabled(key_event: &KeyEvent) -> bool { + // disable numlock if press home etc when numlock is on, + // because we will get numpad value (7,8,9 etc) if not + match key_event.mode.unwrap() { + KeyboardMode::Map => is_rdev_numpad_key(key_event), + _ => has_numpad_key(key_event), + } +} + +fn click_capslock(en: &mut Enigo) { + #[cfg(not(targe_os = "macos"))] + en.key_click(enigo::Key::CapsLock); + #[cfg(target_os = "macos")] + en.key_down(enigo::Key::CapsLock); +} + +fn click_numlock(en: &mut Enigo) { + // without numlock in macos + #[cfg(not(target_os = "macos"))] + en.key_click(enigo::Key::NumLock); +} + +fn sync_status(key_event: &KeyEvent) { let mut en = ENIGO.lock().unwrap(); - // remote caps status - let caps_locking = evt - .modifiers - .iter() - .position(|&r| r == ControlKey::CapsLock.into()) - .is_some(); - // remote numpad status - let num_locking = evt - .modifiers - .iter() - .position(|&r| r == ControlKey::NumLock.into()) - .is_some(); + 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 click_capslock = (caps_locking && !en.get_key_state(enigo::Key::CapsLock)) - || (!caps_locking && en.get_key_state(enigo::Key::CapsLock)); - let click_numlock = (num_locking && !en.get_key_state(enigo::Key::NumLock)) - || (!num_locking && en.get_key_state(enigo::Key::NumLock)); - #[cfg(windows)] - let click_numlock = { - let code = evt.chr(); - let key = rdev::get_win_key(code, 0); - match key { - RdevKey::Home - | RdevKey::UpArrow - | RdevKey::PageUp - | RdevKey::LeftArrow - | RdevKey::RightArrow - | RdevKey::End - | RdevKey::DownArrow - | RdevKey::PageDown - | RdevKey::Insert - | RdevKey::Delete => en.get_key_state(enigo::Key::NumLock), - _ => click_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); - if click_capslock { - #[cfg(not(target_os = "macos"))] - en.key_click(enigo::Key::CapsLock); - #[cfg(target_os = "macos")] - en.key_down(enigo::Key::CapsLock); + #[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 click_numlock { - #[cfg(not(target_os = "macos"))] - en.key_click(enigo::Key::NumLock); + if need_click_numlock && !disable_numlock { + click_capslock(&mut en); } } @@ -845,10 +882,7 @@ fn legacy_keyboard_mode(evt: &KeyEvent) { #[cfg(windows)] crate::platform::windows::try_change_desktop(); let mut en = ENIGO.lock().unwrap(); - // disable numlock if press home etc when numlock is on, - // because we will get numpad value (7,8,9 etc) if not - #[cfg(windows)] - let mut _disable_numlock = false; + #[cfg(target_os = "macos")] en.reset_flag(); // When long-pressed the command key, then press and release @@ -896,14 +930,6 @@ fn legacy_keyboard_mode(evt: &KeyEvent) { match evt.union { Some(key_event::Union::ControlKey(ck)) => { if let Some(key) = KEY_MAP.get(&ck.value()) { - #[cfg(windows)] - if let Some(_) = NUMPAD_KEY_MAP.get(&ck.value()) { - _disable_numlock = en.get_key_state(Key::NumLock); - if _disable_numlock { - en.key_down(Key::NumLock).ok(); - en.key_up(Key::NumLock); - } - } if evt.down { en.key_down(key.clone()).ok(); KEYS_DOWN @@ -1001,52 +1027,3 @@ async fn send_sas() -> ResultType<()> { timeout(1000, stream.send(&crate::ipc::Data::SAS)).await??; Ok(()) } - -#[cfg(test)] -mod test { - use super::*; - use rdev::{listen, Event, EventType, Key}; - use std::sync::mpsc; - - #[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(66); - evt.mode = KeyboardMode::Legacy.into(); - - evt.modifiers.push(ControlKey::CapsLock.into()); - - // 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)) - } - } - #[test] - fn test_get_key_state() { - let mut en = ENIGO.lock().unwrap(); - println!( - "[*] test_get_key_state: {:?}", - en.get_key_state(enigo::Key::NumLock) - ); - } -} From 14e21863bab561031bf0b60dcded0c0cd2633ff4 Mon Sep 17 00:00:00 2001 From: asur4s Date: Tue, 13 Dec 2022 15:33:41 -0800 Subject: [PATCH 2/5] update deps --- flutter/pubspec.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index d79ff0595..c7008dbfe 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -154,7 +154,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.2.1" charcode: dependency: transitive description: @@ -175,7 +175,7 @@ packages: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" code_builder: dependency: transitive description: @@ -623,14 +623,14 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.1.5" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" mime: dependency: transitive description: @@ -707,7 +707,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" path_drawing: dependency: transitive description: From d675bfa7e38f38ecbee738fc3da1cbc03b0ceb4e Mon Sep 17 00:00:00 2001 From: asur4s Date: Tue, 13 Dec 2022 15:40:44 -0800 Subject: [PATCH 3/5] rename: sync status && add numlock capslock --- src/keyboard.rs | 4 ++-- src/server/input_service.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index b2e19ac73..97ce37b12 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -264,7 +264,7 @@ pub fn get_keyboard_mode_enum() -> KeyboardMode { } #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub fn add_numlock_capslock_state(key_event: &mut KeyEvent) { +pub fn add_numlock_capslock_status(key_event: &mut KeyEvent) { if get_key_state(enigo::Key::CapsLock) { key_event.modifiers.push(ControlKey::CapsLock.into()); } @@ -341,7 +341,7 @@ pub fn event_to_key_event(event: &Event) -> KeyEvent { } }; #[cfg(not(any(target_os = "android", target_os = "ios")))] - add_numlock_capslock_state(&mut key_event); + add_numlock_capslock_status(&mut key_event); return key_event; } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index e1355785d..edda4416c 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -830,7 +830,7 @@ fn click_numlock(en: &mut Enigo) { en.key_click(enigo::Key::NumLock); } -fn sync_status(key_event: &KeyEvent) { +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); @@ -851,7 +851,7 @@ fn sync_status(key_event: &KeyEvent) { } if need_click_numlock && !disable_numlock { - click_capslock(&mut en); + click_numlock(&mut en); } } @@ -1001,7 +1001,7 @@ pub fn handle_key_(evt: &KeyEvent) { } if evt.down { - sync_status(evt) + sync_numlock_capslock_status(evt) } match evt.mode.unwrap() { KeyboardMode::Map => { From 11c96922784ae896b81f4c85abcb481014d06a7f Mon Sep 17 00:00:00 2001 From: asur4s Date: Wed, 14 Dec 2022 00:57:28 -0800 Subject: [PATCH 4/5] refacotor: legacy of server --- src/server/input_service.rs | 446 ++++++++++++++++++++---------------- 1 file changed, 251 insertions(+), 195 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index edda4416c..021d85732 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -280,13 +280,17 @@ pub fn mouse_move_relative(x: i32, y: i32) { en.mouse_move_relative(x, y); } -#[cfg(not(target_os = "macos"))] +#[cfg(windows)] fn modifier_sleep() { // sleep for a while, this is only for keying in rdp in peer so far - #[cfg(windows)] std::thread::sleep(std::time::Duration::from_nanos(1)); } +#[inline] +fn is_pressed(key: &Key, en: &mut Enigo) -> bool { + get_modifier_state(key.clone(), en) +} + #[inline] fn get_modifier_state(key: Key, en: &mut Enigo) -> bool { // https://github.com/rustdesk/rustdesk/issues/332 @@ -505,6 +509,7 @@ pub fn handle_mouse_(evt: &MouseEvent) { if key != &Key::CapsLock && key != &Key::NumLock { if !get_modifier_state(key.clone(), &mut en) { en.key_down(key.clone()).ok(); + #[cfg(windows)] modifier_sleep(); to_release.push(key); } @@ -643,100 +648,6 @@ pub async fn lock_screen() { super::video_service::switch_to_primary().await; } -lazy_static::lazy_static! { - static ref KEY_MAP: HashMap = - [ - (ControlKey::Alt, Key::Alt), - (ControlKey::Backspace, Key::Backspace), - (ControlKey::CapsLock, Key::CapsLock), - (ControlKey::Control, Key::Control), - (ControlKey::Delete, Key::Delete), - (ControlKey::DownArrow, Key::DownArrow), - (ControlKey::End, Key::End), - (ControlKey::Escape, Key::Escape), - (ControlKey::F1, Key::F1), - (ControlKey::F10, Key::F10), - (ControlKey::F11, Key::F11), - (ControlKey::F12, Key::F12), - (ControlKey::F2, Key::F2), - (ControlKey::F3, Key::F3), - (ControlKey::F4, Key::F4), - (ControlKey::F5, Key::F5), - (ControlKey::F6, Key::F6), - (ControlKey::F7, Key::F7), - (ControlKey::F8, Key::F8), - (ControlKey::F9, Key::F9), - (ControlKey::Home, Key::Home), - (ControlKey::LeftArrow, Key::LeftArrow), - (ControlKey::Meta, Key::Meta), - (ControlKey::Option, Key::Option), - (ControlKey::PageDown, Key::PageDown), - (ControlKey::PageUp, Key::PageUp), - (ControlKey::Return, Key::Return), - (ControlKey::RightArrow, Key::RightArrow), - (ControlKey::Shift, Key::Shift), - (ControlKey::Space, Key::Space), - (ControlKey::Tab, Key::Tab), - (ControlKey::UpArrow, Key::UpArrow), - (ControlKey::Numpad0, Key::Numpad0), - (ControlKey::Numpad1, Key::Numpad1), - (ControlKey::Numpad2, Key::Numpad2), - (ControlKey::Numpad3, Key::Numpad3), - (ControlKey::Numpad4, Key::Numpad4), - (ControlKey::Numpad5, Key::Numpad5), - (ControlKey::Numpad6, Key::Numpad6), - (ControlKey::Numpad7, Key::Numpad7), - (ControlKey::Numpad8, Key::Numpad8), - (ControlKey::Numpad9, Key::Numpad9), - (ControlKey::Cancel, Key::Cancel), - (ControlKey::Clear, Key::Clear), - (ControlKey::Menu, Key::Alt), - (ControlKey::Pause, Key::Pause), - (ControlKey::Kana, Key::Kana), - (ControlKey::Hangul, Key::Hangul), - (ControlKey::Junja, Key::Junja), - (ControlKey::Final, Key::Final), - (ControlKey::Hanja, Key::Hanja), - (ControlKey::Kanji, Key::Kanji), - (ControlKey::Convert, Key::Convert), - (ControlKey::Select, Key::Select), - (ControlKey::Print, Key::Print), - (ControlKey::Execute, Key::Execute), - (ControlKey::Snapshot, Key::Snapshot), - (ControlKey::Insert, Key::Insert), - (ControlKey::Help, Key::Help), - (ControlKey::Sleep, Key::Sleep), - (ControlKey::Separator, Key::Separator), - (ControlKey::Scroll, Key::Scroll), - (ControlKey::NumLock, Key::NumLock), - (ControlKey::RWin, Key::RWin), - (ControlKey::Apps, Key::Apps), - (ControlKey::Multiply, Key::Multiply), - (ControlKey::Add, Key::Add), - (ControlKey::Subtract, Key::Subtract), - (ControlKey::Decimal, Key::Decimal), - (ControlKey::Divide, Key::Divide), - (ControlKey::Equals, Key::Equals), - (ControlKey::NumpadEnter, Key::NumpadEnter), - (ControlKey::RAlt, Key::RightAlt), - (ControlKey::RControl, Key::RightControl), - (ControlKey::RShift, Key::RightShift), - ].iter().map(|(a, b)| (a.value(), b.clone())).collect(); - static ref NUMPAD_KEY_MAP: HashMap = - [ - (ControlKey::Home, true), - (ControlKey::UpArrow, true), - (ControlKey::PageUp, true), - (ControlKey::LeftArrow, true), - (ControlKey::RightArrow, true), - (ControlKey::End, true), - (ControlKey::DownArrow, true), - (ControlKey::PageDown, true), - (ControlKey::Insert, true), - (ControlKey::Delete, true), - ].iter().map(|(a, b)| (a.value(), b.clone())).collect(); -} - pub fn handle_key(evt: &KeyEvent) { #[cfg(target_os = "macos")] if !*IS_SERVER { @@ -766,14 +677,18 @@ fn rdev_key_down_or_up(key: RdevKey, down_or_up: bool) { std::thread::sleep(Duration::from_millis(20)); } -fn is_modifier_in_key_event(modifier: ControlKey, key_event: &KeyEvent) -> bool { +fn is_modifier_in_key_event(control_key: ControlKey, key_event: &KeyEvent) -> bool { key_event .modifiers .iter() - .position(|&m| m == modifier.into()) + .position(|&m| m == control_key.into()) .is_some() } +fn control_key_to_key(control_key: &EnumOrUnknown) -> Option<&Key> { + KEY_MAP.get(&control_key.value()) +} + fn is_not_same_status(client_locking: bool, remote_locking: bool) -> bool { client_locking != remote_locking } @@ -878,123 +793,160 @@ fn map_keyboard_mode(evt: &KeyEvent) { return; } -fn legacy_keyboard_mode(evt: &KeyEvent) { - #[cfg(windows)] - crate::platform::windows::try_change_desktop(); - let mut en = ENIGO.lock().unwrap(); - - #[cfg(target_os = "macos")] - en.reset_flag(); +#[cfg(target_os = "macos")] +fn add_flags_to_enigo(en: &mut Enigo, key_event: &KeyEvent) { // When long-pressed the command key, then press and release // the Tab key, there should be CGEventFlagCommand in the flag. - #[cfg(target_os = "macos")] + en.reset_flag(); for ck in evt.modifiers.iter() { if let Some(key) = KEY_MAP.get(&ck.value()) { en.add_flag(key); } } - #[cfg(not(target_os = "macos"))] - let mut to_release = Vec::new(); +} - if evt.down { - let ck = if let Some(key_event::Union::ControlKey(ck)) = evt.union { - ck.value() - } else { - -1 - }; - fix_modifiers(&evt.modifiers[..], &mut en, ck); - for ref ck in evt.modifiers.iter() { - if let Some(key) = KEY_MAP.get(&ck.value()) { +fn get_control_key_value(key_event: &KeyEvent) -> i32 { + if let Some(key_event::Union::ControlKey(ck)) = key_event.union { + ck.value() + } else { + -1 + } +} + +fn release_unpressed_modifiers(en: &mut Enigo, key_event: &KeyEvent) { + let ck_value = get_control_key_value(key_event); + fix_modifiers(&key_event.modifiers[..], en, ck_value); +} + +fn is_altgr_pressed(en: &mut Enigo) -> bool { + KEYS_DOWN + .lock() + .unwrap() + .get(&(ControlKey::RAlt.value() as _)) + .is_some() +} + +fn press_modifiers(en: &mut Enigo, key_event: &KeyEvent, to_release: &mut Vec) { + for ref ck in key_event.modifiers.iter() { + if let Some(key) = control_key_to_key(ck) { + if !is_pressed(key, en) { #[cfg(target_os = "linux")] - if key == &Key::Alt && !get_modifier_state(key.clone(), &mut en) { - // for AltGr on Linux - if KEYS_DOWN - .lock() - .unwrap() - .get(&(ControlKey::RAlt.value() as _)) - .is_some() - { - continue; - } - } - #[cfg(not(target_os = "macos"))] - if !get_modifier_state(key.clone(), &mut en) { - en.key_down(key.clone()).ok(); - modifier_sleep(); - to_release.push(key); + if key == &Key::Alt && is_altgr_pressed(en) { + continue; } + en.key_down(key.clone()).ok(); + to_release.push(key.clone()); + #[cfg(windows)] + modifier_sleep(); } } } +} - match evt.union { - Some(key_event::Union::ControlKey(ck)) => { - if let Some(key) = KEY_MAP.get(&ck.value()) { - if evt.down { - en.key_down(key.clone()).ok(); - KEYS_DOWN - .lock() - .unwrap() - .insert(ck.value() as _, Instant::now()); - } else { - en.key_up(key.clone()); - KEYS_DOWN.lock().unwrap().remove(&(ck.value() as _)); - } - } else if ck.value() == ControlKey::CtrlAltDel.value() { - // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. - std::thread::spawn(|| { - allow_err!(send_sas()); - }); - } else if ck.value() == ControlKey::LockScreen.value() { - lock_screen_2(); - } - } - Some(key_event::Union::Chr(chr)) => { - if evt.down { - if en.key_down(get_layout(chr)).is_ok() { - KEYS_DOWN - .lock() - .unwrap() - .insert(chr as u64 + KEY_CHAR_START, Instant::now()); - } else { - if let Ok(chr) = char::try_from(chr) { - let mut x = chr.to_string(); - if get_modifier_state(Key::Shift, &mut en) - || get_modifier_state(Key::CapsLock, &mut en) - { - x = x.to_uppercase(); - } - en.key_sequence(&x); - } - } - KEYS_DOWN - .lock() - .unwrap() - .insert(chr as u64 + KEY_CHAR_START, Instant::now()); - } else { - en.key_up(get_layout(chr)); - KEYS_DOWN - .lock() - .unwrap() - .remove(&(chr as u64 + KEY_CHAR_START)); - } - } - Some(key_event::Union::Unicode(chr)) => { - if let Ok(chr) = char::try_from(chr) { - en.key_sequence(&chr.to_string()); - } - } - Some(key_event::Union::Seq(ref seq)) => { - en.key_sequence(&seq); - } - _ => {} +fn sync_modifiers(en: &mut Enigo, key_event: &KeyEvent, to_release: &mut Vec) { + #[cfg(target_os = "macos")] + add_flag_to_enigo(&mut en, key_event); + + if key_event.down { + release_unpressed_modifiers(en, key_event); + #[cfg(not(target_os = "macos"))] + press_modifiers(en, key_event, to_release); } - #[cfg(not(target_os = "macos"))] +} + +fn process_control_key(en: &mut Enigo, ck: &EnumOrUnknown, down: bool) { + let mut key_down = KEYS_DOWN.lock().unwrap(); + + if ck.value() == ControlKey::CtrlAltDel.value() { + // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. + std::thread::spawn(|| { + allow_err!(send_sas()); + }); + } else if ck.value() == ControlKey::LockScreen.value() { + lock_screen_2(); + } else if let Some(key) = control_key_to_key(ck) { + if down { + en.key_down(key.clone()).ok(); + key_down.insert(ck.value() as _, Instant::now()); + } else { + en.key_up(key.clone()); + key_down.remove(&(ck.value() as _)); + } + } +} + +#[inline] +fn chr_to_record_chr(chr: u32) -> u64 { + chr as u64 + KEY_CHAR_START +} + +#[inline] +fn need_to_uppercase(en: &mut Enigo) -> bool { + get_modifier_state(Key::Shift, en) || get_modifier_state(Key::CapsLock, en) +} + +fn process_chr(en: &mut Enigo, chr: u32, down: bool) { + let mut key_down = KEYS_DOWN.lock().unwrap(); + let key = get_layout(chr); + let record_chr = chr_to_record_chr(chr); + + if down { + if en.key_down(key).is_ok() { + key_down.insert(record_chr, Instant::now()); + } else { + if let Ok(chr) = char::try_from(chr) { + let mut s = chr.to_string(); + if need_to_uppercase(en) { + s = s.to_uppercase(); + } + en.key_sequence(&s); + }; + } + key_down.insert(record_chr, Instant::now()); + } else { + en.key_up(key); + key_down.remove(&record_chr); + } +} + +fn process_unicode(en: &mut Enigo, chr: u32) { + if let Ok(chr) = char::try_from(chr) { + en.key_sequence(&chr.to_string()); + } +} + +fn process_seq(en: &mut Enigo, sequence: &str) { + en.key_sequence(&sequence); +} + +fn release_keys(en: &mut Enigo, to_release: &Vec) { for key in to_release { en.key_up(key.clone()); } } +fn legacy_keyboard_mode(evt: &KeyEvent) { + #[cfg(windows)] + crate::platform::windows::try_change_desktop(); + #[cfg(not(target_os = "macos"))] + let mut to_release: Vec = Vec::new(); + + let mut en = ENIGO.lock().unwrap(); + sync_modifiers(&mut en, &evt, &mut to_release); + + let down = evt.down; + match evt.union { + Some(key_event::Union::ControlKey(ck)) => process_control_key(&mut en, &ck, down), + Some(key_event::Union::Chr(chr)) => process_chr(&mut en, chr, down), + Some(key_event::Union::Unicode(chr)) => process_unicode(&mut en, chr), + Some(key_event::Union::Seq(ref seq)) => process_seq(&mut en, seq), + _ => {} + } + + #[cfg(not(target_os = "macos"))] + release_keys(&mut en, &to_release); +} + pub fn handle_key_(evt: &KeyEvent) { if EXITING.load(Ordering::SeqCst) { return; @@ -1027,3 +979,107 @@ async fn send_sas() -> ResultType<()> { timeout(1000, stream.send(&crate::ipc::Data::SAS)).await??; Ok(()) } + +lazy_static::lazy_static! { + static ref MODIFIER_MAP: HashMap = [ + (ControlKey::Alt, Key::Alt), + (ControlKey::RAlt, Key::RightAlt), + (ControlKey::Control, Key::Control), + (ControlKey::RControl, Key::RightControl), + (ControlKey::Shift, Key::Shift), + (ControlKey::RShift, Key::RightShift), + (ControlKey::Meta, Key::Meta), + (ControlKey::RWin, Key::RWin), + ].iter().map(|(a, b)| (a.value(), b.clone())).collect(); + static ref KEY_MAP: HashMap = + [ + (ControlKey::Alt, Key::Alt), + (ControlKey::Backspace, Key::Backspace), + (ControlKey::CapsLock, Key::CapsLock), + (ControlKey::Control, Key::Control), + (ControlKey::Delete, Key::Delete), + (ControlKey::DownArrow, Key::DownArrow), + (ControlKey::End, Key::End), + (ControlKey::Escape, Key::Escape), + (ControlKey::F1, Key::F1), + (ControlKey::F10, Key::F10), + (ControlKey::F11, Key::F11), + (ControlKey::F12, Key::F12), + (ControlKey::F2, Key::F2), + (ControlKey::F3, Key::F3), + (ControlKey::F4, Key::F4), + (ControlKey::F5, Key::F5), + (ControlKey::F6, Key::F6), + (ControlKey::F7, Key::F7), + (ControlKey::F8, Key::F8), + (ControlKey::F9, Key::F9), + (ControlKey::Home, Key::Home), + (ControlKey::LeftArrow, Key::LeftArrow), + (ControlKey::Meta, Key::Meta), + (ControlKey::Option, Key::Option), + (ControlKey::PageDown, Key::PageDown), + (ControlKey::PageUp, Key::PageUp), + (ControlKey::Return, Key::Return), + (ControlKey::RightArrow, Key::RightArrow), + (ControlKey::Shift, Key::Shift), + (ControlKey::Space, Key::Space), + (ControlKey::Tab, Key::Tab), + (ControlKey::UpArrow, Key::UpArrow), + (ControlKey::Numpad0, Key::Numpad0), + (ControlKey::Numpad1, Key::Numpad1), + (ControlKey::Numpad2, Key::Numpad2), + (ControlKey::Numpad3, Key::Numpad3), + (ControlKey::Numpad4, Key::Numpad4), + (ControlKey::Numpad5, Key::Numpad5), + (ControlKey::Numpad6, Key::Numpad6), + (ControlKey::Numpad7, Key::Numpad7), + (ControlKey::Numpad8, Key::Numpad8), + (ControlKey::Numpad9, Key::Numpad9), + (ControlKey::Cancel, Key::Cancel), + (ControlKey::Clear, Key::Clear), + (ControlKey::Menu, Key::Alt), + (ControlKey::Pause, Key::Pause), + (ControlKey::Kana, Key::Kana), + (ControlKey::Hangul, Key::Hangul), + (ControlKey::Junja, Key::Junja), + (ControlKey::Final, Key::Final), + (ControlKey::Hanja, Key::Hanja), + (ControlKey::Kanji, Key::Kanji), + (ControlKey::Convert, Key::Convert), + (ControlKey::Select, Key::Select), + (ControlKey::Print, Key::Print), + (ControlKey::Execute, Key::Execute), + (ControlKey::Snapshot, Key::Snapshot), + (ControlKey::Insert, Key::Insert), + (ControlKey::Help, Key::Help), + (ControlKey::Sleep, Key::Sleep), + (ControlKey::Separator, Key::Separator), + (ControlKey::Scroll, Key::Scroll), + (ControlKey::NumLock, Key::NumLock), + (ControlKey::RWin, Key::RWin), + (ControlKey::Apps, Key::Apps), + (ControlKey::Multiply, Key::Multiply), + (ControlKey::Add, Key::Add), + (ControlKey::Subtract, Key::Subtract), + (ControlKey::Decimal, Key::Decimal), + (ControlKey::Divide, Key::Divide), + (ControlKey::Equals, Key::Equals), + (ControlKey::NumpadEnter, Key::NumpadEnter), + (ControlKey::RAlt, Key::RightAlt), + (ControlKey::RControl, Key::RightControl), + (ControlKey::RShift, Key::RightShift), + ].iter().map(|(a, b)| (a.value(), b.clone())).collect(); + static ref NUMPAD_KEY_MAP: HashMap = + [ + (ControlKey::Home, true), + (ControlKey::UpArrow, true), + (ControlKey::PageUp, true), + (ControlKey::LeftArrow, true), + (ControlKey::RightArrow, true), + (ControlKey::End, true), + (ControlKey::DownArrow, true), + (ControlKey::PageDown, true), + (ControlKey::Insert, true), + (ControlKey::Delete, true), + ].iter().map(|(a, b)| (a.value(), b.clone())).collect(); +} From 39f8e2d7123b8565e738e9fa24f2270e80ba065c Mon Sep 17 00:00:00 2001 From: asur4s Date: Thu, 15 Dec 2022 03:51:50 -0800 Subject: [PATCH 5/5] refactor: release key of server --- src/server/input_service.rs | 173 +++++++++++++++++++++++------------- 1 file changed, 109 insertions(+), 64 deletions(-) diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 021d85732..66d2b0414 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -69,6 +69,7 @@ struct Input { y: i32, } +const KEY_RDEV_START: u64 = 999; const KEY_CHAR_START: u64 = 9999; #[derive(Clone, Default)] @@ -339,7 +340,7 @@ pub fn handle_mouse(evt: &MouseEvent, conn: i32) { pub fn fix_key_down_timeout_loop() { std::thread::spawn(move || loop { - std::thread::sleep(std::time::Duration::from_millis(1_000)); + std::thread::sleep(std::time::Duration::from_millis(10_000)); fix_key_down_timeout(false); }); if let Err(err) = ctrlc::set_handler(move || { @@ -360,38 +361,61 @@ pub fn fix_key_down_timeout_at_exit() { } #[inline] -fn get_layout(key: u32) -> Key { - Key::Layout(std::char::from_u32(key).unwrap_or('\0')) +fn record_key_is_control_key(record_key: u64) -> bool { + record_key < KEY_CHAR_START +} + +#[inline] +fn record_key_is_chr(record_key: u64) -> bool { + KEY_RDEV_START <= record_key && record_key < KEY_CHAR_START +} + +#[inline] +fn record_key_is_rdev_layout(record_key: u64) -> bool { + KEY_CHAR_START <= record_key +} + +#[inline] +fn record_key_to_key(record_key: u64) -> Option { + if record_key_is_control_key(record_key) { + control_key_value_to_key(record_key as _) + } else if record_key_is_chr(record_key) { + let chr: u32 = (record_key - KEY_CHAR_START) as _; + Some(char_value_to_key(chr)) + } else { + None + } +} + +#[inline] +fn release_record_key(record_key: u64) { + let func = move || { + if record_key_is_rdev_layout(record_key) { + rdev_key_down_or_up(RdevKey::Unknown((record_key - KEY_RDEV_START) as _), false); + } else if let Some(key) = record_key_to_key(record_key) { + ENIGO.lock().unwrap().key_up(key); + log::debug!("Fixed {:?} timeout", key); + } + }; + + #[cfg(target_os = "macos")] + QUEUE.exec_async(func); + #[cfg(not(target_os = "macos"))] + func(); } fn fix_key_down_timeout(force: bool) { - if KEYS_DOWN.lock().unwrap().is_empty() { + let key_down = KEYS_DOWN.lock().unwrap(); + if key_down.is_empty() { return; } - let cloned = (*KEYS_DOWN.lock().unwrap()).clone(); - for (key, value) in cloned.into_iter() { - if force || value.elapsed().as_millis() >= 360_000 { - KEYS_DOWN.lock().unwrap().remove(&key); - let key = if key < KEY_CHAR_START { - if let Some(key) = KEY_MAP.get(&(key as _)) { - Some(*key) - } else { - None - } - } else { - Some(get_layout((key - KEY_CHAR_START) as _)) - }; - if let Some(key) = key { - let func = move || { - let mut en = ENIGO.lock().unwrap(); - en.key_up(key); - log::debug!("Fixed {:?} timeout", key); - }; - #[cfg(target_os = "macos")] - QUEUE.exec_async(func); - #[cfg(not(target_os = "macos"))] - func(); - } + let cloned = (*key_down).clone(); + drop(key_down); + + for (record_key, time) in cloned.into_iter() { + if force || time.elapsed().as_millis() >= 360_000 { + record_pressed_key(record_key, false); + release_record_key(record_key); } } } @@ -685,8 +709,14 @@ fn is_modifier_in_key_event(control_key: ControlKey, key_event: &KeyEvent) -> bo .is_some() } -fn control_key_to_key(control_key: &EnumOrUnknown) -> Option<&Key> { - KEY_MAP.get(&control_key.value()) +#[inline] +fn control_key_value_to_key(value: i32) -> Option { + KEY_MAP.get(&value).and_then(|k| Some(*k)) +} + +#[inline] +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 { @@ -772,6 +802,8 @@ fn sync_numlock_capslock_status(key_event: &KeyEvent) { fn map_keyboard_mode(evt: &KeyEvent) { // map mode(1): Send keycode according to the peer platform. + record_pressed_key(evt.chr() as u64 + KEY_CHAR_START, evt.down); + #[cfg(windows)] crate::platform::windows::try_change_desktop(); @@ -798,7 +830,7 @@ fn add_flags_to_enigo(en: &mut Enigo, key_event: &KeyEvent) { // When long-pressed the command key, then press and release // the Tab key, there should be CGEventFlagCommand in the flag. en.reset_flag(); - for ck in evt.modifiers.iter() { + for ck in key_event.modifiers.iter() { if let Some(key) = KEY_MAP.get(&ck.value()) { en.add_flag(key); } @@ -818,7 +850,7 @@ fn release_unpressed_modifiers(en: &mut Enigo, key_event: &KeyEvent) { fix_modifiers(&key_event.modifiers[..], en, ck_value); } -fn is_altgr_pressed(en: &mut Enigo) -> bool { +fn is_altgr_pressed() -> bool { KEYS_DOWN .lock() .unwrap() @@ -828,10 +860,10 @@ fn is_altgr_pressed(en: &mut Enigo) -> bool { fn press_modifiers(en: &mut Enigo, key_event: &KeyEvent, to_release: &mut Vec) { for ref ck in key_event.modifiers.iter() { - if let Some(key) = control_key_to_key(ck) { - if !is_pressed(key, en) { + if let Some(key) = control_key_value_to_key(ck.value()) { + if !is_pressed(&key, en) { #[cfg(target_os = "linux")] - if key == &Key::Alt && is_altgr_pressed(en) { + if key == Key::Alt && is_altgr_pressed() { continue; } en.key_down(key.clone()).ok(); @@ -845,7 +877,7 @@ fn press_modifiers(en: &mut Enigo, key_event: &KeyEvent, to_release: &mut Vec) { #[cfg(target_os = "macos")] - add_flag_to_enigo(&mut en, key_event); + add_flags_to_enigo(en, key_event); if key_event.down { release_unpressed_modifiers(en, key_event); @@ -855,44 +887,25 @@ fn sync_modifiers(en: &mut Enigo, key_event: &KeyEvent, to_release: &mut Vec, down: bool) { - let mut key_down = KEYS_DOWN.lock().unwrap(); - - if ck.value() == ControlKey::CtrlAltDel.value() { - // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. - std::thread::spawn(|| { - allow_err!(send_sas()); - }); - } else if ck.value() == ControlKey::LockScreen.value() { - lock_screen_2(); - } else if let Some(key) = control_key_to_key(ck) { + if let Some(key) = control_key_value_to_key(ck.value()) { if down { - en.key_down(key.clone()).ok(); - key_down.insert(ck.value() as _, Instant::now()); + en.key_down(key).ok(); } else { - en.key_up(key.clone()); - key_down.remove(&(ck.value() as _)); + en.key_up(key); } } } -#[inline] -fn chr_to_record_chr(chr: u32) -> u64 { - chr as u64 + KEY_CHAR_START -} - #[inline] fn need_to_uppercase(en: &mut Enigo) -> bool { get_modifier_state(Key::Shift, en) || get_modifier_state(Key::CapsLock, en) } fn process_chr(en: &mut Enigo, chr: u32, down: bool) { - let mut key_down = KEYS_DOWN.lock().unwrap(); - let key = get_layout(chr); - let record_chr = chr_to_record_chr(chr); + let key = char_value_to_key(chr); if down { if en.key_down(key).is_ok() { - key_down.insert(record_chr, Instant::now()); } else { if let Ok(chr) = char::try_from(chr) { let mut s = chr.to_string(); @@ -902,10 +915,8 @@ fn process_chr(en: &mut Enigo, chr: u32, down: bool) { en.key_sequence(&s); }; } - key_down.insert(record_chr, Instant::now()); } else { en.key_up(key); - key_down.remove(&record_chr); } } @@ -925,10 +936,33 @@ fn release_keys(en: &mut Enigo, to_release: &Vec) { } } +fn record_pressed_key(record_key: u64, down: bool) { + let mut key_down = KEYS_DOWN.lock().unwrap(); + if down { + key_down.insert(record_key, Instant::now()); + } else { + key_down.remove(&record_key); + } +} + +fn is_function_key(ck: &EnumOrUnknown) -> bool { + let mut res = false; + if ck.value() == ControlKey::CtrlAltDel.value() { + // have to spawn new thread because send_sas is tokio_main, the caller can not be tokio_main. + std::thread::spawn(|| { + allow_err!(send_sas()); + }); + res = true; + } else if ck.value() == ControlKey::LockScreen.value() { + lock_screen_2(); + res = true; + } + return res; +} + fn legacy_keyboard_mode(evt: &KeyEvent) { #[cfg(windows)] crate::platform::windows::try_change_desktop(); - #[cfg(not(target_os = "macos"))] let mut to_release: Vec = Vec::new(); let mut en = ENIGO.lock().unwrap(); @@ -936,8 +970,19 @@ fn legacy_keyboard_mode(evt: &KeyEvent) { let down = evt.down; match evt.union { - Some(key_event::Union::ControlKey(ck)) => process_control_key(&mut en, &ck, down), - Some(key_event::Union::Chr(chr)) => process_chr(&mut en, chr, down), + Some(key_event::Union::ControlKey(ck)) => { + if is_function_key(&ck) { + return; + } + let record_key = ck.value() as u64; + record_pressed_key(record_key, down); + process_control_key(&mut en, &ck, down) + } + Some(key_event::Union::Chr(chr)) => { + let record_key = chr as u64 + KEY_CHAR_START; + record_pressed_key(record_key, down); + process_chr(&mut en, chr, down) + } Some(key_event::Union::Unicode(chr)) => process_unicode(&mut en, chr), Some(key_event::Union::Seq(ref seq)) => process_seq(&mut en, seq), _ => {}