Quellcode durchsuchen

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.
Timothy Flynn vor 10 Monaten
Ursprung
Commit
eabd5b0f22
2 geänderte Dateien mit 45 neuen und 4 gelöschten Zeilen
  1. 8 4
      Ladybird/AppKit/UI/Event.mm
  2. 37 0
      Ladybird/AppKit/UI/LadybirdWebView.mm

+ 8 - 4
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 modifiers = ns_modifiers_to_key_modifiers(event.modifierFlags);
     auto key_code = ns_key_code_to_key_code(event.keyCode, modifiers);
     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.
     // 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.
     // NSEvent assigns PUA code points to to functional keys, e.g. arrow keys. Do not propagate them.
     if (code_point >= 0xE000 && code_point <= 0xF8FF)
     if (code_point >= 0xE000 && code_point <= 0xF8FF)

+ 37 - 0
Ladybird/AppKit/UI/LadybirdWebView.mm

@@ -58,6 +58,11 @@ struct HideCursor {
     Optional<String> m_context_menu_search_text;
     Optional<String> m_context_menu_search_text;
 
 
     Optional<HideCursor> m_hidden_cursor;
     Optional<HideCursor> 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<LadybirdWebViewObserver> observer;
 @property (nonatomic, weak) id<LadybirdWebViewObserver> observer;
@@ -135,6 +140,8 @@ struct HideCursor {
         [self addTrackingArea:area];
         [self addTrackingArea:area];
 
 
         [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeFileURL, nil]];
         [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeFileURL, nil]];
+
+        m_modifier_flags = 0;
     }
     }
 
 
     return self;
     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));
     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
 #pragma mark - NSDraggingDestination
 
 
 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)event
 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)event