From ce7867c1c0ab534afdf4082474a5369d3253b145 Mon Sep 17 00:00:00 2001 From: 21pages Date: Wed, 30 Oct 2024 11:29:39 +0800 Subject: [PATCH 1/5] fix wrong display of custom clients when approval mode is not set (#9779) when approve-mode is not set, the approve mode option shows as password, it's `both` approve mode in rust, so only ui is wrong. Signed-off-by: 21pages --- flutter/lib/desktop/pages/desktop_setting_page.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 15cf2173b5e9..69100470f0ea 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -1029,7 +1029,9 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin { translate('Accept sessions via both'), ]; var modeInitialKey = model.approveMode; - if (!modeKeys.contains(modeInitialKey)) modeInitialKey = ''; + if (!modeKeys.contains(modeInitialKey)) { + modeInitialKey = defaultOptionApproveMode; + } final usePassword = model.approveMode != 'click'; final isApproveModeFixed = isOptionFixed(kOptionApproveMode); From 0f5f9f65245e40b6c0ebb434308be0fe4b2b129b Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:17:13 +0800 Subject: [PATCH 2/5] revert: #9769 (#9780) Not sure TextEditingController.addListener() can handle all composing changes. https://github.com/rustdesk/rustdesk/issues/7727#issuecomment-2445721499 Signed-off-by: fufesou --- flutter/lib/mobile/pages/remote_page.dart | 26 +++++++++-------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index a8446de20225..40890f228e6b 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -57,7 +57,9 @@ class _RemotePageState extends State { final TextEditingController _textController = TextEditingController(text: initText); - bool _lastComposingChangeValid = false; + // This timer is used to check the composing status of the soft keyboard. + // It is used for Android, Korean(and other similar) input method. + Timer? _composingTimer; _RemotePageState(String id) { initSharedStates(id); @@ -97,9 +99,6 @@ class _RemotePageState extends State { showToast(translate('Automatically record outgoing sessions')); } }); - if (isAndroid) { - _textController.addListener(textAndroidListener); - } } @override @@ -115,6 +114,7 @@ class _RemotePageState extends State { _physicalFocusNode.dispose(); await gFFI.close(); _timer?.cancel(); + _composingTimer?.cancel(); gFFI.dialogManager.dismissAll(); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); @@ -127,16 +127,6 @@ class _RemotePageState extends State { // The inner logic of `on_voice_call_closed` will check if the voice call is active. // Only one client is considered here for now. gFFI.chatModel.onVoiceCallClosed("End connetion"); - if (isAndroid) { - _textController.removeListener(textAndroidListener); - } - } - - // This listener is used to handle the composing region changes for Android soft keyboard input. - void textAndroidListener() { - if (_lastComposingChangeValid) { - _handleNonIOSSoftKeyboardInput(_textController.text); - } } // to-do: It should be better to use transparent color instead of the bgColor. @@ -160,6 +150,7 @@ class _RemotePageState extends State { gFFI.ffiModel.pi.version.isNotEmpty) { gFFI.invokeMethod("enable_soft_keyboard", false); } + _composingTimer?.cancel(); } else { _timer?.cancel(); _timer = Timer(kMobileDelaySoftKeyboardFocus, () { @@ -223,8 +214,11 @@ class _RemotePageState extends State { } void _handleNonIOSSoftKeyboardInput(String newValue) { - _lastComposingChangeValid = _textController.value.isComposingRangeValid; - if (_lastComposingChangeValid) { + _composingTimer?.cancel(); + if (_textController.value.isComposingRangeValid) { + _composingTimer = Timer(Duration(milliseconds: 25), () { + _handleNonIOSSoftKeyboardInput(_textController.value.text); + }); return; } var oldValue = _value; From e6c5064ce53baee2fafcdc355653a712a66a29d7 Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:05:25 +0800 Subject: [PATCH 3/5] fix: android input, Backspace and Enter (#9782) Signed-off-by: fufesou --- flutter/lib/models/input_model.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 2b00098caafc..1b2a9736ee2a 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -556,13 +556,14 @@ class InputModel { // The correct PhysicalKeyboardKey should be // PhysicalKeyboardKey#e14a9(usbHidUsage: "0x00070028", debugName: "Enter") // https://github.com/flutter/flutter/issues/157771 - final isKeyMatch = - isIOS || isAndroid && e.logicalKey.debugName == e.physicalKey.debugName; + // We cannot use the debugName to determine the key is correct or not, because it's null in release mode. + // to-do: `isLegacyModeKeys` is not the best workaround, we need to find a better way to fix this issue. + final isLegacyModeKeys = ['Backspace', 'Enter'].contains(e.logicalKey.keyLabel); final isMobileAndPeerNotAndroid = isMobile && peerPlatform != kPeerPlatformAndroid; final isDesktopAndMapMode = isDesktop || isWebDesktop && keyboardMode == kKeyMapMode; - if (isKeyMatch && (isMobileAndPeerNotAndroid || isDesktopAndMapMode)) { + if (!isLegacyModeKeys && (isMobileAndPeerNotAndroid || isDesktopAndMapMode)) { // FIXME: e.character is wrong for dead keys, eg: ^ in de newKeyboardMode( e.character ?? '', From 711ed28846221afee485e8826e7d738990f83952 Mon Sep 17 00:00:00 2001 From: RustDesk <71636191+rustdesk@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:12:18 +0800 Subject: [PATCH 4/5] Revert "revert: #9769 (#9780)" (#9783) This reverts commit 0f5f9f65245e40b6c0ebb434308be0fe4b2b129b. --- flutter/lib/mobile/pages/remote_page.dart | 26 ++++++++++++++--------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index 40890f228e6b..a8446de20225 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -57,9 +57,7 @@ class _RemotePageState extends State { final TextEditingController _textController = TextEditingController(text: initText); - // This timer is used to check the composing status of the soft keyboard. - // It is used for Android, Korean(and other similar) input method. - Timer? _composingTimer; + bool _lastComposingChangeValid = false; _RemotePageState(String id) { initSharedStates(id); @@ -99,6 +97,9 @@ class _RemotePageState extends State { showToast(translate('Automatically record outgoing sessions')); } }); + if (isAndroid) { + _textController.addListener(textAndroidListener); + } } @override @@ -114,7 +115,6 @@ class _RemotePageState extends State { _physicalFocusNode.dispose(); await gFFI.close(); _timer?.cancel(); - _composingTimer?.cancel(); gFFI.dialogManager.dismissAll(); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values); @@ -127,6 +127,16 @@ class _RemotePageState extends State { // The inner logic of `on_voice_call_closed` will check if the voice call is active. // Only one client is considered here for now. gFFI.chatModel.onVoiceCallClosed("End connetion"); + if (isAndroid) { + _textController.removeListener(textAndroidListener); + } + } + + // This listener is used to handle the composing region changes for Android soft keyboard input. + void textAndroidListener() { + if (_lastComposingChangeValid) { + _handleNonIOSSoftKeyboardInput(_textController.text); + } } // to-do: It should be better to use transparent color instead of the bgColor. @@ -150,7 +160,6 @@ class _RemotePageState extends State { gFFI.ffiModel.pi.version.isNotEmpty) { gFFI.invokeMethod("enable_soft_keyboard", false); } - _composingTimer?.cancel(); } else { _timer?.cancel(); _timer = Timer(kMobileDelaySoftKeyboardFocus, () { @@ -214,11 +223,8 @@ class _RemotePageState extends State { } void _handleNonIOSSoftKeyboardInput(String newValue) { - _composingTimer?.cancel(); - if (_textController.value.isComposingRangeValid) { - _composingTimer = Timer(Duration(milliseconds: 25), () { - _handleNonIOSSoftKeyboardInput(_textController.value.text); - }); + _lastComposingChangeValid = _textController.value.isComposingRangeValid; + if (_lastComposingChangeValid) { return; } var oldValue = _value; From bae4a2c71065e07b9149ef0f4ba5ff47dd6e5f6c Mon Sep 17 00:00:00 2001 From: fufesou <13586388+fufesou@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:29:52 +0800 Subject: [PATCH 5/5] Fix/android check normal usbhid usage (#9784) * fix: android check normal usbhid usage Signed-off-by: fufesou * fix: android input, ignore composing if is deleting Signed-off-by: fufesou --------- Signed-off-by: fufesou --- flutter/lib/mobile/pages/remote_page.dart | 4 +- flutter/lib/models/input_model.dart | 52 ++++++++++++++--------- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart index a8446de20225..70ebb987797b 100644 --- a/flutter/lib/mobile/pages/remote_page.dart +++ b/flutter/lib/mobile/pages/remote_page.dart @@ -224,7 +224,9 @@ class _RemotePageState extends State { void _handleNonIOSSoftKeyboardInput(String newValue) { _lastComposingChangeValid = _textController.value.isComposingRangeValid; - if (_lastComposingChangeValid) { + if (_lastComposingChangeValid && newValue.length > _value.length) { + // Only early return if is composing new words. + // We need to send `backspace` immediately if is deleting letters. return; } var oldValue = _value; diff --git a/flutter/lib/models/input_model.dart b/flutter/lib/models/input_model.dart index 1b2a9736ee2a..3f413c499bf9 100644 --- a/flutter/lib/models/input_model.dart +++ b/flutter/lib/models/input_model.dart @@ -544,26 +544,40 @@ class InputModel { handleKeyDownEventModifiers(e); } - // The physicalKey.usbHidUsage may be not correct for soft keyboard on Android. - // iOS does not have this issue. - // 1. Open the soft keyboard on Android - // 2. Switch to input method like zh/ko/ja - // 3. Click Backspace and Enter on the soft keyboard or physical keyboard - // 4. The physicalKey.usbHidUsage is not correct. - // PhysicalKeyboardKey#8ac83(usbHidUsage: "0x1100000042", debugName: "Key with ID 0x1100000042") - // LogicalKeyboardKey#2604c(keyId: "0x10000000d", keyLabel: "Enter", debugName: "Enter") - // - // The correct PhysicalKeyboardKey should be - // PhysicalKeyboardKey#e14a9(usbHidUsage: "0x00070028", debugName: "Enter") - // https://github.com/flutter/flutter/issues/157771 - // We cannot use the debugName to determine the key is correct or not, because it's null in release mode. - // to-do: `isLegacyModeKeys` is not the best workaround, we need to find a better way to fix this issue. - final isLegacyModeKeys = ['Backspace', 'Enter'].contains(e.logicalKey.keyLabel); - final isMobileAndPeerNotAndroid = - isMobile && peerPlatform != kPeerPlatformAndroid; + bool isMobileAndMapMode = false; + if (isMobile) { + // Do not use map mode if mobile -> Android. Android does not support map mode for now. + // Because simulating the physical key events(uhid) which requires root permission is not supported. + if (peerPlatform != kPeerPlatformAndroid) { + if (isIOS) { + isMobileAndMapMode = true; + } else { + // The physicalKey.usbHidUsage may be not correct for soft keyboard on Android. + // iOS does not have this issue. + // 1. Open the soft keyboard on Android + // 2. Switch to input method like zh/ko/ja + // 3. Click Backspace and Enter on the soft keyboard or physical keyboard + // 4. The physicalKey.usbHidUsage is not correct. + // PhysicalKeyboardKey#8ac83(usbHidUsage: "0x1100000042", debugName: "Key with ID 0x1100000042") + // LogicalKeyboardKey#2604c(keyId: "0x10000000d", keyLabel: "Enter", debugName: "Enter") + // + // The correct PhysicalKeyboardKey should be + // PhysicalKeyboardKey#e14a9(usbHidUsage: "0x00070028", debugName: "Enter") + // https://github.com/flutter/flutter/issues/157771 + // We cannot use the debugName to determine the key is correct or not, because it's null in release mode. + // The normal `usbHidUsage` for keyboard shoud be between [0x00000010, 0x000c029f] + // https://github.com/flutter/flutter/blob/c051b69e2a2224300e20d93dbd15f4b91e8844d1/packages/flutter/lib/src/services/keyboard_key.g.dart#L5332 - 5600 + final isNormalHsbHidUsage = (e.physicalKey.usbHidUsage >> 20) == 0; + isMobileAndMapMode = isNormalHsbHidUsage && + // No need to check `!['Backspace', 'Enter'].contains(e.logicalKey.keyLabel)` + // But we still add it for more reliability. + !['Backspace', 'Enter'].contains(e.logicalKey.keyLabel); + } + } + } final isDesktopAndMapMode = - isDesktop || isWebDesktop && keyboardMode == kKeyMapMode; - if (!isLegacyModeKeys && (isMobileAndPeerNotAndroid || isDesktopAndMapMode)) { + isDesktop || (isWebDesktop && keyboardMode == kKeyMapMode); + if (isMobileAndMapMode || isDesktopAndMapMode) { // FIXME: e.character is wrong for dead keys, eg: ^ in de newKeyboardMode( e.character ?? '',