mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
UI+LibWeb+WebContent: Implement KeyEvent repeat property
When a platform key press or release event is repeated, we now pass along a `repeat` flag to indicate that auto-repeating is happening. This flag eventually ends up in `KeyboardEvent.repeat`.
This commit is contained in:
parent
cf315d54ec
commit
9309cc9df3
Notes:
github-actions[bot]
2024-10-22 15:21:37 +00:00
Author: https://github.com/gmta Commit: https://github.com/LadybirdBrowser/ladybird/commit/9309cc9df32 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1913 Reviewed-by: https://github.com/trflynn89 ✅
13 changed files with 39 additions and 35 deletions
|
@ -297,6 +297,7 @@ Web::KeyEvent ns_event_to_key_event(Web::KeyEvent::Type type, NSEvent* event)
|
|||
{
|
||||
auto modifiers = ns_modifiers_to_key_modifiers(event.modifierFlags);
|
||||
auto key_code = ns_key_code_to_key_code(event.keyCode, modifiers);
|
||||
auto repeat = event.isARepeat;
|
||||
|
||||
// FIXME: WebContent should really support multi-code point key events.
|
||||
u32 code_point = 0;
|
||||
|
@ -312,7 +313,7 @@ Web::KeyEvent ns_event_to_key_event(Web::KeyEvent::Type type, NSEvent* event)
|
|||
if (code_point >= 0xE000 && code_point <= 0xF8FF)
|
||||
code_point = 0;
|
||||
|
||||
return { type, key_code, modifiers, code_point, make<KeyData>(event) };
|
||||
return { type, key_code, modifiers, code_point, repeat, make<KeyData>(event) };
|
||||
}
|
||||
|
||||
NSEvent* key_event_to_ns_event(Web::KeyEvent const& event)
|
||||
|
|
|
@ -899,15 +899,15 @@ void WebContentView::enqueue_native_event(Web::KeyEvent::Type type, QKeyEvent co
|
|||
auto to_web_event = [&]() -> Web::KeyEvent {
|
||||
if (event.key() == Qt::Key_Backtab) {
|
||||
// Qt transforms Shift+Tab into a "Backtab", so we undo that transformation here.
|
||||
return { type, Web::UIEvents::KeyCode::Key_Tab, Web::UIEvents::Mod_Shift, '\t', make<KeyData>(event) };
|
||||
return { type, Web::UIEvents::KeyCode::Key_Tab, Web::UIEvents::Mod_Shift, '\t', event.isAutoRepeat(), make<KeyData>(event) };
|
||||
}
|
||||
|
||||
if (event.key() == Qt::Key_Enter || event.key() == Qt::Key_Return) {
|
||||
// This ensures consistent behavior between systems that treat Enter as '\n' and '\r\n'
|
||||
return { type, Web::UIEvents::KeyCode::Key_Return, Web::UIEvents::Mod_Shift, '\n', make<KeyData>(event) };
|
||||
return { type, Web::UIEvents::KeyCode::Key_Return, Web::UIEvents::Mod_Shift, '\n', event.isAutoRepeat(), make<KeyData>(event) };
|
||||
}
|
||||
|
||||
return { type, keycode, modifiers, code_point, make<KeyData>(event) };
|
||||
return { type, keycode, modifiers, code_point, event.isAutoRepeat(), make<KeyData>(event) };
|
||||
};
|
||||
|
||||
enqueue_input_event(to_web_event());
|
||||
|
|
|
@ -79,7 +79,7 @@ void Internals::send_text(HTML::HTMLElement& target, String const& text, WebIDL:
|
|||
target.focus();
|
||||
|
||||
for (auto code_point : text.code_points())
|
||||
page.handle_keydown(UIEvents::code_point_to_key_code(code_point), modifiers, code_point);
|
||||
page.handle_keydown(UIEvents::code_point_to_key_code(code_point), modifiers, code_point, false);
|
||||
}
|
||||
|
||||
void Internals::send_key(HTML::HTMLElement& target, String const& key_name, WebIDL::UnsignedShort modifiers)
|
||||
|
@ -87,12 +87,12 @@ void Internals::send_key(HTML::HTMLElement& target, String const& key_name, WebI
|
|||
auto key_code = UIEvents::key_code_from_string(key_name);
|
||||
target.focus();
|
||||
|
||||
internals_page().handle_keydown(key_code, modifiers, 0);
|
||||
internals_page().handle_keydown(key_code, modifiers, 0, false);
|
||||
}
|
||||
|
||||
void Internals::commit_text()
|
||||
{
|
||||
internals_page().handle_keydown(UIEvents::Key_Return, 0, 0);
|
||||
internals_page().handle_keydown(UIEvents::Key_Return, 0, 0, false);
|
||||
}
|
||||
|
||||
void Internals::click(double x, double y)
|
||||
|
|
|
@ -840,7 +840,7 @@ constexpr bool should_ignore_keydown_event(u32 code_point, u32 modifiers)
|
|||
return code_point == 0 || code_point == 27;
|
||||
}
|
||||
|
||||
EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML::Navigable& navigable, UIEvents::KeyCode key, u32 modifiers, u32 code_point)
|
||||
EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML::Navigable& navigable, UIEvents::KeyCode key, u32 modifiers, u32 code_point, bool repeat)
|
||||
{
|
||||
JS::GCPtr<DOM::Document> document = navigable.active_document();
|
||||
if (!document)
|
||||
|
@ -852,15 +852,15 @@ EventResult EventHandler::fire_keyboard_event(FlyString const& event_name, HTML:
|
|||
if (is<HTML::NavigableContainer>(*focused_element)) {
|
||||
auto& navigable_container = verify_cast<HTML::NavigableContainer>(*focused_element);
|
||||
if (navigable_container.content_navigable())
|
||||
return fire_keyboard_event(event_name, *navigable_container.content_navigable(), key, modifiers, code_point);
|
||||
return fire_keyboard_event(event_name, *navigable_container.content_navigable(), key, modifiers, code_point, repeat);
|
||||
}
|
||||
|
||||
auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point);
|
||||
auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point, repeat);
|
||||
return focused_element->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
|
||||
}
|
||||
|
||||
// FIXME: De-duplicate this. This is just to prevent wasting a KeyboardEvent allocation when recursing into an (i)frame.
|
||||
auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point);
|
||||
auto event = UIEvents::KeyboardEvent::create_from_platform_event(document->realm(), event_name, key, modifiers, code_point, repeat);
|
||||
|
||||
JS::GCPtr target = document->body() ?: &document->root();
|
||||
return target->dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
|
||||
|
@ -911,14 +911,14 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con
|
|||
return document->root().dispatch_event(event) ? EventResult::Accepted : EventResult::Cancelled;
|
||||
}
|
||||
|
||||
EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u32 code_point)
|
||||
EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u32 code_point, bool repeat)
|
||||
{
|
||||
if (!m_navigable->active_document())
|
||||
return EventResult::Dropped;
|
||||
if (!m_navigable->active_document()->is_fully_active())
|
||||
return EventResult::Dropped;
|
||||
|
||||
auto dispatch_result = fire_keyboard_event(UIEvents::EventNames::keydown, m_navigable, key, modifiers, code_point);
|
||||
auto dispatch_result = fire_keyboard_event(UIEvents::EventNames::keydown, m_navigable, key, modifiers, code_point, repeat);
|
||||
if (dispatch_result != EventResult::Accepted)
|
||||
return dispatch_result;
|
||||
|
||||
|
@ -926,7 +926,7 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
|
|||
// 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)) {
|
||||
dispatch_result = fire_keyboard_event(UIEvents::EventNames::keypress, m_navigable, key, modifiers, code_point);
|
||||
dispatch_result = fire_keyboard_event(UIEvents::EventNames::keypress, m_navigable, key, modifiers, code_point, repeat);
|
||||
if (dispatch_result != EventResult::Accepted)
|
||||
return dispatch_result;
|
||||
}
|
||||
|
@ -1171,9 +1171,9 @@ EventResult EventHandler::handle_keydown(UIEvents::KeyCode key, u32 modifiers, u
|
|||
return EventResult::Accepted;
|
||||
}
|
||||
|
||||
EventResult EventHandler::handle_keyup(UIEvents::KeyCode key, u32 modifiers, u32 code_point)
|
||||
EventResult EventHandler::handle_keyup(UIEvents::KeyCode key, u32 modifiers, u32 code_point, [[maybe_unused]] bool repeat)
|
||||
{
|
||||
return fire_keyboard_event(UIEvents::EventNames::keyup, m_navigable, key, modifiers, code_point);
|
||||
return fire_keyboard_event(UIEvents::EventNames::keyup, m_navigable, key, modifiers, code_point, false);
|
||||
}
|
||||
|
||||
void EventHandler::handle_paste(String const& text)
|
||||
|
|
|
@ -34,8 +34,8 @@ public:
|
|||
|
||||
EventResult handle_drag_and_drop_event(DragEvent::Type, CSSPixelPoint, CSSPixelPoint screen_position, unsigned button, unsigned buttons, unsigned modifiers, Vector<HTML::SelectedFile> files);
|
||||
|
||||
EventResult handle_keydown(UIEvents::KeyCode, unsigned modifiers, u32 code_point);
|
||||
EventResult handle_keyup(UIEvents::KeyCode, unsigned modifiers, u32 code_point);
|
||||
EventResult handle_keydown(UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
EventResult handle_keyup(UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
|
||||
void set_mouse_event_tracking_paintable(Painting::Paintable*);
|
||||
|
||||
|
@ -49,7 +49,7 @@ private:
|
|||
bool focus_next_element();
|
||||
bool focus_previous_element();
|
||||
|
||||
EventResult fire_keyboard_event(FlyString const& event_name, HTML::Navigable&, UIEvents::KeyCode, unsigned modifiers, u32 code_point);
|
||||
EventResult fire_keyboard_event(FlyString const& event_name, HTML::Navigable&, UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
[[nodiscard]] EventResult input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable&, u32 code_point);
|
||||
CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const;
|
||||
CSSPixelPoint compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const;
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Web {
|
|||
|
||||
KeyEvent KeyEvent::clone_without_chrome_data() const
|
||||
{
|
||||
return { type, key, modifiers, code_point, nullptr };
|
||||
return { type, key, modifiers, code_point, repeat, nullptr };
|
||||
}
|
||||
|
||||
MouseEvent MouseEvent::clone_without_chrome_data() const
|
||||
|
@ -34,6 +34,7 @@ ErrorOr<void> IPC::encode(Encoder& encoder, Web::KeyEvent const& event)
|
|||
TRY(encoder.encode(event.key));
|
||||
TRY(encoder.encode(event.modifiers));
|
||||
TRY(encoder.encode(event.code_point));
|
||||
TRY(encoder.encode(event.repeat));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -44,8 +45,9 @@ ErrorOr<Web::KeyEvent> IPC::decode(Decoder& decoder)
|
|||
auto key = TRY(decoder.decode<Web::UIEvents::KeyCode>());
|
||||
auto modifiers = TRY(decoder.decode<Web::UIEvents::KeyModifier>());
|
||||
auto code_point = TRY(decoder.decode<u32>());
|
||||
auto repeat = TRY(decoder.decode<bool>());
|
||||
|
||||
return Web::KeyEvent { type, key, modifiers, code_point, nullptr };
|
||||
return Web::KeyEvent { type, key, modifiers, code_point, repeat, nullptr };
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
@ -34,6 +34,7 @@ struct KeyEvent {
|
|||
UIEvents::KeyCode key { UIEvents::KeyCode::Key_Invalid };
|
||||
UIEvents::KeyModifier modifiers { UIEvents::KeyModifier::Mod_None };
|
||||
u32 code_point { 0 };
|
||||
bool repeat { false };
|
||||
|
||||
OwnPtr<ChromeInputData> chrome_data;
|
||||
};
|
||||
|
|
|
@ -216,14 +216,14 @@ EventResult Page::handle_drag_and_drop_event(DragEvent::Type type, DevicePixelPo
|
|||
return top_level_traversable()->event_handler().handle_drag_and_drop_event(type, device_to_css_point(position), device_to_css_point(screen_position), button, buttons, modifiers, move(files));
|
||||
}
|
||||
|
||||
EventResult Page::handle_keydown(UIEvents::KeyCode key, unsigned modifiers, u32 code_point)
|
||||
EventResult Page::handle_keydown(UIEvents::KeyCode key, unsigned modifiers, u32 code_point, bool repeat)
|
||||
{
|
||||
return focused_navigable().event_handler().handle_keydown(key, modifiers, code_point);
|
||||
return focused_navigable().event_handler().handle_keydown(key, modifiers, code_point, repeat);
|
||||
}
|
||||
|
||||
EventResult Page::handle_keyup(UIEvents::KeyCode key, unsigned modifiers, u32 code_point)
|
||||
EventResult Page::handle_keyup(UIEvents::KeyCode key, unsigned modifiers, u32 code_point, bool repeat)
|
||||
{
|
||||
return focused_navigable().event_handler().handle_keyup(key, modifiers, code_point);
|
||||
return focused_navigable().event_handler().handle_keyup(key, modifiers, code_point, repeat);
|
||||
}
|
||||
|
||||
void Page::set_top_level_traversable(JS::NonnullGCPtr<HTML::TraversableNavigable> navigable)
|
||||
|
|
|
@ -100,8 +100,8 @@ public:
|
|||
|
||||
EventResult handle_drag_and_drop_event(DragEvent::Type, DevicePixelPoint, DevicePixelPoint screen_position, unsigned button, unsigned buttons, unsigned modifiers, Vector<HTML::SelectedFile> files);
|
||||
|
||||
EventResult handle_keydown(UIEvents::KeyCode, unsigned modifiers, u32 code_point);
|
||||
EventResult handle_keyup(UIEvents::KeyCode, unsigned modifiers, u32 code_point);
|
||||
EventResult handle_keydown(UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
EventResult handle_keyup(UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
|
||||
Gfx::Palette palette() const;
|
||||
CSSPixelRect web_exposed_screen_area() const;
|
||||
|
|
|
@ -668,7 +668,7 @@ static DOMKeyLocation get_event_location(KeyCode platform_key, unsigned modifier
|
|||
return DOMKeyLocation::Standard;
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<KeyboardEvent> KeyboardEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, KeyCode platform_key, unsigned modifiers, u32 code_point)
|
||||
JS::NonnullGCPtr<KeyboardEvent> KeyboardEvent::create_from_platform_event(JS::Realm& realm, FlyString const& event_name, KeyCode platform_key, unsigned modifiers, u32 code_point, bool repeat)
|
||||
{
|
||||
auto event_key = MUST(get_event_key(platform_key, code_point));
|
||||
auto event_code = MUST(get_event_code(platform_key, modifiers));
|
||||
|
@ -683,7 +683,7 @@ JS::NonnullGCPtr<KeyboardEvent> KeyboardEvent::create_from_platform_event(JS::Re
|
|||
event_init.shift_key = modifiers & Mod_Shift;
|
||||
event_init.alt_key = modifiers & Mod_Alt;
|
||||
event_init.meta_key = modifiers & Mod_Super;
|
||||
event_init.repeat = false;
|
||||
event_init.repeat = repeat;
|
||||
event_init.is_composing = false;
|
||||
event_init.key_code = key_code;
|
||||
event_init.char_code = char_code;
|
||||
|
|
|
@ -38,7 +38,7 @@ class KeyboardEvent final : public UIEvent {
|
|||
|
||||
public:
|
||||
[[nodiscard]] static JS::NonnullGCPtr<KeyboardEvent> create(JS::Realm&, FlyString const& event_name, KeyboardEventInit const& = {});
|
||||
[[nodiscard]] static JS::NonnullGCPtr<KeyboardEvent> create_from_platform_event(JS::Realm&, FlyString const& event_name, KeyCode, unsigned modifiers, u32 code_point);
|
||||
[[nodiscard]] static JS::NonnullGCPtr<KeyboardEvent> create_from_platform_event(JS::Realm&, FlyString const& event_name, KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<KeyboardEvent>> construct_impl(JS::Realm&, FlyString const& event_name, KeyboardEventInit const&);
|
||||
|
||||
virtual ~KeyboardEvent() override;
|
||||
|
|
|
@ -902,7 +902,7 @@ static ErrorOr<void, WebDriver::Error> dispatch_key_down_action(ActionObject::Ke
|
|||
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.
|
||||
bool repeat = source.pressed.contains(key);
|
||||
|
||||
// 4. Let code be the code for raw key.
|
||||
auto code = key_code_data(raw_key);
|
||||
|
@ -945,7 +945,7 @@ static ErrorOr<void, WebDriver::Error> dispatch_key_down_action(ActionObject::Ke
|
|||
// 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);
|
||||
browsing_context.page().handle_keydown(code.code, event.modifiers, event.code_point, repeat);
|
||||
|
||||
// 13. Return success with data null.
|
||||
return {};
|
||||
|
@ -1005,7 +1005,7 @@ static ErrorOr<void, WebDriver::Error> dispatch_key_up_action(ActionObject::KeyF
|
|||
// 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);
|
||||
browsing_context.page().handle_keyup(code.code, event.modifiers, event.code_point, false);
|
||||
|
||||
// 13. Return success with data null.
|
||||
return {};
|
||||
|
|
|
@ -189,9 +189,9 @@ void ConnectionFromClient::process_next_input_event()
|
|||
[&](Web::KeyEvent const& event) {
|
||||
switch (event.type) {
|
||||
case Web::KeyEvent::Type::KeyDown:
|
||||
return page->page().handle_keydown(event.key, event.modifiers, event.code_point);
|
||||
return page->page().handle_keydown(event.key, event.modifiers, event.code_point, event.repeat);
|
||||
case Web::KeyEvent::Type::KeyUp:
|
||||
return page->page().handle_keyup(event.key, event.modifiers, event.code_point);
|
||||
return page->page().handle_keyup(event.key, event.modifiers, event.code_point, event.repeat);
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue