mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
LibWeb: Implement dispatching WebDriver key down and key up actions
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
This commit is contained in:
parent
5b2633d90f
commit
d6a8fc00c3
Notes:
github-actions[bot]
2024-10-10 08:42:10 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/d6a8fc00c34 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1706
2 changed files with 385 additions and 7 deletions
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Enumerate.h>
|
#include <AK/Enumerate.h>
|
||||||
|
#include <AK/Find.h>
|
||||||
#include <AK/GenericShorthands.h>
|
#include <AK/GenericShorthands.h>
|
||||||
#include <AK/JsonArray.h>
|
#include <AK/JsonArray.h>
|
||||||
#include <AK/JsonObject.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
|
// 6. If key is not a String containing a single unicode code point [or grapheme cluster?] return error with error
|
||||||
// code invalid argument.
|
// 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
|
// 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");
|
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.
|
// 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.
|
// 8. Return success with data action.
|
||||||
return action;
|
return action;
|
||||||
|
@ -626,6 +630,379 @@ static void dispatch_pause_action()
|
||||||
// 1. Return success with data null.
|
// 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
|
// 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)
|
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();
|
dispatch_pause_action();
|
||||||
break;
|
break;
|
||||||
case ActionObject::Subtype::KeyDown:
|
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:
|
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:
|
case ActionObject::Subtype::PointerDown:
|
||||||
TRY(dispatch_pointer_down_action(action_object.pointer_up_down_fields(), source->get<PointerInputSource>(), global_key_state, browsing_context));
|
TRY(dispatch_pointer_down_action(action_object.pointer_up_down_fields(), source->get<PointerInputSource>(), global_key_state, browsing_context));
|
||||||
break;
|
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.
|
// 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);
|
return dispatch_actions(input_state, move(actions_by_tick), browsing_context, move(actions_options), on_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ struct ActionObject {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KeyFields {
|
struct KeyFields {
|
||||||
String value;
|
u32 value { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PointerFields {
|
struct PointerFields {
|
||||||
|
|
Loading…
Reference in a new issue