diff --git a/Cargo.lock b/Cargo.lock index 888115066..642828d4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1806,7 +1806,7 @@ dependencies = [ "log", "objc", "pkg-config", - "rdev 0.5.0-2 (git+https://github.com/fufesou/rdev)", + "rdev", "serde 1.0.190", "serde_derive", "tfc", @@ -4894,31 +4894,7 @@ dependencies = [ [[package]] name = "rdev" version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev?branch=master#339b2a334ba273afebb7e27fb76984e620fc76e5" -dependencies = [ - "cocoa", - "core-foundation 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.8.4", - "core-graphics 0.22.3", - "dispatch", - "enum-map", - "epoll", - "inotify", - "lazy_static", - "libc", - "log", - "mio", - "strum 0.24.1", - "strum_macros 0.24.3", - "widestring", - "winapi 0.3.9", - "x11 2.21.0", -] - -[[package]] -name = "rdev" -version = "0.5.0-2" -source = "git+https://github.com/fufesou/rdev#339b2a334ba273afebb7e27fb76984e620fc76e5" +source = "git+https://github.com/fufesou/rdev#b3434caee84c92412b45a2f655a15ac5dad33488" dependencies = [ "cocoa", "core-foundation 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -5261,7 +5237,7 @@ dependencies = [ "pam", "parity-tokio-ipc", "percent-encoding", - "rdev 0.5.0-2 (git+https://github.com/fufesou/rdev?branch=master)", + "rdev", "repng", "reqwest", "ringbuf", diff --git a/Cargo.toml b/Cargo.toml index c41d0744b..cb94b7da1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ default-net = "0.14" wol-rs = "1.0" flutter_rust_bridge = { version = "=1.80", features = ["uuid"], optional = true} errno = "0.3" -rdev = { git = "https://github.com/fufesou/rdev", branch = "master" } +rdev = { git = "https://github.com/fufesou/rdev" } url = { version = "2.3", features = ["serde"] } crossbeam-queue = "0.3" hex = "0.4" diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index bc5b19c97..53e304596 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -959,7 +959,6 @@ class CustomAlertDialog extends StatelessWidget { void msgBox(SessionID sessionId, String type, String title, String text, String link, OverlayDialogManager dialogManager, {bool? hasCancel, ReconnectHandle? reconnect, int? reconnectTimeout}) { - dialogManager.dismissAll(); List buttons = []; bool hasOk = false; @@ -2766,6 +2765,8 @@ parseParamScreenRect(Map params) { return screenRect; } +get isInputSourceFlutter => stateGlobal.getInputSource() == "Input source 2"; + class _ReconnectCountDownButton extends StatefulWidget { _ReconnectCountDownButton({ Key? key, diff --git a/flutter/lib/common/widgets/remote_input.dart b/flutter/lib/common/widgets/remote_input.dart index a07bffa47..e073bffc9 100644 --- a/flutter/lib/common/widgets/remote_input.dart +++ b/flutter/lib/common/widgets/remote_input.dart @@ -34,7 +34,8 @@ class RawKeyFocusScope extends StatelessWidget { canRequestFocus: true, focusNode: focusNode, onFocusChange: onFocusChange, - onKey: inputModel.handleRawKeyEvent, + onKey: (FocusNode data, RawKeyEvent e) => + inputModel.handleRawKeyEvent(e), child: child)); } } diff --git a/flutter/lib/consts.dart b/flutter/lib/consts.dart index 4236e96d4..fe4052d99 100644 --- a/flutter/lib/consts.dart +++ b/flutter/lib/consts.dart @@ -45,6 +45,7 @@ const String kAppTypeDesktopPortForward = "port forward"; const String kWindowMainWindowOnTop = "main_window_on_top"; const String kWindowGetWindowInfo = "get_window_info"; const String kWindowGetScreenList = "get_screen_list"; +// This method is not used, maybe it can be removed. const String kWindowDisableGrabKeyboard = "disable_grab_keyboard"; const String kWindowActionRebuild = "rebuild"; const String kWindowEventHide = "hide"; diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index c97a0ef3f..dee2d2e29 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -156,7 +156,7 @@ class _ConnectionTabPageState extends State { ), )); } else if (call.method == kWindowDisableGrabKeyboard) { - stateGlobal.grabKeyboard = false; + // ??? } else if (call.method == "onDestroy") { tabController.clear(); } else if (call.method == kWindowActionRebuild) { diff --git a/flutter/lib/desktop/screen/desktop_remote_screen.dart b/flutter/lib/desktop/screen/desktop_remote_screen.dart index 4427cf8a3..255f1a5b2 100644 --- a/flutter/lib/desktop/screen/desktop_remote_screen.dart +++ b/flutter/lib/desktop/screen/desktop_remote_screen.dart @@ -12,9 +12,8 @@ class DesktopRemoteScreen extends StatelessWidget { final Map params; DesktopRemoteScreen({Key? key, required this.params}) : super(key: key) { - if (!bind.mainStartGrabKeyboard()) { - stateGlobal.grabKeyboard = true; - } + bind.mainInitInputSource(); + stateGlobal.getInputSource(force: true); } @override diff --git a/flutter/lib/desktop/widgets/remote_toolbar.dart b/flutter/lib/desktop/widgets/remote_toolbar.dart index 271879428..1ae380761 100644 --- a/flutter/lib/desktop/widgets/remote_toolbar.dart +++ b/flutter/lib/desktop/widgets/remote_toolbar.dart @@ -1585,7 +1585,7 @@ class _KeyboardMenu extends StatelessWidget { // If use flutter to grab keys, we can only use one mode. // Map mode and Legacy mode, at least one of them is supported. String? modeOnly; - if (stateGlobal.grabKeyboard) { + if (isInputSourceFlutter) { if (bind.sessionIsKeyboardModeSupported( sessionId: ffi.sessionId, mode: kKeyMapMode)) { modeOnly = kKeyMapMode; @@ -1603,6 +1603,7 @@ class _KeyboardMenu extends StatelessWidget { menuChildren: [ keyboardMode(modeOnly), localKeyboardType(), + inputSource(), Divider(), viewMode(), Divider(), @@ -1627,6 +1628,7 @@ class _KeyboardMenu extends StatelessWidget { if (value == null) return; await bind.sessionSetKeyboardMode( sessionId: ffi.sessionId, value: value); + await ffi.inputModel.updateKeyboardMode(); } for (InputModeMenu mode in modes) { @@ -1678,6 +1680,41 @@ class _KeyboardMenu extends StatelessWidget { ); } + inputSource() { + final supportedInputSource = bind.mainSupportedInputSource(); + if (supportedInputSource.isEmpty) return Offstage(); + late final List supportedInputSourceList; + try { + supportedInputSourceList = jsonDecode(supportedInputSource); + } catch (e) { + debugPrint('Failed to decode $supportedInputSource, $e'); + return; + } + if (supportedInputSourceList.length < 2) return Offstage(); + final inputSource = stateGlobal.getInputSource(); + final enabled = !ffi.ffiModel.viewOnly; + final children = [Divider()]; + children.addAll(supportedInputSourceList.map((e) { + final d = e as List; + return RdoMenuButton( + child: Text(translate(d[1] as String)), + value: d[0] as String, + groupValue: inputSource, + onChanged: enabled + ? (v) async { + if (v != null) { + await stateGlobal.setInputSource(ffi.sessionId, v); + await ffi.ffiModel.checkDesktopKeyboardMode(); + await ffi.inputModel.updateKeyboardMode(); + } + } + : null, + ffi: ffi, + ); + })); + return Column(children: children); + } + viewMode() { final ffiModel = ffi.ffiModel; final enabled = versionCmp(pi.version, '1.2.0') >= 0 && ffiModel.keyboard; diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 29c13f625..458ccf3ad 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -13,7 +13,6 @@ import '../../models/model.dart'; import '../../models/platform_model.dart'; import '../common.dart'; import '../consts.dart'; -import './state_model.dart'; /// Mouse button enum. enum MouseButtons { left, right, wheel } @@ -53,9 +52,114 @@ class PointerEventToRust { } } +class ToReleaseKeys { + RawKeyEvent? lastLShiftKeyEvent; + RawKeyEvent? lastRShiftKeyEvent; + RawKeyEvent? lastLCtrlKeyEvent; + RawKeyEvent? lastRCtrlKeyEvent; + RawKeyEvent? lastLAltKeyEvent; + RawKeyEvent? lastRAltKeyEvent; + RawKeyEvent? lastLCommandKeyEvent; + RawKeyEvent? lastRCommandKeyEvent; + RawKeyEvent? lastSuperKeyEvent; + + reset() { + lastLShiftKeyEvent = null; + lastRShiftKeyEvent = null; + lastLCtrlKeyEvent = null; + lastRCtrlKeyEvent = null; + lastLAltKeyEvent = null; + lastRAltKeyEvent = null; + lastLCommandKeyEvent = null; + lastRCommandKeyEvent = null; + lastSuperKeyEvent = null; + } + + updateKeyDown(LogicalKeyboardKey logicKey, RawKeyDownEvent e) { + if (e.isAltPressed) { + if (logicKey == LogicalKeyboardKey.altLeft) { + lastLAltKeyEvent = e; + } else if (logicKey == LogicalKeyboardKey.altRight) { + lastRAltKeyEvent = e; + } + } else if (e.isControlPressed) { + if (logicKey == LogicalKeyboardKey.controlLeft) { + lastLCtrlKeyEvent = e; + } else if (logicKey == LogicalKeyboardKey.controlRight) { + lastRCtrlKeyEvent = e; + } + } else if (e.isShiftPressed) { + if (logicKey == LogicalKeyboardKey.shiftLeft) { + lastLShiftKeyEvent = e; + } else if (logicKey == LogicalKeyboardKey.shiftRight) { + lastRShiftKeyEvent = e; + } + } else if (e.isMetaPressed) { + if (logicKey == LogicalKeyboardKey.metaLeft) { + lastLCommandKeyEvent = e; + } else if (logicKey == LogicalKeyboardKey.metaRight) { + lastRCommandKeyEvent = e; + } else if (logicKey == LogicalKeyboardKey.superKey) { + lastSuperKeyEvent = e; + } + } + } + + updateKeyUp(LogicalKeyboardKey logicKey, RawKeyUpEvent e) { + if (e.isAltPressed) { + if (logicKey == LogicalKeyboardKey.altLeft) { + lastLAltKeyEvent = null; + } else if (logicKey == LogicalKeyboardKey.altRight) { + lastRAltKeyEvent = null; + } + } else if (e.isControlPressed) { + if (logicKey == LogicalKeyboardKey.controlLeft) { + lastLCtrlKeyEvent = null; + } else if (logicKey == LogicalKeyboardKey.controlRight) { + lastRCtrlKeyEvent = null; + } + } else if (e.isShiftPressed) { + if (logicKey == LogicalKeyboardKey.shiftLeft) { + lastLShiftKeyEvent = null; + } else if (logicKey == LogicalKeyboardKey.shiftRight) { + lastRShiftKeyEvent = null; + } + } else if (e.isMetaPressed) { + if (logicKey == LogicalKeyboardKey.metaLeft) { + lastLCommandKeyEvent = null; + } else if (logicKey == LogicalKeyboardKey.metaRight) { + lastRCommandKeyEvent = null; + } else if (logicKey == LogicalKeyboardKey.superKey) { + lastSuperKeyEvent = null; + } + } + } + + release(KeyEventResult Function(RawKeyEvent e) handleRawKeyEvent) { + for (final key in [ + lastLShiftKeyEvent, + lastRShiftKeyEvent, + lastLCtrlKeyEvent, + lastRCtrlKeyEvent, + lastLAltKeyEvent, + lastRAltKeyEvent, + lastLCommandKeyEvent, + lastRCommandKeyEvent, + lastSuperKeyEvent, + ]) { + if (key != null) { + handleRawKeyEvent(RawKeyUpEvent( + data: key.data, + character: key.character, + )); + } + } + } +} + class InputModel { final WeakReference parent; - String keyboardMode = "legacy"; + String keyboardMode = ''; // keyboard var shift = false; @@ -63,6 +167,8 @@ class InputModel { var alt = false; var command = false; + final ToReleaseKeys toReleaseKeys = ToReleaseKeys(); + // trackpad var _trackpadLastDelta = Offset.zero; var _stopFling = true; @@ -88,18 +194,29 @@ class InputModel { InputModel(this.parent) { sessionId = parent.target!.sessionId; + + // It is ok to call updateKeyboardMode() directly. + // Because `bind` is initialized in `PlatformFFI.init()` which is called very early. + // But we still wrap it in a Future.delayed() to make it more clear. + Future.delayed(Duration(milliseconds: 100), () { + updateKeyboardMode(); + }); } - KeyEventResult handleRawKeyEvent(FocusNode data, RawKeyEvent e) { - if (isDesktop && !stateGlobal.grabKeyboard) { - return KeyEventResult.handled; - } - + updateKeyboardMode() async { // * Currently mobile does not enable map mode if (isDesktop) { - bind.sessionGetKeyboardMode(sessionId: sessionId).then((result) { - keyboardMode = result.toString(); - }); + if (keyboardMode.isEmpty) { + keyboardMode = + await bind.sessionGetKeyboardMode(sessionId: sessionId) ?? + kKeyLegacyMode; + } + } + } + + KeyEventResult handleRawKeyEvent(RawKeyEvent e) { + if (isDesktop && !isInputSourceFlutter) { + return KeyEventResult.handled; } final key = e.logicalKey; @@ -115,6 +232,7 @@ class InputModel { command = true; } } + toReleaseKeys.updateKeyDown(key, e); } if (e is RawKeyUpEvent) { if (key == LogicalKeyboardKey.altLeft || @@ -131,6 +249,8 @@ class InputModel { key == LogicalKeyboardKey.superKey) { command = false; } + + toReleaseKeys.updateKeyUp(key, e); } // * Currently mobile does not enable map mode @@ -320,12 +440,16 @@ class InputModel { } void enterOrLeave(bool enter) { + toReleaseKeys.release(handleRawKeyEvent); + // Fix status if (!enter) { resetModifiers(); } _flingTimer?.cancel(); - bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter); + if (!isInputSourceFlutter) { + bind.sessionEnterOrLeave(sessionId: sessionId, enter: enter); + } } /// Send mouse movement event with distance in [x] and [y]. @@ -396,7 +520,8 @@ class InputModel { } if (x != 0 || y != 0) { if (peerPlatform == kPeerPlatformAndroid) { - handlePointerEvent('touch', 'pan_update', Offset(x.toDouble(), y.toDouble())); + handlePointerEvent( + 'touch', 'pan_update', Offset(x.toDouble(), y.toDouble())); } else { bind.sessionSendMouse( sessionId: sessionId, diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 2de85aa11..f01a97820 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -735,17 +735,9 @@ class FfiModel with ChangeNotifier { } checkDesktopKeyboardMode() async { - final curMode = await bind.sessionGetKeyboardMode(sessionId: sessionId); - if (curMode != null) { - if (bind.sessionIsKeyboardModeSupported( - sessionId: sessionId, mode: curMode)) { - return; - } - } - - // If current keyboard mode is not supported, change to another one. - - if (stateGlobal.grabKeyboard) { + if (isInputSourceFlutter) { + // Local side, flutter keyboard input source + // Currently only map mode is supported, legacy mode is used for compatibility. for (final mode in [kKeyMapMode, kKeyLegacyMode]) { if (bind.sessionIsKeyboardModeSupported( sessionId: sessionId, mode: mode)) { @@ -754,6 +746,15 @@ class FfiModel with ChangeNotifier { } } } else { + final curMode = await bind.sessionGetKeyboardMode(sessionId: sessionId); + if (curMode != null) { + if (bind.sessionIsKeyboardModeSupported( + sessionId: sessionId, mode: curMode)) { + return; + } + } + + // If current keyboard mode is not supported, change to another one. for (final mode in [kKeyMapMode, kKeyTranslateMode, kKeyLegacyMode]) { if (bind.sessionIsKeyboardModeSupported( sessionId: sessionId, mode: mode)) { diff --git a/flutter/lib/models/native_model.dart b/flutter/lib/models/native_model.dart index ef74a17a2..6778cdbb9 100644 --- a/flutter/lib/models/native_model.dart +++ b/flutter/lib/models/native_model.dart @@ -153,10 +153,10 @@ class PlatformFFI { AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo; name = '${androidInfo.brand}-${androidInfo.model}'; id = androidInfo.id.hashCode.toString(); - androidVersion = androidInfo.version.sdkInt ?? 0; + androidVersion = androidInfo.version.sdkInt; } else if (Platform.isIOS) { IosDeviceInfo iosInfo = await deviceInfo.iosInfo; - name = iosInfo.utsname.machine ?? ''; + name = iosInfo.utsname.machine; id = iosInfo.identifierForVendor.hashCode.toString(); } else if (Platform.isLinux) { LinuxDeviceInfo linuxInfo = await deviceInfo.linuxInfo; diff --git a/flutter/lib/models/state_model.dart b/flutter/lib/models/state_model.dart index c80c3551e..0d95b560b 100644 --- a/flutter/lib/models/state_model.dart +++ b/flutter/lib/models/state_model.dart @@ -2,15 +2,16 @@ import 'dart:io'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_hbb/common.dart'; import 'package:get/get.dart'; import '../consts.dart'; +import './platform_model.dart'; enum SvcStatus { notReady, connecting, ready } class StateGlobal { int _windowId = -1; - bool grabKeyboard = false; final RxBool _fullscreen = false.obs; bool _isMinimized = false; final RxBool isMaximized = false.obs; @@ -22,6 +23,8 @@ class StateGlobal { // Only used for macOS bool? closeOnFullscreen; + String _inputSource = ''; + // Use for desktop -> remote toolbar -> resolution final Map> _lastResolutionGroupValues = {}; @@ -94,6 +97,18 @@ class StateGlobal { } } + String getInputSource({bool force = false}) { + if (force || _inputSource.isEmpty) { + _inputSource = bind.mainGetInputSource(); + } + return _inputSource; + } + + setInputSource(SessionID sessionId, String v) async { + await bind.mainSetInputSource(sessionId: sessionId, value: v); + _inputSource = bind.mainGetInputSource(); + } + StateGlobal._(); static final StateGlobal instance = StateGlobal._(); diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 106bc64e8..d25923de5 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1,5 +1,3 @@ -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use crate::common::get_default_sound_input; use crate::{ client::file_trait::FileManager, common::is_keyboard_mode_supported, @@ -8,6 +6,11 @@ use crate::{ input::*, ui_interface::{self, *}, }; +#[cfg(not(any(target_os = "android", target_os = "ios")))] +use crate::{ + common::get_default_sound_input, + keyboard::input_source::{change_input_source, get_cur_session_input_source}, +}; use flutter_rust_bridge::{StreamSink, SyncReturn}; #[cfg(feature = "plugin_framework")] #[cfg(not(any(target_os = "android", target_os = "ios")))] @@ -857,6 +860,19 @@ pub fn main_set_local_option(key: String, value: String) { set_local_option(key, value) } +pub fn main_get_input_source() -> SyncReturn { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + let input_source = get_cur_session_input_source(); + #[cfg(any(target_os = "android", target_os = "ios"))] + let input_source = "".to_owned(); + SyncReturn(input_source) +} + +pub fn main_set_input_source(session_id: SessionID, value: String) { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + change_input_source(session_id, value); +} + pub fn main_get_my_id() -> String { get_id() } @@ -1593,16 +1609,10 @@ pub fn main_is_installed() -> SyncReturn { SyncReturn(is_installed()) } -pub fn main_start_grab_keyboard() -> SyncReturn { - #[cfg(target_os = "linux")] - if !crate::platform::linux::is_x11() { - return SyncReturn(false); - } - crate::keyboard::client::start_grab_loop(); - if !is_can_input_monitoring(false) { - return SyncReturn(false); - } - SyncReturn(true) +pub fn main_init_input_source() -> SyncReturn<()> { + #[cfg(not(any(target_os = "android", target_os = "ios")))] + crate::keyboard::input_source::init_input_source(); + SyncReturn(()) } pub fn main_is_installed_lower_version() -> SyncReturn { @@ -1979,6 +1989,20 @@ pub fn main_supported_privacy_mode_impls() -> SyncReturn { ) } +pub fn main_supported_input_source() -> SyncReturn { + #[cfg(any(target_os = "android", target_os = "ios"))] + { + SyncReturn("".to_owned()) + } + #[cfg(not(any(target_os = "android", target_os = "ios")))] + { + SyncReturn( + serde_json::to_string(&crate::keyboard::input_source::get_supported_input_source()) + .unwrap_or_default(), + ) + } +} + #[cfg(target_os = "android")] pub mod server_side { use hbb_common::{config, log}; diff --git a/src/keyboard.rs b/src/keyboard.rs index be2827c3d..6f7001e93 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -12,7 +12,7 @@ use hbb_common::message_proto::*; #[cfg(any(target_os = "windows", target_os = "macos"))] use rdev::KeyCode; use rdev::{Event, EventType, Key}; -#[cfg(any(target_os = "windows", target_os = "macos"))] +#[cfg(not(any(target_os = "android", target_os = "ios")))] use std::sync::atomic::{AtomicBool, Ordering}; use std::{ collections::HashMap, @@ -34,6 +34,9 @@ const OS_LOWER_ANDROID: &str = "android"; #[cfg(any(target_os = "windows", target_os = "macos"))] static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false); +#[cfg(not(any(target_os = "android", target_os = "ios")))] +static IS_RDEV_ENABLED: AtomicBool = AtomicBool::new(false); + lazy_static::lazy_static! { static ref TO_RELEASE: Arc>> = Arc::new(Mutex::new(HashMap::new())); static ref MODIFIERS_STATE: Mutex> = { @@ -52,6 +55,7 @@ lazy_static::lazy_static! { pub mod client { use super::*; + lazy_static::lazy_static! { static ref IS_GRAB_STARTED: Arc> = Arc::new(Mutex::new(false)); } @@ -67,6 +71,9 @@ pub mod client { #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn change_grab_status(state: GrabState, keyboard_mode: &str) { + if !IS_RDEV_ENABLED.load(Ordering::SeqCst) { + return; + } match state { GrabState::Ready => {} GrabState::Run => { @@ -90,10 +97,7 @@ pub mod client { #[cfg(target_os = "linux")] rdev::disable_grab(); } - GrabState::Exit => { - #[cfg(target_os = "linux")] - rdev::exit_grab_listen(); - } + GrabState::Exit => {} } } @@ -243,7 +247,7 @@ fn get_keyboard_mode() -> String { "legacy".to_string() } -pub fn start_grab_loop() { +fn start_grab_loop() { std::env::set_var("KEYBOARD_ONLY", "y"); #[cfg(any(target_os = "windows", target_os = "macos"))] std::thread::spawn(move || { @@ -327,6 +331,16 @@ pub fn start_grab_loop() { }; } +// #[allow(dead_code)] is ok here. No need to stop grabbing loop. +#[allow(dead_code)] +fn stop_grab_loop() -> Result<(), rdev::GrabError> { + #[cfg(any(target_os = "windows", target_os = "macos"))] + rdev::exit_grab()?; + #[cfg(target_os = "linux")] + rdev::exit_grab_listen(); + Ok(()) +} + pub fn is_long_press(event: &Event) -> bool { let keys = MODIFIERS_STATE.lock().unwrap(); match event.event_type { @@ -1076,3 +1090,104 @@ pub fn keycode_to_rdev_key(keycode: u32) -> Key { #[cfg(target_os = "macos")] return rdev::macos_key_from_code(keycode.try_into().unwrap_or_default()); } + +#[cfg(feature = "flutter")] +#[cfg(not(any(target_os = "android", target_os = "ios")))] +pub mod input_source { + #[cfg(target_os = "macos")] + use hbb_common::log; + use hbb_common::SessionID; + + use crate::ui_interface::{get_local_option, set_local_option}; + + pub const CONFIG_OPTION_INPUT_SOURCE: &str = "input-source"; + // rdev grab mode + pub const CONFIG_INPUT_SOURCE_1: &str = "Input source 1"; + pub const CONFIG_INPUT_SOURCE_1_TIP: &str = "input_source_1_tip"; + // flutter grab mode + pub const CONFIG_INPUT_SOURCE_2: &str = "Input source 2"; + pub const CONFIG_INPUT_SOURCE_2_TIP: &str = "input_source_2_tip"; + + pub const CONFIG_INPUT_SOURCE_DEFAULT: &str = CONFIG_INPUT_SOURCE_1; + + pub fn init_input_source() { + #[cfg(target_os = "linux")] + if !crate::platform::linux::is_x11() { + // If switching from X11 to Wayland, the grab loop will not be started. + // Do not change the config here. + return; + } + #[cfg(target_os = "macos")] + if !crate::platform::macos::is_can_input_monitoring(false) { + log::error!("init_input_source, is_can_input_monitoring() false"); + set_local_option( + CONFIG_OPTION_INPUT_SOURCE.to_string(), + CONFIG_INPUT_SOURCE_2.to_string(), + ); + return; + } + let cur_input_source = get_cur_session_input_source(); + if cur_input_source == CONFIG_INPUT_SOURCE_1 { + super::IS_RDEV_ENABLED.store(true, super::Ordering::SeqCst); + } + super::client::start_grab_loop(); + } + + pub fn change_input_source(session_id: SessionID, input_source: String) { + let cur_input_source = get_cur_session_input_source(); + if cur_input_source == input_source { + return; + } + if input_source == CONFIG_INPUT_SOURCE_1 { + #[cfg(target_os = "macos")] + if !crate::platform::macos::is_can_input_monitoring(false) { + log::error!("change_input_source, is_can_input_monitoring() false"); + return; + } + // It is ok to start grab loop multiple times. + super::client::start_grab_loop(); + super::IS_RDEV_ENABLED.store(true, super::Ordering::SeqCst); + crate::flutter_ffi::session_enter_or_leave(session_id, true); + } else if input_source == CONFIG_INPUT_SOURCE_2 { + // No need to stop grab loop. + crate::flutter_ffi::session_enter_or_leave(session_id, false); + super::IS_RDEV_ENABLED.store(false, super::Ordering::SeqCst); + } + set_local_option(CONFIG_OPTION_INPUT_SOURCE.to_string(), input_source); + } + + #[inline] + pub fn get_cur_session_input_source() -> String { + #[cfg(target_os = "linux")] + if !crate::platform::linux::is_x11() { + return CONFIG_INPUT_SOURCE_2.to_string(); + } + let input_source = get_local_option(CONFIG_OPTION_INPUT_SOURCE.to_string()); + if input_source.is_empty() { + CONFIG_INPUT_SOURCE_DEFAULT.to_string() + } else { + input_source + } + } + + #[inline] + pub fn get_supported_input_source() -> Vec<(String, String)> { + #[cfg(target_os = "linux")] + if !crate::platform::linux::is_x11() { + return vec![( + CONFIG_INPUT_SOURCE_2.to_string(), + CONFIG_INPUT_SOURCE_2_TIP.to_string(), + )]; + } + vec![ + ( + CONFIG_INPUT_SOURCE_1.to_string(), + CONFIG_INPUT_SOURCE_1_TIP.to_string(), + ), + ( + CONFIG_INPUT_SOURCE_2.to_string(), + CONFIG_INPUT_SOURCE_2_TIP.to_string(), + ), + ] + } +} diff --git a/src/lang/ar.rs b/src/lang/ar.rs index bdab9e466..d281facee 100644 --- a/src/lang/ar.rs +++ b/src/lang/ar.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 36aba208c..eafc06864 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 86a01bd6b..66e65db72 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "进入隐私模式"), ("Exit privacy mode", "退出隐私模式"), ("idd_not_support_under_win10_2004_tip", "不支持 Indirect display driver 。需要 windows 10, version 2004 及更高的版本。"), + ("input_source_1_tip", "输入源 1"), + ("input_source_2_tip", "输入源 2"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 616071e88..6e185ce83 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Vstup do režimu soukromí"), ("Exit privacy mode", "Ukončit režim soukromí"), ("idd_not_support_under_win10_2004_tip", "Ovladač nepřímého zobrazení není podporován. Je vyžadován systém Windows 10, verze 2004 nebo novější."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index ed926f0df..739e12690 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 1473119c4..4af92444d 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Datenschutzmodus aktivieren"), ("Exit privacy mode", "Datenschutzmodus beenden"), ("idd_not_support_under_win10_2004_tip", "Indirekter Grafiktreiber wird nicht unterstützt. Windows 10, Version 2004 oder neuer ist erforderlich."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 8bb3a3d79..a18812b98 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/en.rs b/src/lang/en.rs index 101bc63a3..365076018 100644 --- a/src/lang/en.rs +++ b/src/lang/en.rs @@ -206,5 +206,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("privacy_mode_impl_mag_tip", "Mode 1"), ("privacy_mode_impl_virtual_display_tip", "Mode 2"), ("idd_not_support_under_win10_2004_tip", "Indirect display driver is not supported. Windows 10, version 2004 or newer is required."), + ("input_source_1_tip", "Input source 1"), + ("input_source_2_tip", "Input source 2"), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 73eb77aa5..5efda9cf7 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index 40a23f317..3b8b8ab46 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Entrar al modo privado"), ("Exit privacy mode", "Salir del modo privado"), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index af0b8e944..4d1ad99d5 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index ea90ff654..b0d4782e5 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index f179da1df..79f0505bf 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 780b24bbd..e3bc5d4ba 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Masuk mode privasi"), ("Exit privacy mode", "Keluar mode privasi"), ("idd_not_support_under_win10_2004_tip", "Driver grafis yang Anda gunakan tidak kompatibel dengan versi Windows Anda dan memerlukan Windows 10 versi 2004 atau yang lebih baru"), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index e148ece66..d049d79ef 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Entra in modalità privacy"), ("Exit privacy mode", "Esci dalla modalità privacy"), ("idd_not_support_under_win10_2004_tip", "Il driver video indiretto non è supportato. È richiesto Windows 10, versione 2004 o successiva."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 0ff52484c..2b646c8ac 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 36d8338b9..2455b4099 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "개인정보 보호 모드 사용"), ("Exit privacy mode", "개인정보 보호 모드 종료"), ("idd_not_support_under_win10_2004_tip", "간접 디스플레이 드라이버는 지원되지 않습니다. Windows 10 버전 2004 이상이 필요합니다."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 7a552e96a..a485d78bb 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index b4990d9c6..78716e3a2 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lv.rs b/src/lang/lv.rs index 53b714723..a13ad8520 100644 --- a/src/lang/lv.rs +++ b/src/lang/lv.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Ieiet privātuma režīmā"), ("Exit privacy mode", "Iziet no privātuma režīma"), ("idd_not_support_under_win10_2004_tip", "Netiešā displeja draiveris netiek atbalstīts. Nepieciešama operētājsistēma Windows 10, versija 2004 vai jaunāka."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nb.rs b/src/lang/nb.rs index 4f8945721..b3f1360cf 100644 --- a/src/lang/nb.rs +++ b/src/lang/nb.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index 7b66fb3f3..9267d9be0 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 3aa80786e..763a7ed19 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Wejdź w tryb prywatności"), ("Exit privacy mode", "Wyjdź z trybu prywatności"), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 6b89eaa8c..79b3374b6 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index c5c4f2768..5f477f853 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 5e806e426..30434268b 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 98994795d..b4e12f93d 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Включить режим конфиденциальности"), ("Exit privacy mode", "Отключить режим конфиденциальности"), ("idd_not_support_under_win10_2004_tip", "Драйвер непрямого отображения не поддерживается. Требуется Windows 10 версии 2004 или новее."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 46848da73..9173f7467 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Vstup do režimu súkromia"), ("Exit privacy mode", "Ukončiť režim súkromia"), ("idd_not_support_under_win10_2004_tip", "Ovládač nepriameho zobrazenia nie je podporovaný. Vyžaduje sa systém Windows 10, verzia 2004 alebo novšia."), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index be9774be8..9a2b39366 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index ff8851b94..499c2fd09 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index ae4c4e364..8ded31ae3 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index cfefe48a1..56e64e8fb 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index e3f8f6f38..2431d0130 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index ea3a72af2..971745e56 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index e14be47db..c5b2f4816 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 57b7d7b9f..c1072f373 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 6fa172311..ffe887436 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", "Увійти в режим конфіденційності"), ("Exit privacy mode", "Вийти з режиму конфіденційності"), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 84b0bf752..4ef8825fa 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -573,5 +573,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enter privacy mode", ""), ("Exit privacy mode", ""), ("idd_not_support_under_win10_2004_tip", ""), + ("input_source_1_tip", ""), + ("input_source_2_tip", ""), ].iter().cloned().collect(); } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index bc44161ab..fd9802986 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -5,8 +5,6 @@ use crate::{ use async_trait::async_trait; use bytes::Bytes; use rdev::{Event, EventType::*, KeyCode}; -#[cfg(not(any(target_os = "android", target_os = "ios")))] -use std::sync::atomic::{AtomicBool, Ordering}; use std::{ collections::HashMap, ops::{Deref, DerefMut}, @@ -43,9 +41,6 @@ use crate::common::GrabState; use crate::keyboard; use crate::{client::Data, client::Interface}; -#[cfg(not(any(target_os = "android", target_os = "ios")))] -pub static IS_IN: AtomicBool = AtomicBool::new(false); - const CHANGE_RESOLUTION_VALID_TIMEOUT_SECS: u64 = 15; #[derive(Clone, Default)] @@ -725,13 +720,11 @@ impl Session { #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn enter(&self, keyboard_mode: String) { - IS_IN.store(true, Ordering::SeqCst); keyboard::client::change_grab_status(GrabState::Run, &keyboard_mode); } #[cfg(not(any(target_os = "android", target_os = "ios")))] pub fn leave(&self, keyboard_mode: String) { - IS_IN.store(false, Ordering::SeqCst); keyboard::client::change_grab_status(GrabState::Wait, &keyboard_mode); }