https://bugs.kde.org/show_bug.cgi?id=527400

            Bug ID: 527400
           Summary: companion change needed in kdeconnect-android
    Classification: Applications
           Product: kdeconnect
      Version First 26.08.2
       Reported In:
          Platform: Other
                OS: Microsoft Windows
            Status: REPORTED
          Severity: critical
          Priority: NOR
         Component: desktop-application
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

Created attachment 197321
  --> https://bugs.kde.org/attachment.cgi?id=197321&action=edit
companion change needed in kdeconnect-android

# Feature request (English, for KDE GitLab)

> Target repo: **kdeconnect-kde** (desktop); companion change required in 
> **kdeconnect-android** (phone keyboard).  
> Drafted from `kde-kbd-ime-switch.md`.

---

## Title

Feature request: option to send **committed text** (bypass IME) in the remote
keyboard / mousepad plugin

## Summary

Add an opt-in toggle — **"Send as committed text (bypass IME)"** — to the
remote keyboard (mousepad) plugin. When enabled, the phone sends
already-composed text as a single committed-string message instead of a stream
of key events, and the desktop inserts it by paste (or by Unicode char
injection) so the desktop Input Method Editor (IME) does **not** re-segment it.
This fixes garbled CJK (and other composable) input on Windows/desktop when
typing via the phone.

## Motivation / Problem

When the phone is used as a remote keyboard to type into a desktop application,
KDE Connect injects the characters as **individual key events**. On platforms
with an active IME — most visibly Windows with Microsoft Pinyin / Chinese,
Japanese, Korean, but the same class of bug applies anywhere an IME is in
composition state — those events are fed into the IME's composition buffer,
which **re-tokenizes and re-submits** the text. Observable consequences:

- Reordered characters (e.g. `为PVC主连写一个15分钟周期策略` becomes
`为PVC5分钟周期策略...主连写一个`).
- Dropped characters (`15` → `5`).
- Wrong candidates injected by the desktop IME.

There is currently **no way** to deliver already-composed final text through
the keyboard plugin; users must either (a) switch the desktop IME to English,
or (b) fall back to the clipboard plugin. Both are workarounds, not a real fix.

## Proposed solution

### 1. The toggle

- Name: `Send as committed text (bypass IME)`.
- Location: **phone-side** keyboard plugin settings (composition happens on the
phone, so the switch belongs there).
- Default: **off** (preserves current key-event behaviour and full support for
special keys / shortcuts).
- Scope: applies only to **text runs**; arrow keys, modifiers and shortcuts
continue to be sent as key events and are unaffected.

### 2. Behaviour when enabled

When the phone IME finishes a composition (commit), the plugin sends the
**final string** as one committed-text packet instead of a batch of key events.

### 3. Desktop-side handling (on receiving the committed-text packet)

- **Option A — clipboard + paste (recommended, cross-platform):** save current
clipboard → set clipboard to the string → send `Esc` (cancel any in-flight
composition) → send `Ctrl+V` → restore clipboard. Pasting bypasses IME
composition on Wayland, X11 and Windows.
- **Option B — Unicode char injection (cleaner on Windows):** on Windows use
`SendInput` with `KEYEVENTF_UNICODE` to deliver each character directly as
`WM_CHAR` (the IME will not re-compose it); on X11 use `XTest` with the
resolved Unicode keysym. Does not touch the clipboard and coexists with
special-key sending. Limitation: Wayland input injection is restricted, so
Option A is more reliable there.

### 4. Protocol / packet change

Extend the `kdeconnect.mousepad` packet:

- Add a `text` field carrying the committed UTF-8 string, plus a subtype/marker
distinguishing it from the existing key-event fields (`key` / `specialKey`),
**or**
- introduce a dedicated message type such as `kdeconnect.mousepad.string`.

Special keys must keep using the existing key-event path so shortcuts and
navigation keep working.

## Affected components

| Repo                 | Component                                             
   | Change                                                                    
                                         |
| -------------------- |
--------------------------------------------------------- |
-------------------------------------------------------------------------------------------------------------------
|
| `kdeconnect-android` | `plugins/keyboard` (remote keyboard
`InputMethodService`) | Add the settings toggle; on commit, when enabled, send
the committed-text packet instead of dispatching key events. |
| `kdeconnect-kde`     | `plugins/mousepad`                                    
   | Add a receive branch for the committed-text packet implementing Option A
(and Option B on Windows).                 |

## Alternatives considered

1. **Tell users to use the clipboard plugin.** Already possible and IME-safe,
but less convenient than typing directly — it is a workaround, not a fix.
2. **Always paste instead of key events (change the default).** Breaks special
keys / shortcuts and is undesirable as a default.
3. **Fix it via OS / IME settings.** Out of KDE Connect's control and not
portable across users.

## Additional context (IME background)

An IME only re-composes input that arrives as **key events**. Final text
delivered as a **string** (paste, or `WM_CHAR`/`KEYEVENTF_UNICODE`) is never
re-tokenized, which is exactly why the clipboard-plugin path already works. The
proposed toggle essentially automates that safe path for the keyboard plugin.

## Possible implementation sketch (illustrative)

**Android (`plugins/keyboard`):**

```kotlin
// when the IME commits a composed string and the toggle is ON
if (prefs.bypassIme) {
    val np = NetworkPacket(PACKET_TYPE_MOUSEPAD_STRING)
    np["text"] = committedText
    device.sendPacket(np)
} else {
    // current behaviour: dispatch as key events
}
```

**Desktop (`plugins/mousepad`, C++ / Windows Option B):**

```cpp
// on receiving the committed-text packet
const QString text = np.get<QString>(QStringLiteral("text"));
INPUT inputs[1];
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki.wScan = text[0].unicode();
inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;   // delivered as WM_CHAR, IME won't
re-compose
SendInput(1, inputs, sizeof(INPUT));
// (loop per character; Option A uses clipboard + Ctrl+V instead)
```

## Environment where the bug is reproduced

- OS: Windows 10/11, display language Chinese (Simplified) — Microsoft Pinyin
IME active.
- KDE Connect: Microsoft Store build `26.801.6731.0` (x64); the bug is not
version-specific (it is inherent to key-event injection + active IME).
- Also affects other IME languages (JA/KO) and likely any desktop where an IME
is in composition state.

---

*Note: this is a feature request. A working implementation would need changes
in both `kdeconnect-android` and `kdeconnect-kde`; the sketches above are
illustrative, not a finished patch.*

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to