MicrosoftEdge / MicrosoftEdge/WebView2Feedback

[Problem/Bug]: IME composition window jumps to the top-left of the screen after the host window is resized

Open
#5,675 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
PowerShell
Stars
526
Forks
67
PR merge metrics
No merged PRs in 30d

Description

What happened?
What happened?

Resize the host window, then start typing with a Korean IME. The in-progress composition is drawn in
a floating window at the top-left corner of the screen instead of at the caret. The committed text
still goes into the input correctly, it's only the composition that's displaced.

It doesn't sort itself out. It stays wrong until you move the window with the mouse, or click away to
another window and come back. Then the next resize does it again.

The input is a plain <input>. No canvas editor, no EditContext, nothing custom.

Edge and Chrome don't do this. Only WebView2.


Things I checked that turned out not to be it

Posting these so nobody has to redo them:

  • The child windows keeping up with the parent. Chrome_RenderWidgetHostHWND picks up the new
    geometry 28ms after the parent resize. (Intermediate D3D Window takes ~1.2s, but that one has no
    caret in it.)
  • My app blocking the main thread and delaying a caret update. Longest frame gap over the two
    seconds after a resize was 0ms.
  • The page-side caret being in the wrong place. I logged the focused element's rect across resizes,
    it tracks the caret and stays inside the window every time.
  • MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC) after the resize. No effect.
  • NotifyParentWindowPositionChanged() after the resize. I called it ten times spread over
    0-1100ms so the timing couldn't be the reason it missed. Still no effect.

It isn't specific to one UI framework either. The stock Tauri repro above keeps the default window
decorations, and #2241 reports the same thing from WinUI3. And since the browser doesn't do it but
WebView2 does, my guess is it sits in the hosting layer rather than the Chromium IME code they share.
I can't see inside the runtime to confirm that though.

If it helps as a starting point: in Chromium the caret position reaches TSF through
InputMethodWinTSF::OnCaretBoundsChanged -> TSFBridge::OnTextLayoutChanged ->
TSFTextStore::SendOnLayoutChange -> ITextStoreACPSink::OnLayoutChange. If that doesn't fire after
a host resize, GetTextExt would go on returning a stale rect or TS_E_NOLAYOUT, and a floating
composition window at the screen origin is what you'd expect to see. That's a guess, I haven't been
able to verify it.

Related

Checked the open bug list first. Closest ones, and why I filed separately:

  • #1611 is about an already-open candidate window not following when the window is moved. Mine is
    a resize, it affects a composition that starts afterwards, and it lands at the screen origin rather
    than staying where it was. Moving the window is one of the things that fixes mine.
  • #2241 is the same family from WinUI3, but there's no trigger or repro on it.
  • #5570 is IME candidate position in composition mode over RDP.

If you think these are all one defect, feel free to fold this in. The repro and the checks above
should still be useful.

Importance

Moderate. My app's user experience is affected, but still usable.

Runtime Channel

Stable release (WebView2 Runtime)

Runtime Version

151.0.4129.86

SDK Version

webview2-com 0.38.2 (Rust bindings via Tauri 2.11.5 / wry 0.55.1)

Framework

Win32

Operating System

Windows 11

OS Version

10.0.26200

Repro steps

I hit this in my own app but it reproduces in a stock Tauri project, so there's no custom code involved:

pnpm create tauri-app imetest --template vanilla --manager pnpm --yes
cd imetest && pnpm install
pnpm tauri dev

Replace src/index.html with this, that's the whole page:

  <!doctype html>
  <html><head><meta charset="UTF-8" /></head>
  <body style="padding:24px;font-family:system-ui">
	<input style="width:90%;font-size:20px;padding:12px" />
  </body></html>

Steps:

  1. Set the OS input method to a composition IME. I used the Korean Microsoft IME (0412).
  2. Click the input, type a syllable so a composition happens.
  3. Resize the window.
  4. Type again straight away. Don't press anything else first and don't move the mouse.

Expected: the composition appears at the caret.
Actual: it appears at the top-left corner of the screen, outside the window.

Image

One thing worth knowing if you try to reproduce it: moving the mouse or clicking anywhere in the
window clears it. So if you do either between steps 3 and 4 you won't see it, and it looks like it
fixes itself after a moment. It doesn't. Hands off the keyboard and mouse, it stays wrong
indefinitely.

Repros in Edge Browser

No, issue does not reproduce in the corresponding Edge version

Regression

Don't know

Last working version (if regression)

n/a

No response

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce with the stock Tauri app, replacing src/index.html with the minimal input page and following the Korean IME resize steps. Start by tracing Chromium’s InputMethodWinTSF::OnCaretBoundsChanged through TSFBridge::OnTextLayoutChanged, TSFTextStore::SendOnLayoutChange, and ITextStoreACPSink::OnLayoutChange. Done means a composition started after resizing is positioned at the caret without moving the window or changing focus.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, tauri
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.