From d2828e87228125820f570c894cad4fd436fc9e10 Mon Sep 17 00:00:00 2001 From: Szymon Piechaczek Date: Thu, 30 Jan 2025 20:27:50 +0100 Subject: [PATCH] gpui: Handle Swipe events to support navigation buttons on some mice (#23332) Closes #14170 To fix this, Zed needs to handle swipe events on its NSView. Logitech mice don't send the usual Mouse4 and Mouse5 buttons but emulate swipe gestures according to these websites: - https://superuser.com/a/1216049 - https://sensible-side-buttons.archagon.net/ Of course, the user can map these buttons to something else in the device's driver. Most IDEs (VSCode, IntelliJ) handle that correctly by default so it would be good to follow that pattern. Since it's my first contribution here, please let me know if I need to enhance this PR to make it good enough for the main branch. Release Notes: - Fixed mouse navigation buttons on some devices (Logitech, Mac OS) --- crates/gpui/src/platform/mac/events.rs | 27 ++++++++++++++++++++++++++ crates/gpui/src/platform/mac/window.rs | 4 ++++ 2 files changed, 31 insertions(+) diff --git a/crates/gpui/src/platform/mac/events.rs b/crates/gpui/src/platform/mac/events.rs index 56256aeffd..4d2fc12dc1 100644 --- a/crates/gpui/src/platform/mac/events.rs +++ b/crates/gpui/src/platform/mac/events.rs @@ -158,6 +158,33 @@ impl PlatformInput { }) }) } + // Some mice (like Logitech MX Master) send navigation buttons as swipe events + NSEventType::NSEventTypeSwipe => { + let navigation_direction = match native_event.phase() { + NSEventPhase::NSEventPhaseEnded => match native_event.deltaX() { + x if x > 0.0 => Some(NavigationDirection::Back), + x if x < 0.0 => Some(NavigationDirection::Forward), + _ => return None, + }, + _ => return None, + }; + + match navigation_direction { + Some(direction) => window_height.map(|window_height| { + Self::MouseDown(MouseDownEvent { + button: MouseButton::Navigate(direction), + position: point( + px(native_event.locationInWindow().x as f32), + window_height - px(native_event.locationInWindow().y as f32), + ), + modifiers: read_modifiers(native_event), + click_count: 1, + first_mouse: false, + }) + }), + _ => None, + } + } NSEventType::NSScrollWheel => window_height.map(|window_height| { let phase = match native_event.phase() { NSEventPhase::NSEventPhaseMayBegin | NSEventPhase::NSEventPhaseBegan => { diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index dc715a071b..35b1f598b3 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -148,6 +148,10 @@ unsafe fn build_classes() { sel!(scrollWheel:), handle_view_event as extern "C" fn(&Object, Sel, id), ); + decl.add_method( + sel!(swipeWithEvent:), + handle_view_event as extern "C" fn(&Object, Sel, id), + ); decl.add_method( sel!(flagsChanged:), handle_view_event as extern "C" fn(&Object, Sel, id),