[iOS] Soft keyboard: first letter of every Pinyin (IME) composition is sent to the remote while still composing
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 74/100
調査の方向性
flutter/lib/mobile/pages/remote_page.dart の _handleIOSSoftKeyboardInput から始めて、inputChar() が入力を送信する前に、変換中のテキストがどのように処理されるかを追ってください。issue の nihao の並びを手がかりに、最初のキー入力時と部分確定時の動作を確認してください。変換中のテキストがローカルにとどまり、確定済みのテキストだけが送信されれば完了です。payload にはテストファイル名を含めません。
索引モデルが issue の本文から書いたものです。
説明
Bug Description
Keyboard mode: N/A (mobile soft keyboard, no mode switch on mobile).
When typing Chinese with the iOS system Pinyin keyboard in the iOS client, the first letter of every new composition is sent to the remote host immediately, while it is still marked (composing) text on the phone. The rest of the composition is held back correctly. English input with the iOS English keyboard is not affected.
When a candidate is committed, the client sends VK_BACK to remove the leaked letter and then sends the committed characters. So in the simplest case the final text is right, but the host sees a stray letter for every word, and anything on the host that reacts to that letter (autocomplete popups, shortcuts, terminal apps, a host-side IME) gets out of sync with the follow-up backspace. In practice this shows up as garbled or dropped characters when typing Chinese.
Root cause — flutter/lib/mobile/pages/remote_page.dart, _handleIOSSoftKeyboardInput (line 257 at tag 1.4.5, line 351 on master as of 2026-10-20):
if (_textController.value.isComposingRangeValid) {
final composingLength = _textController.value.composing.end -
_textController.value.composing.start;
if (composingLength > newStr.length) {
_value = oldValue;
return;
}
}
On the first keystroke of a composition the composing range is exactly the new string (composingLength == newStr.length == 1), so 1 > 1 is false and the letter falls through to inputChar().
Trace for typing nihao and picking 你好:
| keystroke | composing text | guard | sent to host |
|---|---|---|---|
n |
n |
1 > 1 → false |
n |
i |
ni |
2 > 1 → true |
nothing |
h, a, o |
nihao |
true | nothing |
| pick 你好 | (none) | not composing | VK_BACK, then 你好 |
From reading the code (not verified separately on device), the same guard also leaks on a partial commit: committing 你 while hao is still composing gives newStr = "你hao" (length 4) vs composingLength = 3, so 你hao is sent and corrected later with three VK_BACKs.
How to Reproduce
- Connect from the iOS client to a Linux host (X11).
- Focus a text field on the host and open the soft keyboard.
- Switch the iPhone keyboard to Chinese (Simplified) Pinyin and type
n. - The letter
nshows up on the host right away, although it is still underlined (composing) on the phone. Typing more letters sends nothing until a candidate is picked.
Expected Behavior
Nothing should be sent while the text is composing; only committed text should be sent. On a partial commit, only the committed part (the text before composing.start) should be sent.
Operating system(s) on local (controlling) side and remote (controlled) side
iOS -> Ubuntu 22.04 (GNOME on X11, IBus)
RustDesk Version(s) on local (controlling) side and remote (controlled) side
iOS app (App Store) -> 1.4.5; the code above is unchanged on master
Screenshots
N/A - code-level analysis; the table above shows the event sequence.
Additional Context
Suggested fix direction: changing > to >= would stop the first-letter leak but not the partial-commit case. A more complete fix is to diff only the committed part of the text: when isComposingRangeValid, use text.substring(0, composing.start) as the new value and never send the composing part.
Related: #16527 (single committed CJK characters go through the raw key path). That is a different root cause, and its proposal keeps the composing guards unchanged, so it does not cover this one.
Host side ruled out: on the Linux X11 host, English and Chinese text injected with xdotool (the same libxdo calls key_sequence / key_click use) arrives intact with and without IBus, so the problem is on the client side.
- 主要言語
- Rust
- スター
- 126k
- フォーク
- 19.7k
- 平均マージ
- 1日 14時間
- マージ済み PR(30日)
- 74
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
rustdesk/rustdesk のほかの issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
rustdesk/rustdesk#15642 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 3/5 1〜2日 初心者へのやさしさ 58/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
-
[Linux] Recent sessions and favorites silently empty when `xdg-user-dir` is not installed対応中かも @bercedev が 1 日前に担当しました。 オープンbug
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 38/100
メンテナーはふだん 1 日以内に返信
rustdesk/rustdesk の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
longbridge/gpui-kit#3620 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
mongodb/kingfisher#564 ·
メンテナーはふだん 1 日以内に返信
-
bug qq-feedback
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
corro-client drops the last byte of a response line that has no trailing newline対応中かも @RaphaelFakhri が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
-
proxy: include denial_category in the "proxy request denied" log line対応中かも @sreyas-endor が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
nolabs-ai/nono#2172 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信