|
@@ -5,6 +5,7 @@
|
|
|
*/
|
|
|
|
|
|
#include <AK/Enumerate.h>
|
|
|
+#include <AK/Find.h>
|
|
|
#include <AK/GenericShorthands.h>
|
|
|
#include <AK/JsonArray.h>
|
|
|
#include <AK/JsonObject.h>
|
|
@@ -245,14 +246,17 @@ static ErrorOr<ActionObject, WebDriver::Error> process_key_action(String id, Jso
|
|
|
|
|
|
// 6. If key is not a String containing a single unicode code point [or grapheme cluster?] return error with error
|
|
|
// code invalid argument.
|
|
|
- if (Utf8View { key }.length() != 1) {
|
|
|
+ Utf8View utf8_key { key };
|
|
|
+
|
|
|
+ if (utf8_key.length() != 1) {
|
|
|
// FIXME: The spec seems undecided on whether grapheme clusters should be supported. Update this step to check
|
|
|
- // for graphemes if we end up needing to support them.
|
|
|
+ // for graphemes if we end up needing to support them. We would also need to update Page's key event
|
|
|
+ // handlers to support multi-code point events.
|
|
|
return WebDriver::Error::from_code(WebDriver::ErrorCode::InvalidArgument, "Property 'value' must be a single code point");
|
|
|
}
|
|
|
|
|
|
// 7. Set the value property on action to key.
|
|
|
- action.key_fields().value = MUST(String::from_byte_string(key));
|
|
|
+ action.key_fields().value = *utf8_key.begin();
|
|
|
|
|
|
// 8. Return success with data action.
|
|
|
return action;
|
|
@@ -626,6 +630,379 @@ static void dispatch_pause_action()
|
|
|
// 1. Return success with data null.
|
|
|
}
|
|
|
|
|
|
+// https://w3c.github.io/webdriver/#dfn-normalized-key-value
|
|
|
+static String normalized_key_value(u32 key)
|
|
|
+{
|
|
|
+ // The normalized key value for a raw key key is, if key appears in the table below, the string value in the second
|
|
|
+ // column on the row containing key's unicode code point in the first column, otherwise it is key.
|
|
|
+ // clang-format off
|
|
|
+ switch (key) {
|
|
|
+ case 0xE000: return "Unidentified"_string;
|
|
|
+ case 0xE001: return "Cancel"_string;
|
|
|
+ case 0xE002: return "Help"_string;
|
|
|
+ case 0xE003: return "Backspace"_string;
|
|
|
+ case 0xE004: return "Tab"_string;
|
|
|
+ case 0xE005: return "Clear"_string;
|
|
|
+ case 0xE006: return "Return"_string;
|
|
|
+ case 0xE007: return "Enter"_string;
|
|
|
+ case 0xE008: return "Shift"_string;
|
|
|
+ case 0xE009: return "Control"_string;
|
|
|
+ case 0xE00A: return "Alt"_string;
|
|
|
+ case 0xE00B: return "Pause"_string;
|
|
|
+ case 0xE00C: return "Escape"_string;
|
|
|
+ case 0xE00D: return " "_string;
|
|
|
+ case 0xE00E: return "PageUp"_string;
|
|
|
+ case 0xE00F: return "PageDown"_string;
|
|
|
+ case 0xE010: return "End"_string;
|
|
|
+ case 0xE011: return "Home"_string;
|
|
|
+ case 0xE012: return "ArrowLeft"_string;
|
|
|
+ case 0xE013: return "ArrowUp"_string;
|
|
|
+ case 0xE014: return "ArrowRight"_string;
|
|
|
+ case 0xE015: return "ArrowDown"_string;
|
|
|
+ case 0xE016: return "Insert"_string;
|
|
|
+ case 0xE017: return "Delete"_string;
|
|
|
+ case 0xE018: return ";"_string;
|
|
|
+ case 0xE019: return "="_string;
|
|
|
+ case 0xE01A: return "0"_string;
|
|
|
+ case 0xE01B: return "1"_string;
|
|
|
+ case 0xE01C: return "2"_string;
|
|
|
+ case 0xE01D: return "3"_string;
|
|
|
+ case 0xE01E: return "4"_string;
|
|
|
+ case 0xE01F: return "5"_string;
|
|
|
+ case 0xE020: return "6"_string;
|
|
|
+ case 0xE021: return "7"_string;
|
|
|
+ case 0xE022: return "8"_string;
|
|
|
+ case 0xE023: return "9"_string;
|
|
|
+ case 0xE024: return "*"_string;
|
|
|
+ case 0xE025: return "+"_string;
|
|
|
+ case 0xE026: return ","_string;
|
|
|
+ case 0xE027: return "-"_string;
|
|
|
+ case 0xE028: return "."_string;
|
|
|
+ case 0xE029: return "/"_string;
|
|
|
+ case 0xE031: return "F1"_string;
|
|
|
+ case 0xE032: return "F2"_string;
|
|
|
+ case 0xE033: return "F3"_string;
|
|
|
+ case 0xE034: return "F4"_string;
|
|
|
+ case 0xE035: return "F5"_string;
|
|
|
+ case 0xE036: return "F6"_string;
|
|
|
+ case 0xE037: return "F7"_string;
|
|
|
+ case 0xE038: return "F8"_string;
|
|
|
+ case 0xE039: return "F9"_string;
|
|
|
+ case 0xE03A: return "F10"_string;
|
|
|
+ case 0xE03B: return "F11"_string;
|
|
|
+ case 0xE03C: return "F12"_string;
|
|
|
+ case 0xE03D: return "Meta"_string;
|
|
|
+ case 0xE040: return "ZenkakuHankaku"_string;
|
|
|
+ case 0xE050: return "Shift"_string;
|
|
|
+ case 0xE051: return "Control"_string;
|
|
|
+ case 0xE052: return "Alt"_string;
|
|
|
+ case 0xE053: return "Meta"_string;
|
|
|
+ case 0xE054: return "PageUp"_string;
|
|
|
+ case 0xE055: return "PageDown"_string;
|
|
|
+ case 0xE056: return "End"_string;
|
|
|
+ case 0xE057: return "Home"_string;
|
|
|
+ case 0xE058: return "ArrowLeft"_string;
|
|
|
+ case 0xE059: return "ArrowUp"_string;
|
|
|
+ case 0xE05A: return "ArrowRight"_string;
|
|
|
+ case 0xE05B: return "ArrowDown"_string;
|
|
|
+ case 0xE05C: return "Insert"_string;
|
|
|
+ case 0xE05D: return "Delete"_string;
|
|
|
+ }
|
|
|
+ // clang-format on
|
|
|
+
|
|
|
+ return String::from_code_point(key);
|
|
|
+}
|
|
|
+
|
|
|
+struct KeyCodeData {
|
|
|
+ u32 key { 0 };
|
|
|
+ Optional<u32> alternate_key {};
|
|
|
+ UIEvents::KeyCode code { UIEvents::KeyCode::Key_Invalid };
|
|
|
+ UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
|
|
|
+};
|
|
|
+
|
|
|
+// https://w3c.github.io/webdriver/#dfn-code
|
|
|
+static KeyCodeData key_code_data(u32 code_point)
|
|
|
+{
|
|
|
+ // The code for key is the value in the last column of the following table on the row with key in either the first
|
|
|
+ // or second column, if any such row exists, otherwise it is undefined.
|
|
|
+ static auto key_code_data = to_array<KeyCodeData>({
|
|
|
+ { '`', '~', UIEvents::KeyCode::Key_Backtick },
|
|
|
+ { '\\', '|', UIEvents::KeyCode::Key_Backslash },
|
|
|
+ { 0xE003, {}, UIEvents::KeyCode::Key_Backspace },
|
|
|
+ { '[', '{', UIEvents::KeyCode::Key_LeftBracket },
|
|
|
+ { ']', '}', UIEvents::KeyCode::Key_RightBracket },
|
|
|
+ { ',', '<', UIEvents::KeyCode::Key_Comma },
|
|
|
+ { '0', ')', UIEvents::KeyCode::Key_0 },
|
|
|
+ { '1', '!', UIEvents::KeyCode::Key_1 },
|
|
|
+ { '2', '@', UIEvents::KeyCode::Key_2 },
|
|
|
+ { '3', '#', UIEvents::KeyCode::Key_3 },
|
|
|
+ { '4', '$', UIEvents::KeyCode::Key_4 },
|
|
|
+ { '5', '%', UIEvents::KeyCode::Key_5 },
|
|
|
+ { '6', '^', UIEvents::KeyCode::Key_6 },
|
|
|
+ { '7', '&', UIEvents::KeyCode::Key_7 },
|
|
|
+ { '8', '*', UIEvents::KeyCode::Key_8 },
|
|
|
+ { '9', '(', UIEvents::KeyCode::Key_9 },
|
|
|
+ { '=', '+', UIEvents::KeyCode::Key_Equal },
|
|
|
+ // FIXME: "IntlBackslash"
|
|
|
+ { 'a', 'A', UIEvents::KeyCode::Key_A },
|
|
|
+ { 'b', 'B', UIEvents::KeyCode::Key_B },
|
|
|
+ { 'c', 'C', UIEvents::KeyCode::Key_C },
|
|
|
+ { 'd', 'D', UIEvents::KeyCode::Key_D },
|
|
|
+ { 'e', 'E', UIEvents::KeyCode::Key_E },
|
|
|
+ { 'f', 'F', UIEvents::KeyCode::Key_F },
|
|
|
+ { 'g', 'G', UIEvents::KeyCode::Key_G },
|
|
|
+ { 'h', 'H', UIEvents::KeyCode::Key_H },
|
|
|
+ { 'i', 'I', UIEvents::KeyCode::Key_I },
|
|
|
+ { 'j', 'J', UIEvents::KeyCode::Key_J },
|
|
|
+ { 'k', 'K', UIEvents::KeyCode::Key_K },
|
|
|
+ { 'l', 'L', UIEvents::KeyCode::Key_L },
|
|
|
+ { 'm', 'M', UIEvents::KeyCode::Key_M },
|
|
|
+ { 'n', 'N', UIEvents::KeyCode::Key_N },
|
|
|
+ { 'o', 'O', UIEvents::KeyCode::Key_O },
|
|
|
+ { 'p', 'P', UIEvents::KeyCode::Key_P },
|
|
|
+ { 'q', 'Q', UIEvents::KeyCode::Key_Q },
|
|
|
+ { 'r', 'R', UIEvents::KeyCode::Key_R },
|
|
|
+ { 's', 'S', UIEvents::KeyCode::Key_S },
|
|
|
+ { 't', 'T', UIEvents::KeyCode::Key_T },
|
|
|
+ { 'u', 'U', UIEvents::KeyCode::Key_U },
|
|
|
+ { 'v', 'V', UIEvents::KeyCode::Key_V },
|
|
|
+ { 'w', 'W', UIEvents::KeyCode::Key_W },
|
|
|
+ { 'x', 'X', UIEvents::KeyCode::Key_X },
|
|
|
+ { 'y', 'Y', UIEvents::KeyCode::Key_Y },
|
|
|
+ { 'z', 'Z', UIEvents::KeyCode::Key_Z },
|
|
|
+ { '-', '_', UIEvents::KeyCode::Key_Minus },
|
|
|
+ { '.', '>', UIEvents::KeyCode::Key_Period },
|
|
|
+ { '\'', '"', UIEvents::KeyCode::Key_Apostrophe },
|
|
|
+ { ';', ':', UIEvents::KeyCode::Key_Semicolon },
|
|
|
+ { '/', '?', UIEvents::KeyCode::Key_Slash },
|
|
|
+ { ' ', {}, UIEvents::KeyCode::Key_Space },
|
|
|
+ { 0xE00A, {}, UIEvents::KeyCode::Key_LeftAlt },
|
|
|
+ { 0xE052, {}, UIEvents::KeyCode::Key_RightAlt },
|
|
|
+ { 0xE009, {}, UIEvents::KeyCode::Key_LeftControl },
|
|
|
+ { 0xE051, {}, UIEvents::KeyCode::Key_RightControl },
|
|
|
+ { 0xE006, {}, UIEvents::KeyCode::Key_Return },
|
|
|
+ { 0xE00B, {}, UIEvents::KeyCode::Key_PauseBreak },
|
|
|
+ { 0xE03D, {}, UIEvents::KeyCode::Key_LeftSuper },
|
|
|
+ { 0xE053, {}, UIEvents::KeyCode::Key_RightSuper },
|
|
|
+ { 0xE008, {}, UIEvents::KeyCode::Key_LeftShift },
|
|
|
+ { 0xE050, {}, UIEvents::KeyCode::Key_RightShift },
|
|
|
+ { 0xE00D, {}, UIEvents::KeyCode::Key_Space },
|
|
|
+ { 0xE004, {}, UIEvents::KeyCode::Key_Tab },
|
|
|
+ { 0xE017, {}, UIEvents::KeyCode::Key_Delete },
|
|
|
+ { 0xE010, {}, UIEvents::KeyCode::Key_End },
|
|
|
+ // FIXME: "Help"
|
|
|
+ { 0xE011, {}, UIEvents::KeyCode::Key_Home },
|
|
|
+ { 0xE016, {}, UIEvents::KeyCode::Key_Insert },
|
|
|
+ { 0xE00F, {}, UIEvents::KeyCode::Key_PageDown },
|
|
|
+ { 0xE00E, {}, UIEvents::KeyCode::Key_PageUp },
|
|
|
+ { 0xE015, {}, UIEvents::KeyCode::Key_Down },
|
|
|
+ { 0xE012, {}, UIEvents::KeyCode::Key_Left },
|
|
|
+ { 0xE014, {}, UIEvents::KeyCode::Key_Right },
|
|
|
+ { 0xE013, {}, UIEvents::KeyCode::Key_Up },
|
|
|
+ { 0xE00C, {}, UIEvents::KeyCode::Key_Escape },
|
|
|
+ { 0xE031, {}, UIEvents::KeyCode::Key_F1 },
|
|
|
+ { 0xE032, {}, UIEvents::KeyCode::Key_F2 },
|
|
|
+ { 0xE033, {}, UIEvents::KeyCode::Key_F3 },
|
|
|
+ { 0xE034, {}, UIEvents::KeyCode::Key_F4 },
|
|
|
+ { 0xE035, {}, UIEvents::KeyCode::Key_F5 },
|
|
|
+ { 0xE036, {}, UIEvents::KeyCode::Key_F6 },
|
|
|
+ { 0xE037, {}, UIEvents::KeyCode::Key_F7 },
|
|
|
+ { 0xE038, {}, UIEvents::KeyCode::Key_F8 },
|
|
|
+ { 0xE039, {}, UIEvents::KeyCode::Key_F9 },
|
|
|
+ { 0xE03A, {}, UIEvents::KeyCode::Key_F10 },
|
|
|
+ { 0xE03B, {}, UIEvents::KeyCode::Key_F11 },
|
|
|
+ { 0xE03C, {}, UIEvents::KeyCode::Key_F12 },
|
|
|
+ { 0xE019, {}, UIEvents::KeyCode::Key_Equal, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01A, 0xE05C, UIEvents::KeyCode::Key_0, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01B, 0xE056, UIEvents::KeyCode::Key_1, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01C, 0xE05B, UIEvents::KeyCode::Key_2, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01D, 0xE055, UIEvents::KeyCode::Key_3, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01E, 0xE058, UIEvents::KeyCode::Key_4, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE01F, {}, UIEvents::KeyCode::Key_5, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE020, 0xE05A, UIEvents::KeyCode::Key_6, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE021, 0xE057, UIEvents::KeyCode::Key_7, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE022, 0xE059, UIEvents::KeyCode::Key_8, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE023, 0xE054, UIEvents::KeyCode::Key_9, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE025, {}, UIEvents::KeyCode::Key_Plus, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE026, {}, UIEvents::KeyCode::Key_Comma, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE028, 0xE05D, UIEvents::KeyCode::Key_Period, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE029, {}, UIEvents::KeyCode::Key_Slash, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE007, {}, UIEvents::KeyCode::Key_Return, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE024, {}, UIEvents::KeyCode::Key_Asterisk, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ { 0xE027, {}, UIEvents::KeyCode::Key_Minus, UIEvents::KeyModifier::Mod_Keypad },
|
|
|
+ });
|
|
|
+
|
|
|
+ auto it = find_if(key_code_data.begin(), key_code_data.end(), [&](auto const& data) {
|
|
|
+ return data.key == code_point || data.alternate_key == code_point;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (it == key_code_data.end())
|
|
|
+ return { .key = code_point };
|
|
|
+ return *it;
|
|
|
+}
|
|
|
+
|
|
|
+struct KeyEvent {
|
|
|
+ u32 code_point { 0 };
|
|
|
+ UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
|
|
|
+};
|
|
|
+static KeyEvent key_code_to_page_event(u32 code_point, UIEvents::KeyModifier modifiers, KeyCodeData const& code)
|
|
|
+{
|
|
|
+ if (code_point >= 0xE000 && code_point <= 0xE05D) {
|
|
|
+ code_point = [&]() -> u32 {
|
|
|
+ // clang-format off
|
|
|
+ switch (code_point) {
|
|
|
+ case 0xE00D: return ' ';
|
|
|
+ case 0xE018: return ';';
|
|
|
+ case 0xE019: return '=';
|
|
|
+ case 0xE01A: return '0';
|
|
|
+ case 0xE01B: return '1';
|
|
|
+ case 0xE01C: return '2';
|
|
|
+ case 0xE01D: return '3';
|
|
|
+ case 0xE01E: return '4';
|
|
|
+ case 0xE01F: return '5';
|
|
|
+ case 0xE020: return '6';
|
|
|
+ case 0xE021: return '7';
|
|
|
+ case 0xE022: return '8';
|
|
|
+ case 0xE023: return '9';
|
|
|
+ case 0xE024: return '*';
|
|
|
+ case 0xE025: return '+';
|
|
|
+ case 0xE026: return ',';
|
|
|
+ case 0xE027: return '-';
|
|
|
+ case 0xE028: return '.';
|
|
|
+ case 0xE029: return '/';
|
|
|
+ default: return 0;
|
|
|
+ }
|
|
|
+ // clang-format on
|
|
|
+ }();
|
|
|
+ }
|
|
|
+
|
|
|
+ modifiers |= code.modifiers;
|
|
|
+
|
|
|
+ if (has_flag(modifiers, UIEvents::KeyModifier::Mod_Shift))
|
|
|
+ code_point = code.alternate_key.value_or(code_point);
|
|
|
+
|
|
|
+ return { code_point, modifiers };
|
|
|
+}
|
|
|
+
|
|
|
+// https://w3c.github.io/webdriver/#dfn-dispatch-a-keydown-action
|
|
|
+static ErrorOr<void, WebDriver::Error> dispatch_key_down_action(ActionObject::KeyFields const& action_object, KeyInputSource& source, GlobalKeyState const& global_key_state, HTML::BrowsingContext& browsing_context)
|
|
|
+{
|
|
|
+ // 1. Let raw key be equal to the action object's value property.
|
|
|
+ auto raw_key = action_object.value;
|
|
|
+
|
|
|
+ // 2. Let key be equal to the normalized key value for raw key.
|
|
|
+ auto key = normalized_key_value(raw_key);
|
|
|
+
|
|
|
+ // 3. If the source's pressed property contains key, let repeat be true, otherwise let repeat be false.
|
|
|
+ // FIXME: Add `repeat` support to Page::handle_keydown.
|
|
|
+
|
|
|
+ // 4. Let code be the code for raw key.
|
|
|
+ auto code = key_code_data(raw_key);
|
|
|
+
|
|
|
+ // 5. Let location be the key location for raw key.
|
|
|
+ // 6. Let charCode, keyCode and which be the implementation-specific values of the charCode, keyCode and which
|
|
|
+ // properties appropriate for a key with key key and location location on a 102 key US keyboard, following the
|
|
|
+ // guidelines in [UI-EVENTS].
|
|
|
+
|
|
|
+ auto modifiers = global_key_state.modifiers();
|
|
|
+
|
|
|
+ // 7. If key is "Alt", let source's alt property be true.
|
|
|
+ if (key == "Alt"sv) {
|
|
|
+ modifiers |= UIEvents::KeyModifier::Mod_Alt;
|
|
|
+ source.alt = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 8. If key is "Shift", let source's shift property be true.
|
|
|
+ else if (key == "Shift"sv) {
|
|
|
+ modifiers |= UIEvents::KeyModifier::Mod_Shift;
|
|
|
+ source.shift = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 9. If key is "Control", let source's ctrl property be true.
|
|
|
+ else if (key == "Control"sv) {
|
|
|
+ modifiers |= UIEvents::KeyModifier::Mod_Ctrl;
|
|
|
+ source.ctrl = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 10. If key is "Meta", let source's meta property be true.
|
|
|
+ else if (key == "Meta"sv) {
|
|
|
+ modifiers |= UIEvents::KeyModifier::Mod_Super;
|
|
|
+ source.meta = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 11. Add key to source's pressed property.
|
|
|
+ source.pressed.set(key);
|
|
|
+
|
|
|
+ // 12. Perform implementation-specific action dispatch steps on browsing context equivalent to pressing a key on the
|
|
|
+ // keyboard in accordance with the requirements of [UI-EVENTS], and producing the following events, as appropriate,
|
|
|
+ // with the specified properties. This will always produce events including at least a keyDown event.
|
|
|
+ auto event = key_code_to_page_event(raw_key, modifiers, code);
|
|
|
+ browsing_context.page().handle_keydown(code.code, event.modifiers, event.code_point);
|
|
|
+
|
|
|
+ // 13. Return success with data null.
|
|
|
+ return {};
|
|
|
+}
|
|
|
+
|
|
|
+// https://w3c.github.io/webdriver/#dfn-dispatch-a-keyup-action
|
|
|
+static ErrorOr<void, WebDriver::Error> dispatch_key_up_action(ActionObject::KeyFields const& action_object, KeyInputSource& source, GlobalKeyState const& global_key_state, HTML::BrowsingContext& browsing_context)
|
|
|
+{
|
|
|
+ // 1. Let raw key be equal to action object's value property.
|
|
|
+ auto raw_key = action_object.value;
|
|
|
+
|
|
|
+ // 2. Let key be equal to the normalized key value for raw key.
|
|
|
+ auto key = normalized_key_value(raw_key);
|
|
|
+
|
|
|
+ // 3. If the source's pressed item does not contain key, return.
|
|
|
+ if (!source.pressed.contains(key))
|
|
|
+ return {};
|
|
|
+
|
|
|
+ // 4. Let code be the code for raw key.
|
|
|
+ auto code = key_code_data(raw_key);
|
|
|
+
|
|
|
+ // 5. Let location be the key location for raw key.
|
|
|
+ // 6. Let charCode, keyCode and which be the implementation-specific values of the charCode, keyCode and which
|
|
|
+ // properties appropriate for a key with key key and location location on a 102 key US keyboard, following the
|
|
|
+ // guidelines in [UI-EVENTS].
|
|
|
+
|
|
|
+ auto modifiers = global_key_state.modifiers();
|
|
|
+
|
|
|
+ // 7. If key is "Alt", let source's alt property be false.
|
|
|
+ if (key == "Alt"sv) {
|
|
|
+ modifiers &= ~UIEvents::KeyModifier::Mod_Alt;
|
|
|
+ source.alt = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 8. If key is "Shift", let source's shift property be false.
|
|
|
+ else if (key == "Shift"sv) {
|
|
|
+ modifiers &= ~UIEvents::KeyModifier::Mod_Shift;
|
|
|
+ source.shift = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 9. If key is "Control", let source's ctrl property be false.
|
|
|
+ else if (key == "Control"sv) {
|
|
|
+ modifiers &= ~UIEvents::KeyModifier::Mod_Ctrl;
|
|
|
+ source.ctrl = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 10. If key is "Meta", let source's meta property be false.
|
|
|
+ else if (key == "Meta"sv) {
|
|
|
+ modifiers &= ~UIEvents::KeyModifier::Mod_Super;
|
|
|
+ source.meta = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 11. Remove key from sources's pressed property.
|
|
|
+ source.pressed.remove(key);
|
|
|
+
|
|
|
+ // 12. Perform implementation-specific action dispatch steps on browsing context equivalent to releasing a key on the
|
|
|
+ // keyboard in accordance with the requirements of [UI-EVENTS], and producing at least the following events with
|
|
|
+ // the specified properties:
|
|
|
+ auto event = key_code_to_page_event(raw_key, modifiers, code);
|
|
|
+ browsing_context.page().handle_keyup(code.code, event.modifiers, event.code_point);
|
|
|
+
|
|
|
+ // 13. Return success with data null.
|
|
|
+ return {};
|
|
|
+}
|
|
|
+
|
|
|
// https://w3c.github.io/webdriver/#dfn-dispatch-a-pointerdown-action
|
|
|
static ErrorOr<void, WebDriver::Error> dispatch_pointer_down_action(ActionObject::PointerUpDownFields const& action_object, PointerInputSource& source, GlobalKeyState const& global_key_state, HTML::BrowsingContext& browsing_context)
|
|
|
{
|
|
@@ -973,9 +1350,11 @@ ErrorOr<void, WebDriver::Error> dispatch_tick_actions(InputState& input_state, R
|
|
|
dispatch_pause_action();
|
|
|
break;
|
|
|
case ActionObject::Subtype::KeyDown:
|
|
|
- return WebDriver::Error::from_code(WebDriver::ErrorCode::UnsupportedOperation, "Key down events not implemented"sv);
|
|
|
+ TRY(dispatch_key_down_action(action_object.key_fields(), source->get<KeyInputSource>(), global_key_state, browsing_context));
|
|
|
+ break;
|
|
|
case ActionObject::Subtype::KeyUp:
|
|
|
- return WebDriver::Error::from_code(WebDriver::ErrorCode::UnsupportedOperation, "Key up events not implemented"sv);
|
|
|
+ TRY(dispatch_key_up_action(action_object.key_fields(), source->get<KeyInputSource>(), global_key_state, browsing_context));
|
|
|
+ break;
|
|
|
case ActionObject::Subtype::PointerDown:
|
|
|
TRY(dispatch_pointer_down_action(action_object.pointer_up_down_fields(), source->get<PointerInputSource>(), global_key_state, browsing_context));
|
|
|
break;
|
|
@@ -1025,5 +1404,4 @@ JS::NonnullGCPtr<JS::Cell> dispatch_list_of_actions(InputState& input_state, Vec
|
|
|
// 3. Return the result of dispatch actions with input state, actions by tick, browsing context, and actions options.
|
|
|
return dispatch_actions(input_state, move(actions_by_tick), browsing_context, move(actions_options), on_complete);
|
|
|
}
|
|
|
-
|
|
|
}
|