Merge pull request #3968 from fufesou/refact/led_sync

Refact/led sync
This commit is contained in:
RustDesk 2023-04-09 20:54:08 +08:00 committed by GitHub
commit b9214efdb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 182 additions and 102 deletions

View File

@ -359,9 +359,6 @@ impl Enigo {
} }
fn key_to_keycode(&self, key: Key) -> u16 { fn key_to_keycode(&self, key: Key) -> u16 {
unsafe {
LAYOUT = std::ptr::null_mut();
}
// do not use the codes from crate winapi they're // do not use the codes from crate winapi they're
// wrongly typed with i32 instead of i16 use the // wrongly typed with i32 instead of i16 use the
// ones provided by win/keycodes.rs that are prefixed // ones provided by win/keycodes.rs that are prefixed
@ -456,6 +453,9 @@ impl Enigo {
} }
fn get_layoutdependent_keycode(&self, chr: char) -> u16 { fn get_layoutdependent_keycode(&self, chr: char) -> u16 {
unsafe {
LAYOUT = std::ptr::null_mut();
}
// NOTE VkKeyScanW uses the current keyboard LAYOUT // NOTE VkKeyScanW uses the current keyboard LAYOUT
// to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout // to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout
// or load one with LoadKeyboardLayoutW // or load one with LoadKeyboardLayoutW

View File

@ -350,6 +350,7 @@ pub fn get_keyboard_mode_enum() -> KeyboardMode {
} }
#[inline] #[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn is_modifier(key: &rdev::Key) -> bool { pub fn is_modifier(key: &rdev::Key) -> bool {
matches!( matches!(
key, key,
@ -364,26 +365,73 @@ pub fn is_modifier(key: &rdev::Key) -> bool {
) )
} }
#[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn is_numpad_rdev_key(key: &rdev::Key) -> bool {
matches!(
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
)
}
#[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub fn is_letter_rdev_key(key: &rdev::Key) -> bool {
matches!(
key,
Key::KeyA
| Key::KeyB
| Key::KeyC
| Key::KeyD
| Key::KeyE
| Key::KeyF
| Key::KeyG
| Key::KeyH
| Key::KeyI
| Key::KeyJ
| Key::KeyK
| Key::KeyL
| Key::KeyM
| Key::KeyN
| Key::KeyO
| Key::KeyP
| Key::KeyQ
| Key::KeyR
| Key::KeyS
| Key::KeyT
| Key::KeyU
| Key::KeyV
| Key::KeyW
| Key::KeyX
| Key::KeyY
| Key::KeyZ
)
}
#[inline] #[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
fn is_numpad_key(event: &Event) -> bool { fn is_numpad_key(event: &Event) -> bool {
matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if match key { matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if is_numpad_rdev_key(&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
})
} }
#[inline] #[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
fn is_letter_key(event: &Event) -> bool { fn is_letter_key(event: &Event) -> bool {
matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if match key { matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if is_letter_rdev_key(&key))
Key::KeyA | Key::KeyB | Key::KeyC | Key::KeyD | Key::KeyE | Key::KeyF | Key::KeyG | Key::KeyH |
Key::KeyI | Key::KeyJ | Key::KeyK | Key::KeyL | Key::KeyM | Key::KeyN | Key::KeyO | Key::KeyP |
Key::KeyQ | Key::KeyR | Key::KeyS | Key::KeyT | Key::KeyU | Key::KeyV | Key::KeyW | Key::KeyX |
Key::KeyY | Key::KeyZ => true,
_ => false
})
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]

View File

@ -3,8 +3,6 @@
pub mod platform; pub mod platform;
mod keyboard; mod keyboard;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use keyboard::keycode_to_rdev_key;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
pub use platform::{get_cursor, get_cursor_data, get_cursor_pos, start_os_service}; pub use platform::{get_cursor, get_cursor_data, get_cursor_pos, start_os_service};
#[cfg(not(any(target_os = "ios")))] #[cfg(not(any(target_os = "ios")))]
/// cbindgen:ignore /// cbindgen:ignore

View File

