From eabd5b0f2271e7a89727daf80dd28623711f3416 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 8 Oct 2024 20:17:08 -0400 Subject: [PATCH] UI/AppKit: Send keyboard events for modifier-only key presses/releases If the user only presses the shift key, for example, we are required to still send that event to WebContent and generate the corresponding JS events. Unfortunately, NSApp does not inform us of these events via the keyDown/keyUp methods. We have to implement the flagsChanged interface, and track for ourselves what modifier keys were pressed or released. --- Ladybird/AppKit/UI/Event.mm | 12 ++++++--- Ladybird/AppKit/UI/LadybirdWebView.mm | 37 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Ladybird/AppKit/UI/Event.mm b/Ladybird/AppKit/UI/Event.mm index f119f587a5f..de029ca5367 100644 --- a/Ladybird/AppKit/UI/Event.mm +++ b/Ladybird/AppKit/UI/Event.mm @@ -298,11 +298,15 @@ 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 const* utf8 = [event.characters UTF8String]; - Utf8View utf8_view { StringView { utf8, strlen(utf8) } }; - // FIXME: WebContent should really support multi-code point key events. - auto code_point = utf8_view.is_empty() ? 0u : *utf8_view.begin(); + u32 code_point = 0; + + if (event.type == NSEventTypeKeyDown || event.type == NSEventTypeKeyUp) { + auto const* utf8 = [event.characters UTF8String]; + Utf8View utf8_view { StringView { utf8, strlen(utf8) } }; + + code_point = utf8_view.is_empty() ? 0u : *utf8_view.begin(); + } // NSEvent assigns PUA code points to to functional keys, e.g. arrow keys. Do not propagate them. if (code_point >= 0xE000 && code_point <= 0xF8FF) diff --git a/Ladybird/AppKit/UI/LadybirdWebView.mm b/Ladybird/AppKit/UI/LadybirdWebView.mm index 4b0504ebf6e..5905f4e5a3a 100644 --- a/Ladybird/AppKit/UI/LadybirdWebView.mm +++ b/Ladybird/AppKit/UI/LadybirdWebView.mm @@ -58,6 +58,11 @@ struct HideCursor { Optional m_context_menu_search_text; Optional m_hidden_cursor; + + // We have to send key events for modifer keys, but AppKit does not generate key down/up events when only a modifier + // key is pressed. Instead, we only receive an event that the modifier flags have changed, and we must determine for + // ourselves whether the modifier key was pressed or released. + NSEventModifierFlags m_modifier_flags; } @property (nonatomic, weak) id observer; @@ -135,6 +140,8 @@ struct HideCursor { [self addTrackingArea:area]; [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeFileURL, nil]]; + + m_modifier_flags = 0; } return self; @@ -1676,6 +1683,36 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ m_web_view_bridge->enqueue_input_event(move(key_event)); } +- (void)flagsChanged:(NSEvent*)event +{ + if (self.event_being_redispatched == event) { + return; + } + + auto enqueue_event_if_needed = [&](auto flag) { + auto is_flag_set = [&](auto flags) { return (flags & flag) != 0; }; + Web::KeyEvent::Type type; + + if (is_flag_set(event.modifierFlags) && !is_flag_set(m_modifier_flags)) { + type = Web::KeyEvent::Type::KeyDown; + } else if (!is_flag_set(event.modifierFlags) && is_flag_set(m_modifier_flags)) { + type = Web::KeyEvent::Type::KeyUp; + } else { + return; + } + + auto key_event = Ladybird::ns_event_to_key_event(type, event); + m_web_view_bridge->enqueue_input_event(move(key_event)); + }; + + enqueue_event_if_needed(NSEventModifierFlagShift); + enqueue_event_if_needed(NSEventModifierFlagControl); + enqueue_event_if_needed(NSEventModifierFlagOption); + enqueue_event_if_needed(NSEventModifierFlagCommand); + + m_modifier_flags = event.modifierFlags; +} + #pragma mark - NSDraggingDestination - (NSDragOperation)draggingEntered:(id)event