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 56256aeffded2231a7b11693805a8ade5a71c4fc..4d2fc12dc151282f8f5b0a40f58437c439c47f0d 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 dc715a071b53679d1595ed1ce0e458d783a988a5..35b1f598b346ab0a1fdcd2091c35a8f03fc84280 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),