Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: 0d1f138acdf6a28210cc38a6377894e8a5f84e67
      
https://github.com/WebKit/WebKit/commit/0d1f138acdf6a28210cc38a6377894e8a5f84e67
  Author: Alexey Proskuryakov <[email protected]>
  Date:   2026-10-07 (Wed, 07 Oct 2026)

  Changed paths:
    M Source/WebDriver/Session.cpp
    M Source/WebDriver/Session.h
    M Source/WebKit/UIProcess/Automation/Automation.json
    M Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp
    M Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h
    M Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp
    M WebDriverTests/TestExpectations.json

  Log Message:
  -----------
  "Only one CharKey may differ at a time" assertion failure when running 
WebDriver tests
https://bugs.webkit.org/show_bug.cgi?id=320476
rdar://183445273

Reviewed by BJ Burg.

The keyboard dispatch algorithm assumed that at most one key differs between 
two adjacent
input source states, and asserted otherwise. That assumption does not hold, for 
two reasons.

First, InputSourceState could only carry a single 'pressedCharKey', so a client 
with two
character keys held down at the same time had no way to say so. Perform Actions 
with
keyDown "a" followed by keyDown "b" therefore arrived as {"a"} and then {"b"} — 
a press and a
release within one tick — which tripped the assertion in a debug build, and in 
a release build
pressed "b" while dropping "a" from the tracked state without ever releasing 
it. Add
'pressedCharKeys' so that a set of held character keys can be expressed, and 
keep
'pressedCharKey' for clients and backends that do not support the new field.

Second, the keyframe that resets every input source (§17.6 Release Actions) 
releases everything
still held at once, so more than one key legitimately differs there. Simulate 
every difference
in order rather than only the first, and check the one-difference-per-tick 
invariant only for
keyframes that come from a tick.

Also reset input state when Release Actions cannot reach the page. That state 
is per session, so a
character key left pressed by a page that closed its own window was treated as 
still held down by
every later interaction in the session.

The corresponding safaridriver change is in the Safari repository; on its own 
this change fixes
Source/WebDriver, which is the driver used by the GTK, WPE, Windows and 
PlayStation ports.

Covered by existing tests in the imported WebDriver test suite:
perform_actions/key_events.py::test_sequence_of_keydown_printable_keys_sends_events,
 which was
the assertion failure, and 
release_actions/sequence.py::test_release_char_sequence_sends_keyup_events_in_reverse,
which releases several held keys at once.

* WebDriverTests/TestExpectations.json:
Remove the failure expectations for the two tests above, except on GTK for
test_sequence_of_keydown_printable_keys_sends_events, which expects keypress 
events that GTK3 does
not emit (webkit.org/b/224736), as for the neighboring tests.

* Source/WebDriver/Session.h:
Hold character keys in an ordered set instead of a single optional string.

* Source/WebDriver/Session.cpp:
(WebDriver::Session::performActions):
Add to and remove from that set on keyDown and keyUp, and send the whole set as
'pressedCharKeys'. Also send the most recently pressed key as 'pressedCharKey' 
so that a backend
without support for the new field behaves as it did before.

* Source/WebKit/UIProcess/Automation/Automation.json:
Add InputSourceState.pressedCharKeys and deprecate pressedCharKey.

* Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::performInteractionSequence):
Parse 'pressedCharKeys', validating each entry the way the singular field was 
validated, and fall
back to 'pressedCharKey' when the array is absent.
(WebKit::WebAutomationSession::cancelInteractionSequence):
When the page is gone, clear m_inputSources even though there is nowhere to 
dispatch release events
to, and reset m_currentModifiers with it, since that only changes when a 
release is dispatched and
would otherwise stay set for the rest of the session.

* Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h:
Add KeyboardInteractionSpec, and SimulatedInputKeyFrame::IsResetKeyFrame to 
distinguish the
keyframe that resets all input sources from one produced by a tick.

* Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp:
(WebKit::SimulatedInputKeyFrame::SimulatedInputKeyFrame):
Take and store whether this is the reset keyframe.
(WebKit::SimulatedInputKeyFrame::keyFrameToResetInputSources):
Mark the keyframe it produces as the reset keyframe.
(WebKit::SimulatedInputDispatcher::transitionInputSourceToState):
Collect every difference between the two keyboard states instead of assuming 
there is at most
one. Character keys are released in reverse order of being pressed, as §17.6 
Release Actions
requires. Assert that a keyframe from a tick yields at most one interaction; 
this replaces the two
per-key-type assertions and additionally covers a transition that changes both 
a character key
and a virtual key, which the previous structure could not see.
(WebKit::SimulatedInputDispatcher::dispatchKeyboardInteractions):
Added. Simulates the collected interactions one at a time, chaining each 
completion handler into
the next, and finishes the state transition after the last one.

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



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

Reply via email to