LibWeb: Fire keypress event for Enter, Shift+Enter, and Ctrl+Enter keys

For web compat and interop with other engines, this change makes us fire
“keypress” events for the Enter key and for the combination of the Enter
key with the Shift or Ctrl keys — despite the fact the UI Events spec
states at https://w3c.github.io/uievents/#event-type-keypress it must be
fired “if and only if that key normally produces a character value”.

See https://github.com/w3c/uievents/issues/183#issuecomment-448091687
and https://github.com/w3c/uievents/issues/266#issuecomment-1887917756.
This commit is contained in:
sideshowbarker 2025-01-24 16:25:59 +09:00 committed by Sam Atkins
parent be38acfad9
commit 738cb24691
Notes: github-actions[bot] 2025-01-31 12:08:14 +00:00
3 changed files with 51 additions and 3 deletions

View file

@ -1068,6 +1068,18 @@ static bool produces_character_value(u32 code_point)
|| Unicode::code_point_has_symbol_general_category(code_point);
}
// https://github.com/w3c/uievents/issues/183#issuecomment-448091687
static bool is_enter_key_or_interoperable_enter_key_combo(UIEvents::KeyCode key, u32 modifiers)
{
if (key != UIEvents::KeyCode::Key_Return)
return false;
if (!modifiers)
return true;
if (modifiers & (UIEvents::KeyModifier::Mod_Shift | UIEvents::KeyModifier::Mod_Ctrl))
return true;
return false;
}
EventResult EventHandler::input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable& navigable, u32 code_point)
{
auto document = navigable.active_document();
@ -1115,7 +1127,10 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
// https://w3c.github.io/uievents/#event-type-keypress
// If supported by a user agent, this event MUST be dispatched when a key is pressed down, if and only if that key
// normally produces a character value.
if (produces_character_value(code_point)) {
// AD-HOC: For web compat and for interop with other engines, we make an exception here for the Enter key. See:
// https://github.com/w3c/uievents/issues/183#issuecomment-448091687 and
// https://github.com/w3c/uievents/issues/266#issuecomment-1887917756
if (produces_character_value(code_point) || is_enter_key_or_interoperable_enter_key_combo(key, modifiers)) {
dispatch_result = fire_keyboard_event(UIEvents::EventNames::keypress, m_navigable, key, modifiers, code_point, repeat);
if (dispatch_result != EventResult::Accepted)
return dispatch_result;

View file

@ -3,3 +3,12 @@ keypress key=A charCode=65
keydown key=Shift charCode=0
keydown key=B charCode=0
keypress key=B charCode=66
keydown key=Enter charCode=0
keypress key=Enter charCode=0
keydown key=Enter charCode=0 modifiers=Alt
keydown key=Enter charCode=0 modifiers=Control
keypress key=Enter charCode=0 modifiers=Control
keydown key=Enter charCode=0 modifiers=Shift
keypress key=Enter charCode=0 modifiers=Shift
keydown key=Enter charCode=0
keydown key=Enter charCode=0

View file

@ -4,15 +4,39 @@
test(() => {
let input = document.getElementById("input");
const modifierKeys = ['Alt', 'Control', 'Shift', 'Super', 'NumLock'];
input.addEventListener("keydown", e => {
println(`keydown key=${e.key} charCode=${e.charCode}`);
const activeModifiers = modifierKeys.filter(modifier => e.getModifierState(modifier));
if (activeModifiers.length > 0) {
println(`keydown key=${e.key} charCode=${e.charCode} modifiers=${activeModifiers.join(', ')}`);
} else {
println(`keydown key=${e.key} charCode=${e.charCode}`);
}
});
input.addEventListener("keypress", e => {
println(`keypress key=${e.key} charCode=${e.charCode}`);
const activeModifiers = modifierKeys.filter(modifier => e.getModifierState(modifier));
if (activeModifiers.length > 0) {
println(`keypress key=${e.key} charCode=${e.charCode} modifiers=${activeModifiers.join(', ')}`);
} else {
println(`keypress key=${e.key} charCode=${e.charCode}`);
}
});
internals.sendText(input, "A");
internals.sendKey(input, "LeftShift");
internals.sendText(input, "B");
internals.sendKey(input, "Return");
let modifiers = 1 << 0; // Mod_Alt
internals.sendKey(input, "Return", modifiers);
modifiers = 1 << 1; // Mod_Ctrl
internals.sendKey(input, "Return", modifiers);
modifiers = 1 << 2; // Mod_Shift
internals.sendKey(input, "Return", modifiers);
modifiers = 1 << 3; // Mod_Super
internals.sendKey(input, "Return", modifiers);
modifiers = 1 << 4; // Mod_Keypad
internals.sendKey(input, "Return", modifiers);
});
</script>