1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:27:44 +00:00

LibWeb: Implement KeyboardEvent.key according to the spec

This implementation only includes key codes marked as required by the
spec, as those are the only keys we have in our kernel.
This commit is contained in:
Timothy Flynn 2023-07-08 19:19:26 -04:00 committed by Andreas Kling
parent 64022031c4
commit 71bf9f1d0d

View file

@ -5,6 +5,7 @@
*/
#include <AK/CharacterTypes.h>
#include <LibUnicode/CharacterTypes.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/UIEvents/KeyboardEvent.h>
@ -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<Optional<String>> 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<Optional<String>> 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<String> 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<String> 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<JS::NonnullGCPtr<KeyboardEvent>> 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));