1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:57:35 +00:00

Ladybird/AppKit: Handle input events through LibWebView

The AppKit chrome currently handles all input events before selectively
forwarding those events to WebContent. This means that WebContent does
not see events like cmd+c.

Here, we make use of LibWebView's input handling and wait for LibWebView
to inform the chrome that it should handle the event itself.
This commit is contained in:
Timothy Flynn 2024-03-05 16:11:22 -05:00 committed by Andreas Kling
parent c1476c3405
commit 2c31ef11bc
5 changed files with 130 additions and 98 deletions

View file

@ -67,6 +67,11 @@ struct HideCursor {
@property (nonatomic, strong) NSTextField* status_label;
@property (nonatomic, strong) NSAlert* dialog;
// NSEvent does not provide a way to mark whether it has been handled, nor can we attach user data to the event. So
// when we dispatch the event for a second time after WebContent has had a chance to handle it, we must track that
// event ourselves to prevent indefinitely repeating the event.
@property (nonatomic, strong) NSEvent* event_being_redispatched;
@end
@implementation LadybirdWebView
@ -284,6 +289,14 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_
[self.observer onFaviconChange:bitmap];
};
m_web_view_bridge->on_finish_handling_key_event = [self](auto const& key_event) {
NSEvent* event = Ladybird::key_event_to_ns_event(key_event);
self.event_being_redispatched = event;
[NSApp sendEvent:event];
self.event_being_redispatched = nil;
};
m_web_view_bridge->on_scroll = [self](auto position) {
auto content_rect = [self frame];
auto document_rect = [[self documentView] frame];
@ -1238,82 +1251,90 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_
- (void)mouseMoved:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::None);
m_web_view_bridge->mouse_move_event(position, screen_position, button, modifiers);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseMove, event, self, [self scrollView], GUI::MouseButton::None);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)scrollWheel:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Middle);
CGFloat delta_x = -[event scrollingDeltaX];
CGFloat delta_y = -[event scrollingDeltaY];
if (![event hasPreciseScrollingDeltas]) {
delta_x *= [self scrollView].horizontalLineScroll;
delta_y *= [self scrollView].verticalLineScroll;
}
m_web_view_bridge->mouse_wheel_event(position, screen_position, button, modifiers, delta_x, delta_y);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseWheel, event, self, [self scrollView], GUI::MouseButton::Middle);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)mouseDown:(NSEvent*)event
{
[[self window] makeFirstResponder:self];
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Primary);
if (event.clickCount % 2 == 0) {
m_web_view_bridge->mouse_double_click_event(position, screen_position, button, modifiers);
} else {
m_web_view_bridge->mouse_down_event(position, screen_position, button, modifiers);
}
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseDown, event, self, [self scrollView], GUI::MouseButton::Primary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)mouseUp:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Primary);
m_web_view_bridge->mouse_up_event(position, screen_position, button, modifiers);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseUp, event, self, [self scrollView], GUI::MouseButton::Primary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)mouseDragged:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Primary);
m_web_view_bridge->mouse_move_event(position, screen_position, button, modifiers);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseMove, event, self, [self scrollView], GUI::MouseButton::Primary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)rightMouseDown:(NSEvent*)event
{
[[self window] makeFirstResponder:self];
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Secondary);
if (event.clickCount % 2 == 0) {
m_web_view_bridge->mouse_double_click_event(position, screen_position, button, modifiers);
} else {
m_web_view_bridge->mouse_down_event(position, screen_position, button, modifiers);
}
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseDown, event, self, [self scrollView], GUI::MouseButton::Primary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)rightMouseUp:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Secondary);
m_web_view_bridge->mouse_up_event(position, screen_position, button, modifiers);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseUp, event, self, [self scrollView], GUI::MouseButton::Secondary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (void)rightMouseDragged:(NSEvent*)event
{
auto [position, screen_position, button, modifiers] = Ladybird::ns_event_to_mouse_event(event, self, GUI::MouseButton::Secondary);
m_web_view_bridge->mouse_move_event(position, screen_position, button, modifiers);
auto mouse_event = Ladybird::ns_event_to_mouse_event(Web::MouseEvent::Type::MouseMove, event, self, [self scrollView], GUI::MouseButton::Secondary);
m_web_view_bridge->enqueue_input_event(move(mouse_event));
}
- (BOOL)performKeyEquivalent:(NSEvent*)event
{
if ([event window] != [self window]) {
return NO;
}
if ([[self window] firstResponder] != self) {
return NO;
}
if (self.event_being_redispatched == event) {
return NO;
}
[self keyDown:event];
return YES;
}
- (void)keyDown:(NSEvent*)event
{
auto [key_code, modifiers, code_point] = Ladybird::ns_event_to_key_event(event);
m_web_view_bridge->key_down_event(key_code, modifiers, code_point);
if (self.event_being_redispatched == event) {
return;
}
auto key_event = Ladybird::ns_event_to_key_event(Web::KeyEvent::Type::KeyDown, event);
m_web_view_bridge->enqueue_input_event(move(key_event));
}
- (void)keyUp:(NSEvent*)event
{
auto [key_code, modifiers, code_point] = Ladybird::ns_event_to_key_event(event);
m_web_view_bridge->key_up_event(key_code, modifiers, code_point);
if (self.event_being_redispatched == event) {
return;
}
auto key_event = Ladybird::ns_event_to_key_event(Web::KeyEvent::Type::KeyUp, event);
m_web_view_bridge->enqueue_input_event(move(key_event));
}
@end