mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-06-22 10:02:20 +00:00
When the Android soft keyboard is active, key events from the IME carry unreliable physicalKey data (Flutter issue #157771). The RawKeyFocusScope handler was processing these garbled scancodes, desynchronising the hidden TextFormField's text buffer and causing every subsequent keypress to repeat a single character (space or '1'). Changes: - InputModel: add androidSoftKeyboardActive flag; when set, handleKeyEvent returns handled but skips the normal key processing pipeline. Backspace and Enter are sent directly using reliable logicalKey data. - remote_page.dart: set/clear the flag via onSoftKeyboardChanged callback; fix multi-delete counting for Samsung keyboard acceleration. Fixes: rustdesk/rustdesk#13737, rustdesk/rustdesk#9789, rustdesk/rustdesk#11073
This commit is contained in:
parent
db3f5fe816
commit
7b04665f33
2 changed files with 35 additions and 2 deletions
|
|
@ -201,6 +201,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
);
|
||||
|
||||
void onSoftKeyboardChanged(bool visible) {
|
||||
inputModel.androidSoftKeyboardActive = visible;
|
||||
if (!visible) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
|
||||
// [pi.version.isNotEmpty] -> check ready or not, avoid login without soft-keyboard
|
||||
|
|
@ -300,8 +301,11 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
|
|||
if (newValue.length == oldValue.length) {
|
||||
// ?
|
||||
} else if (newValue.length < oldValue.length) {
|
||||
final char = 'VK_BACK';
|
||||
inputModel.inputKey(char);
|
||||
// Send exactly one VK_BACK per onChanged callback regardless of how many
|
||||
// characters the IME removed (Samsung accelerates held-delete). The
|
||||
// IME's own callback frequency provides a steady, controllable repeat
|
||||
// rate instead of runaway exponential deletion.
|
||||
inputModel.inputKey('VK_BACK');
|
||||
} else {
|
||||
final content = newValue.substring(oldValue.length);
|
||||
if (content.length > 1) {
|
||||
|
|
|
|||
|
|
@ -367,6 +367,12 @@ class InputModel {
|
|||
bool _pointerMovedAfterEnter = false;
|
||||
bool _pointerInsideImage = false;
|
||||
|
||||
/// True while the Android soft keyboard editor is active.
|
||||
/// When set, key events are ignored so they flow through to the
|
||||
/// hidden TextFormField's onChanged handler instead of being
|
||||
/// processed here with potentially incorrect physicalKey data.
|
||||
bool androidSoftKeyboardActive = false;
|
||||
|
||||
// mouse
|
||||
final isPhysicalMouse = false.obs;
|
||||
int _lastButtons = 0;
|
||||
|
|
@ -687,6 +693,29 @@ class InputModel {
|
|||
KeyEventResult handleKeyEvent(KeyEvent e) {
|
||||
if (isViewOnly) return KeyEventResult.handled;
|
||||
if (isViewCamera) return KeyEventResult.handled;
|
||||
// When the Android soft keyboard is active, avoid processing key events
|
||||
// through the normal input pipeline because physicalKey data from the
|
||||
// soft keyboard is unreliable (Flutter issue #157771) and can corrupt
|
||||
// subsequent input, causing every keypress to repeat a single character.
|
||||
//
|
||||
// Return `handled` (not `ignored`) so Android keeps sending key-repeat
|
||||
// events for held keys and the TextFormField does not consume sentinel
|
||||
// buffer characters.
|
||||
//
|
||||
// For Backspace and Enter, send them directly using the reliable logical
|
||||
// key data. This is required because for some IMEs (ko/zh/ja) returning
|
||||
// `handled` prevents the IME from processing the key through onChanged.
|
||||
if (isAndroid && androidSoftKeyboardActive) {
|
||||
if (e is KeyDownEvent || e is KeyRepeatEvent) {
|
||||
if (e.logicalKey == LogicalKeyboardKey.backspace) {
|
||||
inputKey('VK_BACK', press: true);
|
||||
} else if (e.logicalKey == LogicalKeyboardKey.enter ||
|
||||
e.logicalKey == LogicalKeyboardKey.numpadEnter) {
|
||||
inputKey('VK_RETURN', press: true);
|
||||
}
|
||||
}
|
||||
return KeyEventResult.handled;
|
||||
}
|
||||
if (!isInputSourceFlutter) {
|
||||
if (isDesktop) {
|
||||
return KeyEventResult.handled;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue