diff --git a/Cargo.lock b/Cargo.lock index f40582eb7..2b220c15d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4305,7 +4305,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/asur4s/rdev#3d6d413a9b2ab703edc22071acea31826b0efce3" +source = "git+https://github.com/asur4s/rdev#18bb9dd64563fc9761005bb39ff830e6402e326e" dependencies = [ "cocoa", "core-foundation 0.9.3", @@ -4316,6 +4316,7 @@ dependencies = [ "inotify", "lazy_static", "libc", + "log", "mio 0.8.5", "strum 0.24.1", "strum_macros 0.24.3", diff --git a/src/keyboard.rs b/src/keyboard.rs index 99e1c1455..df052ebbc 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -7,19 +7,19 @@ use crate::flutter::FlutterHandler; use crate::ui::remote::SciterHandler; use crate::ui_session_interface::Session; use hbb_common::{log, message_proto::*}; -#[cfg(target_os = "linux")] -use rdev::GrabError; use rdev::{Event, EventType, Key}; +#[cfg(any(target_os = "windows", target_os = "macos"))] +use std::sync::atomic::{AtomicBool, Ordering}; use std::{ collections::{HashMap, HashSet}, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, Mutex, - }, + sync::{Arc, Mutex}, time::SystemTime, }; +#[cfg(windows)] static mut IS_ALT_GR: bool = false; + +#[cfg(any(target_os = "windows", target_os = "macos"))] static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false); #[cfg(feature = "flutter")] @@ -103,8 +103,9 @@ pub mod client { if is_long_press(&event) { return; } - let key_event = event_to_key_event(&event); - send_key_event(&key_event); + if let Some(key_event) = event_to_key_event(&event) { + send_key_event(&key_event); + } } pub fn get_modifiers_state( @@ -314,7 +315,7 @@ fn update_modifiers_state(event: &Event) { }; } -pub fn event_to_key_event(event: &Event) -> KeyEvent { +pub fn event_to_key_event(event: &Event) -> Option { let mut key_event = KeyEvent::new(); update_modifiers_state(event); @@ -330,22 +331,22 @@ pub fn event_to_key_event(event: &Event) -> KeyEvent { let keyboard_mode = get_keyboard_mode_enum(); key_event.mode = keyboard_mode.into(); - match keyboard_mode { + let mut key_event = match keyboard_mode { KeyboardMode::Map => { - map_keyboard_mode(event, &mut key_event); + map_keyboard_mode(event, key_event)? } KeyboardMode::Translate => { - translate_keyboard_mode(event, &mut key_event); + translate_keyboard_mode(event, key_event)? } _ => { #[cfg(not(any(target_os = "android", target_os = "ios")))] - legacy_keyboard_mode(event, &mut key_event); + legacy_keyboard_mode(event, key_event)? } }; #[cfg(not(any(target_os = "android", target_os = "ios")))] add_numlock_capslock_status(&mut key_event); - return key_event; + return Some(key_event); } pub fn event_type_to_event(event_type: EventType) -> Event { @@ -374,15 +375,15 @@ pub fn get_peer_platform() -> String { } #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub fn legacy_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { +pub fn legacy_keyboard_mode(event: &Event, mut key_event: KeyEvent) -> Option { // legacy mode(0): Generate characters locally, look for keycode on other side. let (mut key, down_or_up) = match event.event_type { EventType::KeyPress(key) => (key, true), EventType::KeyRelease(key) => (key, false), _ => { - return; + return None; } - }; + }; let peer = get_peer_platform(); let is_win = peer == "Windows"; @@ -422,11 +423,11 @@ pub fn legacy_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { // when pressing AltGr, an extra VK_LCONTROL with a special // scancode with bit 9 set is sent, let's ignore this. #[cfg(windows)] - if event.scan_code & 0x200 != 0 { + if (event.scan_code >> 8) == 0xE0 { unsafe { IS_ALT_GR = true; } - return; + return None; } Some(ControlKey::Control) } @@ -458,7 +459,7 @@ pub fn legacy_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { Key::Delete => { if is_win && ctrl && alt { client::ctrl_alt_del(); - return; + return None; } Some(ControlKey::Delete) } @@ -496,7 +497,7 @@ pub fn legacy_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { Key::KpMinus => Some(ControlKey::Subtract), Key::KpPlus => Some(ControlKey::Add), Key::CapsLock | Key::NumLock | Key::ScrollLock => { - return; + return None; } Key::Home => Some(ControlKey::Home), Key::End => Some(ControlKey::End), @@ -579,43 +580,60 @@ pub fn legacy_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { if chr != '\0' { if chr == 'l' && is_win && command { client::lock_screen(); - return; + return None; } key_event.set_chr(chr as _); } else { log::error!("Unknown key {:?}", &event); - return; + return None; } } let (alt, ctrl, shift, command) = client::get_modifiers_state(alt, ctrl, shift, command); - client::legacy_modifiers(key_event, alt, ctrl, shift, command); + client::legacy_modifiers(&mut key_event, alt, ctrl, shift, command); if down_or_up == true { key_event.down = true; } + Some(key_event) } -pub fn map_keyboard_mode(event: &Event, key_event: &mut KeyEvent) { +pub fn map_keyboard_mode(event: &Event, mut key_event: KeyEvent) -> Option { + match event.event_type { + EventType::KeyPress(..) => { + key_event.down = true; + } + EventType::KeyRelease(..) => { + key_event.down = false; + } + _ => return None, + }; + let mut peer = get_peer_platform().to_lowercase(); peer.retain(|c| !c.is_whitespace()); - let key = match event.event_type { - EventType::KeyPress(key) => { - key_event.down = true; - key - } - EventType::KeyRelease(key) => { - key_event.down = false; - key - } - _ => return, + #[cfg(target_os = "windows")] + let keycode = match peer.as_str() { + "windows" => event.scan_code, + "macos" => rdev::win_scancode_to_macos_code(event.scan_code)?, + _ => rdev::win_scancode_to_linux_code(event.scan_code)?, }; - let keycode: u32 = match peer.as_str() { - "windows" => rdev::win_keycode_from_key(key).unwrap_or_default().into(), - "macos" => rdev::macos_keycode_from_key(key).unwrap_or_default().into(), - _ => rdev::linux_keycode_from_key(key).unwrap_or_default().into(), + #[cfg(target_os = "macos")] + let keycode = match peer.as_str() { + "windows" => rdev::macos_code_to_win_scancode(event.code as _)?, + "macos" => event.code as _, + _ => rdev::macos_code_to_linux_code(event.code as _)?, }; + #[cfg(target_os = "linux")] + let keycode = match peer.as_str() { + "windows" => rdev::linux_code_to_win_scancode(event.code as _)?, + "macos" => rdev::linux_code_to_macos_code(event.code as _)?, + _ => event.code as _, + }; + key_event.set_chr(keycode); + Some(key_event) } -pub fn translate_keyboard_mode(_event: &Event, _key_event: &mut KeyEvent) {} +pub fn translate_keyboard_mode(_event: &Event, mut _key_event: KeyEvent) -> Option { + None +} diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 66d2b0414..6b678dbdc 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::{simulate, EventType, Key as RdevKey}; +use rdev::{self, simulate, EventType, Key as RdevKey, RawKey}; use std::time::Duration; use std::{ convert::TryFrom, @@ -686,6 +686,20 @@ pub fn handle_key(evt: &KeyEvent) { handle_key_(evt); } +fn sim_rdev_rawkey(code: u32, down_or_up: bool) { + #[cfg(target_os = "windows")] + let rawkey = RawKey::ScanCode(code); + #[cfg(target_os = "linux")] + let rawkey = RawKey::LinuxXorgKeycode(code); + // // to-do: test android + // #[cfg(target_os = "android")] + // let rawkey = RawKey::LinuxConsoleKeycode(code); + #[cfg(target_os = "macos")] + let rawkey = RawKey::MacVirtualKeycode(code); + + rdev_key_down_or_up(RdevKey::RawKey(rawkey), down_or_up); +} + fn rdev_key_down_or_up(key: RdevKey, down_or_up: bool) { let event_type = match down_or_up { true => EventType::KeyPress(key), @@ -821,8 +835,7 @@ fn map_keyboard_mode(evt: &KeyEvent) { return; } - rdev_key_down_or_up(RdevKey::Unknown(evt.chr()), evt.down); - return; + sim_rdev_rawkey(evt.chr(), evt.down); } #[cfg(target_os = "macos")] @@ -850,6 +863,7 @@ fn release_unpressed_modifiers(en: &mut Enigo, key_event: &KeyEvent) { fix_modifiers(&key_event.modifiers[..], en, ck_value); } +#[cfg(target_os = "linux")] fn is_altgr_pressed() -> bool { KEYS_DOWN .lock() diff --git a/src/ui/macos.rs b/src/ui/macos.rs index 488d1afc8..ab3fb9079 100644 --- a/src/ui/macos.rs +++ b/src/ui/macos.rs @@ -13,7 +13,6 @@ use objc::{ }; use sciter::{make_args, Host}; use std::{ffi::c_void, rc::Rc}; -use dark_light; static APP_HANDLER_IVAR: &str = "GoDeskAppHandler"; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index f38cb6ad3..f6d5a0e94 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -376,7 +376,7 @@ impl Session { let scancode: u32 = scancode as u32; #[cfg(not(target_os = "windows"))] - let key = rdev::key_from_scancode(scancode) as rdev::Key; + let key = rdev::key_from_code(keycode) as rdev::Key; // Windows requires special handling #[cfg(target_os = "windows")] let key = rdev::get_win_key(keycode, scancode);