@ -8,13 +8,12 @@ use hbb_common::{config::COMPRESS_LEVEL, get_time, protobuf::EnumOrUnknown};
use rdev::{self, EventType, Key as RdevKey, KeyCode, RawKey}; use rdev::{self, EventType, Key as RdevKey, KeyCode, RawKey};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput}; use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput};
use std::time::Duration;
use std::{ use std::{
convert::TryFrom, convert::TryFrom,
ops::Sub, ops::Sub,
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
thread, thread,
time::{self, Instant}, time::{self, Duration, Instant},
}; };
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use winapi::um::winuser::{ use winapi::um::winuser::{
@ -123,7 +122,7 @@ impl Subscriber for MouseCursorSub {
} }
} }
#[cfg(not(target_os = "macos"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
struct LockModesHandler { struct LockModesHandler {
caps_lock_changed: bool, caps_lock_changed: bool,
num_lock_changed: bool, num_lock_changed: bool,
@ -138,8 +137,21 @@ impl LockModesHandler {
key_event.modifiers.contains(&modifier.into()) key_event.modifiers.contains(&modifier.into())
} }
#[cfg(not(target_os = "macos"))] #[inline]
fn new(key_event: &KeyEvent) -> Self { #[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
fn new_handler(key_event: &KeyEvent, _is_numpad_key: bool) -> Self {
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
Self::new(key_event, _is_numpad_key)
}
#[cfg(target_os = "macos")]
{
Self::new(key_event)
}
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
fn new(key_event: &KeyEvent, is_numpad_key: bool) -> Self {
let mut en = ENIGO.lock().unwrap(); let mut en = ENIGO.lock().unwrap();
let event_caps_enabled = Self::is_modifier_enabled(key_event, ControlKey::CapsLock); let event_caps_enabled = Self::is_modifier_enabled(key_event, ControlKey::CapsLock);
let local_caps_enabled = en.get_key_state(enigo::Key::CapsLock); let local_caps_enabled = en.get_key_state(enigo::Key::CapsLock);
@ -148,13 +160,18 @@ impl LockModesHandler {
en.key_click(enigo::Key::CapsLock); en.key_click(enigo::Key::CapsLock);
} }
let event_num_enabled = Self::is_modifier_enabled(key_event, ControlKey::NumLock); let mut num_lock_changed = false;
let local_num_enabled = en.get_key_state(enigo::Key::NumLock); if is_numpad_key {
#[cfg(not(target_os = "windows"))] let local_num_enabled = en.get_key_state(enigo::Key::NumLock);
let disable_numlock = false; let event_num_enabled = Self::is_modifier_enabled(key_event, ControlKey::NumLock);
#[cfg(target_os = "windows")] num_lock_changed = event_num_enabled != local_num_enabled;
let disable_numlock = is_numlock_disabled(key_event); } else if is_legacy_mode(key_event) {
let num_lock_changed = event_num_enabled != local_num_enabled && !disable_numlock; #[cfg(target_os = "windows")]
{
num_lock_changed =
should_disable_numlock(key_event) && en.get_key_state(enigo::Key::NumLock);
}
}
if num_lock_changed { if num_lock_changed {
en.key_click(enigo::Key::NumLock); en.key_click(enigo::Key::NumLock);
} }
@ -191,7 +208,7 @@ impl LockModesHandler {
} }
} }
#[cfg(not(target_os = "macos"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
impl Drop for LockModesHandler { impl Drop for LockModesHandler {
fn drop(&mut self) { fn drop(&mut self) {
let mut en = ENIGO.lock().unwrap(); let mut en = ENIGO.lock().unwrap();
@ -204,6 +221,20 @@ impl Drop for LockModesHandler {
} }
} }
#[inline]
#[cfg(target_os = "windows")]
fn should_disable_numlock(evt: &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 (&evt.union, evt.mode.enum_value_or(KeyboardMode::Legacy)) {
(Some(key_event::Union::ControlKey(ck)), KeyboardMode::Legacy) => {
return NUMPAD_KEY_MAP.contains_key(&ck.value());
}
_ => {}
}
false
}
pub const NAME_CURSOR: &'static str = "mouse_cursor"; pub const NAME_CURSOR: &'static str = "mouse_cursor";
pub const NAME_POS: &'static str = "mouse_pos"; pub const NAME_POS: &'static str = "mouse_pos";
pub type MouseCursorService = ServiceTmpl<MouseCursorSub>; pub type MouseCursorService = ServiceTmpl<MouseCursorSub>;
@ -1010,45 +1041,6 @@ fn char_value_to_key(value: u32) -> Key {
Key::Layout(std::char::from_u32(value).unwrap_or('\0')) Key::Layout(std::char::from_u32(value).unwrap_or('\0'))
} }
#[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 map_keyboard_mode(evt: &KeyEvent) { fn map_keyboard_mode(evt: &KeyEvent) {
#[cfg(windows)] #[cfg(windows)]
crate::platform::windows::try_change_desktop(); crate::platform::windows::try_change_desktop();
@ -1372,7 +1364,7 @@ fn simulate_win2win_hotkey(code: u32, down: bool) {
} }
#[cfg(not(any(target_os = "windows", target_os = "linux")))] #[cfg(not(any(target_os = "windows", target_os = "linux")))]
fn skip_led_sync_control_key(_evt: &KeyEvent) -> bool { fn skip_led_sync_control_key(_key: &ControlKey) -> bool {
false false
} }
@ -1383,37 +1375,65 @@ fn skip_led_sync_control_key(_evt: &KeyEvent) -> bool {
// https://github.com/rustdesk/rustdesk/issues/3928#issuecomment-1500773473 // https://github.com/rustdesk/rustdesk/issues/3928#issuecomment-1500773473
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
fn skip_led_sync_control_key(key: &ControlKey) -> bool { fn skip_led_sync_control_key(key: &ControlKey) -> bool {
[ matches!(
ControlKey::Control, key,
ControlKey::Meta, ControlKey::Control
ControlKey::Shift, | ControlKey::RControl
ControlKey::Alt, | ControlKey::Meta
ControlKey::Tab, | ControlKey::Shift
ControlKey::Return, | ControlKey::RShift
] | ControlKey::Alt
.contains(key) | ControlKey::RAlt
| ControlKey::Tab
| ControlKey::Return
)
}
#[inline]
#[cfg(any(target_os = "windows", target_os = "linux"))]
fn is_numpad_control_key(key: &ControlKey) -> bool {
matches!(
key,
ControlKey::Numpad0
| ControlKey::Numpad1
| ControlKey::Numpad2
| ControlKey::Numpad3
| ControlKey::Numpad4
| ControlKey::Numpad5
| ControlKey::Numpad6
| ControlKey::Numpad7
| ControlKey::Numpad8
| ControlKey::Numpad9
| ControlKey::NumpadEnter
)
} }
#[cfg(not(any(target_os = "windows", target_os = "linux")))] #[cfg(not(any(target_os = "windows", target_os = "linux")))]
fn skip_led_sync_rdev_key(_evt: &KeyEvent) -> bool { fn skip_led_sync_rdev_key(_key: &RdevKey) -> bool {
false false
} }
#[cfg(any(target_os = "windows", target_os = "linux"))] #[cfg(any(target_os = "windows", target_os = "linux"))]
fn skip_led_sync_rdev_key(key: &RdevKey) -> bool { fn skip_led_sync_rdev_key(key: &RdevKey) -> bool {
[ matches!(
RdevKey::ControlLeft, key,
RdevKey::ControlRight, RdevKey::ControlLeft
RdevKey::MetaLeft, | RdevKey::ControlRight
RdevKey::MetaRight, | RdevKey::MetaLeft
RdevKey::ShiftRight, | RdevKey::MetaRight
RdevKey::ShiftRight, | RdevKey::ShiftLeft
RdevKey::Alt, | RdevKey::ShiftRight
RdevKey::AltGr, | RdevKey::Alt
RdevKey::Tab, | RdevKey::AltGr
RdevKey::Return, | RdevKey::Tab
] | RdevKey::Return
.contains(key) )
}
#[inline]
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn is_legacy_mode(evt: &KeyEvent) -> bool {
evt.mode.enum_value_or(KeyboardMode::Legacy) == KeyboardMode::Legacy
} }
pub fn handle_key_(evt: &KeyEvent) { pub fn handle_key_(evt: &KeyEvent) {
@ -1421,21 +1441,35 @@ pub fn handle_key_(evt: &KeyEvent) {
return; return;
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let mut _lock_mode_handler = None; let mut _lock_mode_handler = None;
match (&evt.union, evt.mode.enum_value_or(KeyboardMode::Legacy)) { #[cfg(not(any(target_os = "android", target_os = "ios")))]
(Some(key_event::Union::Unicode(..)) | Some(key_event::Union::Seq(..)), _) => { match &evt.union {
_lock_mode_handler = Some(LockModesHandler::new(&evt)); Some(key_event::Union::Unicode(..)) | Some(key_event::Union::Seq(..)) => {
_lock_mode_handler = Some(LockModesHandler::new_handler(&evt, false));
} }
(Some(key_event::Union::ControlKey(ck)), _) => { Some(key_event::Union::ControlKey(ck)) => {
let key = ck.enum_value_or(ControlKey::Unknown); let key = ck.enum_value_or(ControlKey::Unknown);
if !skip_led_sync_control_key(&key) { if !skip_led_sync_control_key(&key) {
_lock_mode_handler = Some(LockModesHandler::new(&evt)); #[cfg(target_os = "macos")]
let is_numpad_key = false;
#[cfg(any(target_os = "windows", target_os = "linux"))]
let is_numpad_key = is_numpad_control_key(&key);
_lock_mode_handler = Some(LockModesHandler::new_handler(&evt, is_numpad_key));
} }
} }
(Some(key_event::Union::Chr(code)), KeyboardMode::Map | KeyboardMode::Translate) => { Some(key_event::Union::Chr(code)) => {
let key = crate::keycode_to_rdev_key(*code); if is_legacy_mode(&evt) {
if !skip_led_sync_rdev_key(&key) { _lock_mode_handler = Some(LockModesHandler::new_handler(evt, false));
_lock_mode_handler = Some(LockModesHandler::new(evt)); } else {
let key = crate::keyboard::keycode_to_rdev_key(*code);
if !skip_led_sync_rdev_key(&key) {
#[cfg(target_os = "macos")]
let is_numpad_key = false;
#[cfg(any(target_os = "windows", target_os = "linux"))]
let is_numpad_key = crate::keyboard::is_numpad_rdev_key(&key);
_lock_mode_handler = Some(LockModesHandler::new_handler(evt, is_numpad_key));
}
} }
} }
_ => {} _ => {}