Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 4951276cc765d82514a1a3d7d6ef10e363ea7d18
      
https://github.com/WebKit/WebKit/commit/4951276cc765d82514a1a3d7d6ef10e363ea7d18
  Author: Ryosuke Niwa <[email protected]>
  Date:   2026-05-14 (Thu, 14 May 2026)

  Changed paths:
    M Source/WebKit/UIProcess/mac/WebViewImpl.mm
    M Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
    M Tools/Scripts/webkitpy/api_tests/allowlist.txt
    M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/mac/WKWebViewMacEditingTests.mm

  Log Message:
  -----------
  REGRESSION(310826@main): Vietnamese & Korean keyboard gets out of modeless 
input method in Mail Compose
https://bugs.webkit.org/show_bug.cgi?id=314823
rdar://176847897

Reviewed by Wenson Hsieh.

InputMethodUsesCorrectKeyEventOrder (turned on by default in 310826@main, 
originally added in
297270@main to fix Devanagari typing on docs.google.com) defers setMarkedText: 
and insertText: calls
from the input method's handleEventByInputMethod: callback into a queue 
(m_collectedKeypressCommands).
The queue is replayed in the web process's keydown default handler, ensuring 
keydown fires before
downstream events such as compositionstart and input.

There was an unintended consequence from this change: while the input method is 
still inside its
callback, it polls selectedRange to verify that its insertText: took effect. 
Because the queued command
hasn't reached the web process yet, the poll returns the pre-keystroke cursor, 
which is logically stale
by the inserted text length. Modeless input methods such as Vietnamese Simple 
Telex and 2-Set Korean
interpret that as "my insertion didn't stick" and abandon the modeless path, 
switching back to the mode
which uses setMarkedText:-based for the rest of the session in applications 
such as Mail and Notes.

There were also two other related issues of the same root cause:
  - Once an input method is confident enough to keep going in modeless mode, it 
commits via insertText:
    with a non-NSNotFound replacementRange (e.g. insertText:"vi" 
replacementRange:(0,1) to extend 'v'
    into "vi"). The queue's KeypressCommand constructor ignored 
replacementRange, and the queue path
    asserted it was NSNotFound.
  - When the IME returned handled=YES for a purely-insertText: keystroke with 
no prior composition,
    handleEditingKeyboardEvent's event.handledByInputMethod() branch (added by 
313212@main) executed
    the command during the keydown default handler. That dispatched a TextInput 
event with
    underlyingEvent set to keydown, which trips the assertion in 
EventHandler::handleTextInputEvent
    requiring a keypress as the underlying event instead.

This PR implements three narrow changes in 
Source/WebKit/UIProcess/mac/WebViewImpl.mm:

  1. Modeless commit routing in interpretKeyEvent's completion handler: when 
the input method's
     commands are purely insertText: (no setMarkedText:, no other) and 
editorState().hasComposition is
     false, force handled=NO. The keypress flow then runs and 
executeKeypressCommandsInternal fires
     insertText: during the Char phase with underlyingEvent=keypress — no 
assertion.
     The !hasComposition guard preserves 313212@main's Japanese Enter-commit 
fix: insertText:"k" with
     prior composition stays handled=YES, keydown gets keyCode 229, and 
google.com doesn't misread it
     as a real Enter.
  2. selectedRange staging in selectedRangeWithCompletionHandler: when every 
queued keypress command
     is insertText:, add the cumulative text length to the cursor returned to 
the input method.
     The input method observes its own insertion reflected and stays in 
modeless mode. If any
     setMarkedText: is in the queue, the input method is already composing and 
the unstaged value is
     correct.
  3. Replacement-range queueing in WebViewImpl::insertText: the queue path uses 
the existing 6-arg
     KeypressCommand constructor (already used by setMarkedText:) so it carries 
replacementRange.
     The IME's modeless continuation goes through the same queue as plain 
insertText:, executed in
     the web process's keydown default handler with the same event ordering.

In addition, this PR implements one fix in 
Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
  4. replacementRange execution in executeKeypressCommandsInternal for 
insertText:: when the queued
     command has a non-NSNotFound replacementRange, set the selection to that 
range first via
     frame->selection().setSelection(VisibleSelection(replacementRange)) then 
call editor->insertText.
     This mirrors what WebPage::insertTextAsync already does for the same case.

Test: 
TestWebKitAPI.WKWebViewMacEditingTests.KeyDownForModelessInputMethodInsertUsesRealKeyCode
      
TestWebKitAPI.WKWebViewMacEditingTests.ModelessInputMethodInsertTextWithReplacementRangeInsertsCorrectly
      
TestWebKitAPI.WKWebViewMacEditingTests.ModelessInputMethodEventOrderingMatchesNormalTyping

* Source/WebKit/UIProcess/mac/WebViewImpl.mm:
(WebKit::WebViewImpl::interpretKeyEvent):
(WebKit::WebViewImpl::insertText):
(WebKit::WebViewImpl::selectedRangeWithCompletionHandler):
* Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::executeKeypressCommandsInternal):
* Tools/Scripts/webkitpy/api_tests/allowlist.txt:
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/mac/WKWebViewMacEditingTests.mm:
(TestWebKitAPI::TEST(WKWebViewMacEditingTests, 
KeyDownForModelessInputMethodInsertUsesRealKeyCode)):
(TestWebKitAPI::TEST(WKWebViewMacEditingTests, 
ModelessInputMethodInsertTextWithReplacementRangeInsertsCorrectly)):
(TestWebKitAPI::TEST(WKWebViewMacEditingTests, 
ModelessInputMethodEventOrderingMatchesNormalTyping)):

Canonical link: https://commits.webkit.org/313286@main



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to