diff --git a/Userland/Libraries/LibWeb/UIEvents/KeyboardEvent.cpp b/Userland/Libraries/LibWeb/UIEvents/KeyboardEvent.cpp index 93b095ff7f..a97ac2c8ac 100644 --- a/Userland/Libraries/LibWeb/UIEvents/KeyboardEvent.cpp +++ b/Userland/Libraries/LibWeb/UIEvents/KeyboardEvent.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -66,18 +67,161 @@ static unsigned long determine_key_code(KeyCode platform_key, u32 code_point) return platform_key; } +// 3. Named key Attribute Values, https://www.w3.org/TR/uievents-key/#named-key-attribute-values +static ErrorOr> get_event_named_key(KeyCode platform_key) +{ + switch (platform_key) { + // 3.1. Special Keys, https://www.w3.org/TR/uievents-key/#keys-special + case KeyCode::Key_Invalid: + return "Unidentified"_string; + + // 3.2. Modifier Keys, https://www.w3.org/TR/uievents-key/#keys-modifier + case KeyCode::Key_Alt: + return "Alt"_string; + // FIXME: AltGraph + case KeyCode::Key_CapsLock: + return "CapsLock"_string; + case KeyCode::Key_Control: + return "Control"_string; + case KeyCode::Key_Super: + return "Meta"_string; + case KeyCode::Key_NumLock: + return "NumLock"_string; + case KeyCode::Key_ScrollLock: + return "ScrollLock"_string; + case KeyCode::Key_LeftShift: + case KeyCode::Key_RightShift: + return "Shift"_string; + + // 3.3. Whitespace Keys, https://www.w3.org/TR/uievents-key/#keys-whitespace + case KeyCode::Key_Return: + return "Enter"_string; + case KeyCode::Key_Tab: + return "Tab"_string; + case KeyCode::Key_Space: + return " "_string; + + // 3.4. Navigation Keys, https://www.w3.org/TR/uievents-key/#keys-navigation + case KeyCode::Key_Down: + return "ArrowDown"_string; + case KeyCode::Key_Left: + return "ArrowLeft"_string; + case KeyCode::Key_Right: + return "ArrowRight"_string; + case KeyCode::Key_Up: + return "ArrowUp"_string; + case KeyCode::Key_End: + return "End"_string; + case KeyCode::Key_Home: + return "Home"_string; + case KeyCode::Key_PageDown: + return "PageDown"_string; + case KeyCode::Key_PageUp: + return "PageUp"_string; + + // 3.5. Editing Keys, https://www.w3.org/TR/uievents-key/#keys-editing + case KeyCode::Key_Backspace: + return "Backspace"_string; + case KeyCode::Key_Delete: + return "Delete"_string; + case KeyCode::Key_Insert: + return "Insert"_string; + + // 3.6. UI Keys, https://www.w3.org/TR/uievents-key/#keys-ui + case KeyCode::Key_Menu: + return "ContextMenu"_string; + case KeyCode::Key_Escape: + return "Escape"_string; + // FIXME: Help + // FIXME: Pause + + // 3.7. Device Keys, https://www.w3.org/TR/uievents-key/#keys-device + case KeyCode::Key_PrintScreen: + return "PrintScreen"_string; + + // 3.9. General-Purpose Function Keys, https://www.w3.org/TR/uievents-key/#keys-function + case KeyCode::Key_F1: + return "F1"_string; + case KeyCode::Key_F2: + return "F2"_string; + case KeyCode::Key_F3: + return "F3"_string; + case KeyCode::Key_F4: + return "F4"_string; + case KeyCode::Key_F5: + return "F5"_string; + case KeyCode::Key_F6: + return "F6"_string; + case KeyCode::Key_F7: + return "F7"_string; + case KeyCode::Key_F8: + return "F8"_string; + case KeyCode::Key_F9: + return "F9"_string; + case KeyCode::Key_F10: + return "F10"_string; + case KeyCode::Key_F11: + return "F11"_string; + case KeyCode::Key_F12: + return "F12"_string; + + default: + break; + } + + return OptionalNone {}; +} + +// 2.1. Unicode Values, https://www.w3.org/TR/uievents-key/#keys-unicode +static ErrorOr> get_event_key_string(u32 code_point) +{ + auto is_non_control_character = [&]() { + // A non-control character is any valid Unicode character except those that are part of the "Other, Control" + // ("Cc") General Category. + static auto control_general_category = Unicode::general_category_from_string("Cc"sv); + if (!control_general_category.has_value()) + return true; + + return !Unicode::code_point_has_general_category(code_point, *control_general_category); + }; + + // A key string is a string containing a 0 or 1 non-control characters ("base" characters) followed by 0 or more + // combining characters. The string MUST be in Normalized Form C (NFC) as described in [UAX15]. + // FIXME: Our key events are currently set up to provide one code point at a time. We will need to handle multi- + // code point events and NFC normalize that string. + if (is_non_control_character()) + return String::from_code_point(code_point); + + return OptionalNone {}; +} + +// 2.2. Selecting key Attribute Values, https://www.w3.org/TR/uievents-key/#selecting-key-attribute-values static ErrorOr get_event_key(KeyCode platform_key, u32 code_point) { - auto event_key = String::from_deprecated_string(key_code_to_string(platform_key)); - if (event_key.is_error()) { - return event_key; + // 1. Let key be a DOMString initially set to "Unidentified". + // NOTE: We return "Unidentified" at the end to avoid needlessly allocating it here. + Optional key; + + // 2. If there exists an appropriate named key attribute value for this key event, then + if (auto named_key = TRY(get_event_named_key(platform_key)); named_key.has_value()) { + // 1. Set key to that named key attribute value. + key = named_key.release_value(); } - // Original case should be preserved for the key value of the event. - // https://www.w3.org/TR/uievents-key/#key-attr-values - if (is_ascii_lower_alpha(code_point)) { - event_key = event_key.release_value().to_lowercase(); + + // 3. Else, if the key event generates a valid key string, then + else if (auto key_string = TRY(get_event_key_string(code_point)); key_string.has_value()) { + // 1. Set key to that key string value. + key = key_string.release_value(); } - return event_key; + + // FIXME: 4. Else, if the key event has any modifier keys other than glyph modifier keys, then + // FIXME: 1. Set key to the key string that would have been generated by this event if it had been typed with all + // modifer keys removed except for glyph modifier keys. + + // 5. Return key as the key attribute value for this key event. + if (key.has_value()) + return key.release_value(); + return TRY("Unidentified"_string); } // 3. Keyboard Event code Value Tables, https://www.w3.org/TR/uievents-code/#code-value-tables @@ -344,7 +488,6 @@ WebIDL::ExceptionOr> KeyboardEvent::create_from_ { auto& vm = realm.vm(); - // FIXME: Figure out what these should actually contain. auto event_key = TRY_OR_THROW_OOM(vm, get_event_key(platform_key, code_point)); auto event_code = TRY_OR_THROW_OOM(vm, get_event_code(platform_key, modifiers));