Skip to content

Fix windows osr key event dom codes (#2597) #4215

Open
rjx-ray wants to merge 4 commits into
chromiumembedded:masterfrom
rjx-ray:keyevent-domcodes-fix
Open

Fix windows osr key event dom codes (#2597) #4215
rjx-ray wants to merge 4 commits into
chromiumembedded:masterfrom
rjx-ray:keyevent-domcodes-fix

Conversation

@rjx-ray

@rjx-ray rjx-ray commented Jul 15, 2026

Copy link
Copy Markdown

This PR is a resubmission of https://bitbucket.org/chromiumembedded/cef/pull-requests/336 and fixes issue #2597.
It ensures that correct DOM codes are sent with osr key events.
The original PR code worked perfectly but it was never accepted due to lack of a unit test.
We have been patching CEF for many years with this code as some web sites do not work correctly without it.

Recently I noticed that CLAUDE_TEST_INSTRUCTIONS.md is now available so decided to have a go with it and this PR is the result.
I have checked that the new unit test fails with current CEF master and passes with this PR code.
Also that https://dvcs.w3.org/hg/d4e/raw-file/tip/key-event-test.html now reports correct DOM codes with cefclient --off-screen-rendering-enabled
This PR applies only to Windows builds, I believe that it will not affect Mac or Linux builds but I have been unable to test that.

@magreenblatt magreenblatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review findings from comparison with the current CEF implementation and Chromium Windows key-event conversion.

ui::KeyboardCodeForWindowsKeyCode(key_event.windows_key_code);
ui::DomCode dom_code =
ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
ui::DomCode dom_code = ui::KeycodeConverter::NativeKeycodeToDomCode(

@magreenblatt magreenblatt Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Please preserve the existing raw scan-code representation. This now unconditionally treats native_key_code as a Windows LPARAM. Before this patch, passing raw scan code 0x001E directly produced KeyA; after GetScanCodeFromLParam() it becomes zero and produces an unidentified DOM code. That representation is consistent with the current public description (the platform actual key code) and with the behavior of the existing implementation, even though cefclient passes LPARAM. Please accept both forms; for example, treat values confined to the low 16 bits as raw scan codes and values with an upper word as LPARAM; and document Windows LPARAM as the preferred form. Repeat-bit inference should likewise only apply to the LPARAM form; raw-code callers can use EVENTFLAG_IS_REPEAT.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A concrete compatibility implementation could decode the two representations structurally:

namespace {

struct DecodedWindowsNativeKeyCode {
  uint16_t scan_code;
  bool is_lparam;
};

DecodedWindowsNativeKeyCode DecodeWindowsNativeKeyCode(int native_key_code) {
  const uint32_t value = static_cast<uint32_t>(native_key_code);

  // Legacy/raw Windows scan codes, including E0-prefixed extended codes such
  // as 0xE01D, fit in the low 16 bits. A normal keyboard-message LPARAM stores
  // its scan code in bits 16-23 and therefore has a non-zero upper word.
  if ((value & 0xFFFF0000u) == 0) {
    return {static_cast<uint16_t>(value), false};
  }

  return {ui::GetScanCodeFromLParam(
              static_cast<LPARAM>(static_cast<int32_t>(value))),
          true};
}

}  // namespace

TranslateUiKeyEvent can then use the decoded scan code and only interpret bit 30 when the input was actually classified as an LPARAM:

const auto decoded =
    DecodeWindowsNativeKeyCode(key_event.native_key_code);
ui::DomCode dom_code =
    ui::KeycodeConverter::NativeKeycodeToDomCode(decoded.scan_code);

// Existing raw-scan-code callers can express repeat through
// EVENTFLAG_IS_REPEAT, which TranslateUiEventModifiers already handles.
if (decoded.is_lparam && type == ui::EventType::kKeyPressed &&
    (static_cast<uint32_t>(key_event.native_key_code) & 0x40000000u)) {
  flags |= ui::EF_IS_REPEAT;
}

I would document Windows LPARAM as the preferred representation in cef_key_event_t::native_key_code, while explicitly retaining low-16-bit scan codes for compatibility. Suggested coverage:

  • 0x001E (raw) and 0x001E0001 (LPARAM) both produce KeyA.
  • 0xE01D (raw extended) and 0x011D0001 (extended LPARAM) both produce ControlRight.
  • 0x401E0001 produces KeyA with repeat.
  • A raw 0x001E event with EVENTFLAG_IS_REPEAT also produces repeat.

The structural rule deliberately treats an upper-word-zero value as the legacy raw form. A malformed or synthetic LPARAM with no scan code is inherently ambiguous; favoring the previously accepted representation is the compatibility-preserving choice. I would avoid falling back based on DomCode::NONE, because that would make input interpretation depend on Chromium's evolving scan-code table.

// native_key_code
// 2. event.repeat is true for a keydown whose lParam bit 30 is set
// 3. event.repeat is always false for keyup events.
TEST(KeyboardDomCodeTest, DomCodeAndRepeatFlags) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Please cover the character-message path in this regression test. SendKeyDownUp sends only KEYEVENT_RAWKEYDOWN and KEYEVENT_KEYUP, so the test never exercises KEYEVENT_CHAR. Consequently it does not validate the accompanying cefclient/helper change for issue #2597 case 4, where a character such as a was incorrectly reported with NUMPAD location. Please send a character event and assert its code, location, and repeat, or add a focused test for the split modifier helper.


// Verifies that:
// 1. event.code is correctly derived from the scan-code portion of
// native_key_code

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3] Whitespace: This line has trailing whitespace, so the patch fails git diff --check.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've now pushed updates which I believe address the above points.

While testing the changes I had an occasional issue with OnLoadEnd not being called and the test timing out so I'm now using an OnPaint check to signify readiness instead. This is as per the OSR tests in osr_display_unittest.cc.

}

TrackCallback got_paint_;
TrackCallback got_load_end_; // informational only

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Please remove this unused field. After the readiness path was changed from OnLoadEnd to OnPaint, got_load_end_ is never referenced. Chromium’s Windows warning configuration (clang-cl /W4 /WX) diagnoses this as private field 'got_load_end_' is not used [-Werror,-Wunused-private-field], so the ceftests target will fail to compile.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, done

@magreenblatt

Copy link
Copy Markdown
Collaborator

Please rebase this branch cleanly onto the current master before merging. The branch currently places the original PR commit before rewritten copies of three changes that already exist on masterceftests: Skip GBK download tests without a UTF-8 locale, Fix validation of newer CEF structures, and ai: Add tmp/ to .gitignore. As a result, the PR commit list and changed-file view include unrelated files. The desired history is current master followed only by the keyboard-event commits.

@rjx-ray
rjx-ray force-pushed the keyevent-domcodes-fix branch from d8fbd7d to 41d5dbb Compare July 22, 2026 08:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants