diff --git a/flutter/lib/common/widgets/remote_input.dart b/flutter/lib/common/widgets/remote_input.dart index 017850cf5..2d0dcacdf 100644 --- a/flutter/lib/common/widgets/remote_input.dart +++ b/flutter/lib/common/widgets/remote_input.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_hbb/models/state_model.dart'; import '../../models/input_model.dart'; @@ -25,7 +26,8 @@ class RawKeyFocusScope extends StatelessWidget { canRequestFocus: true, focusNode: focusNode, onFocusChange: onFocusChange, - onKey: inputModel.handleRawKeyEvent, + onKey: + stateGlobal.grabKeyboard ? inputModel.handleRawKeyEvent : null, child: child)); } } diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index e8361a652..bb6bc431b 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/desktop/pages/remote_tab_page.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; +import 'package:flutter_hbb/models/state_model.dart'; import 'package:provider/provider.dart'; /// multi-tab desktop remote screen @@ -10,7 +11,9 @@ class DesktopRemoteScreen extends StatelessWidget { final Map params; DesktopRemoteScreen({Key? key, required this.params}) : super(key: key) { - bind.mainStartGrabKeyboard(); + if (!bind.mainStartGrabKeyboard()) { + stateGlobal.grabKeyboard = true; + } } @override diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 63f86078c..7356c6ec8 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -119,8 +119,11 @@ class InputModel { keyCode = newData.keyCode; } else if (e.data is RawKeyEventDataLinux) { RawKeyEventDataLinux newData = e.data as RawKeyEventDataLinux; - scanCode = newData.scanCode; - keyCode = newData.keyCode; + // scanCode and keyCode of RawKeyEventDataLinux are incorrect. + // 1. scanCode means keycode + // 2. keyCode means keysym + scanCode = 0; + keyCode = newData.scanCode; } else if (e.data is RawKeyEventDataAndroid) { RawKeyEventDataAndroid newData = e.data as RawKeyEventDataAndroid; scanCode = newData.scanCode + 8; @@ -135,16 +138,33 @@ class InputModel { } else { down = false; } - inputRawKey(e.character ?? "", keyCode, scanCode, down); + inputRawKey(e.character ?? '', keyCode, scanCode, down); } /// Send raw Key Event void inputRawKey(String name, int keyCode, int scanCode, bool down) { + const capslock = 1; + const numlock = 2; + const scrolllock = 3; + int lockModes = 0; + if (HardwareKeyboard.instance.lockModesEnabled + .contains(KeyboardLockMode.capsLock)) { + lockModes |= (1 << capslock); + } + if (HardwareKeyboard.instance.lockModesEnabled + .contains(KeyboardLockMode.numLock)) { + lockModes |= (1 << numlock); + } + if (HardwareKeyboard.instance.lockModesEnabled + .contains(KeyboardLockMode.scrollLock)) { + lockModes |= (1 << scrolllock); + } bind.sessionHandleFlutterKeyEvent( id: id, name: name, keycode: keyCode, scancode: scanCode, + lockModes: lockModes, downOrUp: down); } diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index 53f1a19b1..e4c9fa03f 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -9,6 +9,7 @@ import '../consts.dart'; class StateGlobal { int _windowId = -1; bool _fullscreen = false; + bool grabKeyboard = false; final RxBool _showTabBar = true.obs; final RxDouble _resizeEdgeSize = RxDouble(kWindowEdgeSize); final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth); diff --git a/libs/enigo/src/linux/nix_impl.rs b/libs/enigo/src/linux/nix_impl.rs index d9be7b43b..f6e172677 100644 --- a/libs/enigo/src/linux/nix_impl.rs +++ b/libs/enigo/src/linux/nix_impl.rs @@ -183,6 +183,7 @@ impl MouseControllable for Enigo { fn get_led_state(key: Key) -> bool { let led_file = match key { + // FIXME: the file may be /sys/class/leds/input2 or input5 ... Key::CapsLock => "/sys/class/leds/input1::capslock/brightness", Key::NumLock => "/sys/class/leds/input1::numlock/brightness", _ => { diff --git a/src/common.rs b/src/common.rs index 0be84e79f..163937479 100644 --- a/src/common.rs +++ b/src/common.rs @@ -51,7 +51,7 @@ lazy_static::lazy_static! { pub fn global_init() -> bool { #[cfg(target_os = "linux")] { - if !scrap::is_x11() { + if !*IS_X11 { crate::server::wayland::set_wayland_scrap_map_err(); } } @@ -660,13 +660,13 @@ pub fn make_privacy_mode_msg(state: back_notification::PrivacyModeState) -> Mess #[cfg(not(target_os = "linux"))] lazy_static::lazy_static! { - pub static ref IS_X11: Mutex = Mutex::new(false); + pub static ref IS_X11: bool = false; } #[cfg(target_os = "linux")] lazy_static::lazy_static! { - pub static ref IS_X11: Mutex = Mutex::new("x11" == hbb_common::platform::linux::get_display_server()); + pub static ref IS_X11: bool = "x11" == hbb_common::platform::linux::get_display_server(); } pub fn make_fd_to_json(id: i32, path: String, entries: &Vec) -> String { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 92f1e0606..b30e1e108 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -289,10 +289,11 @@ pub fn session_handle_flutter_key_event( name: String, keycode: i32, scancode: i32, + lock_modes: i32, down_or_up: bool, ) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - session.handle_flutter_key_event(&name, keycode, scancode, down_or_up); + session.handle_flutter_key_event(&name, keycode, scancode, lock_modes, down_or_up); } } @@ -1093,8 +1094,13 @@ pub fn main_is_installed() -> SyncReturn { SyncReturn(is_installed()) } -pub fn main_start_grab_keyboard() { +pub fn main_start_grab_keyboard() -> SyncReturn { + #[cfg(target_os = "linux")] + if !*crate::common::IS_X11 { + return SyncReturn(false); + } crate::keyboard::client::start_grab_loop(); + SyncReturn(true) } pub fn main_is_installed_lower_version() -> SyncReturn { diff --git a/src/keyboard.rs b/src/keyboard.rs index a11b0e97e..2d2aada23 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -99,11 +99,11 @@ pub mod client { } } - pub fn process_event(event: &Event) { + pub fn process_event(event: &Event, lock_modes: Option) { if is_long_press(&event) { return; } - if let Some(key_event) = event_to_key_event(&event) { + if let Some(key_event) = event_to_key_event(&event, lock_modes) { send_key_event(&key_event); } } @@ -196,7 +196,7 @@ pub fn start_grab_loop() { return Some(event); } if KEYBOARD_HOOKED.load(Ordering::SeqCst) { - client::process_event(&event); + client::process_event(&event, None); if is_press { return None; } else { @@ -222,7 +222,7 @@ pub fn start_grab_loop() { if let Key::Unknown(keycode) = key { log::error!("rdev get unknown key, keycode is : {:?}", keycode); } else { - client::process_event(&event); + client::process_event(&event, None); } None } @@ -254,7 +254,7 @@ pub fn release_remote_keys() { for key in to_release { let event_type = EventType::KeyRelease(key); let event = event_type_to_event(event_type); - client::process_event(&event); + client::process_event(&event, None); } } @@ -267,7 +267,23 @@ pub fn get_keyboard_mode_enum() -> KeyboardMode { } #[cfg(not(any(target_os = "android", target_os = "ios")))] -pub fn add_numlock_capslock_status(key_event: &mut KeyEvent) { +fn add_numlock_capslock_with_lock_modes(key_event: &mut KeyEvent, lock_modes: i32) { + const CAPS_LOCK: i32 = 1; + const NUM_LOCK: i32 = 2; + // const SCROLL_LOCK: i32 = 3; + if lock_modes & (1 << CAPS_LOCK) != 0 { + key_event.modifiers.push(ControlKey::CapsLock.into()); + } + if lock_modes & (1 << NUM_LOCK) != 0 { + key_event.modifiers.push(ControlKey::NumLock.into()); + } + // if lock_modes & (1 << SCROLL_LOCK) != 0 { + // key_event.modifiers.push(ControlKey::ScrollLock.into()); + // } +} + +#[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) { key_event.modifiers.push(ControlKey::CapsLock.into()); } @@ -315,7 +331,7 @@ fn update_modifiers_state(event: &Event) { }; } -pub fn event_to_key_event(event: &Event) -> Option { +pub fn event_to_key_event(event: &Event, lock_modes: Option) -> Option { let mut key_event = KeyEvent::new(); update_modifiers_state(event); @@ -345,8 +361,12 @@ pub fn event_to_key_event(event: &Event) -> Option { } } }; - #[cfg(not(any(target_os = "android", target_os = "ios")))] - add_numlock_capslock_status(&mut key_event); + if let Some(lock_modes) = lock_modes { + add_numlock_capslock_with_lock_modes(&mut key_event, lock_modes); + } else { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + add_numlock_capslock_status(&mut key_event); + } return Some(key_event); } diff --git a/src/server/input_service.rs b/src/server/input_service.rs index 814fea110..2715a2643 100644 --- a/src/server/input_service.rs +++ b/src/server/input_service.rs @@ -882,7 +882,7 @@ fn map_keyboard_mode(evt: &KeyEvent) { // Wayland #[cfg(target_os = "linux")] - if !*IS_X11.lock().unwrap() { + if !*IS_X11 { let mut en = ENIGO.lock().unwrap(); let code = evt.chr() as u16; diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index c66e1fa3b..7bacb9b21 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -394,6 +394,7 @@ impl Session { name: &str, keycode: i32, scancode: i32, + lock_modes: i32, down_or_up: bool, ) { if scancode < 0 || keycode < 0 { @@ -420,7 +421,7 @@ impl Session { scan_code: scancode as _, event_type: event_type, }; - keyboard::client::process_event(&event); + keyboard::client::process_event(&event, Some(lock_modes)); } // flutter only TODO new input