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