From bc3f998ee8d58aecbbf3924ab4ee9c42c32808de Mon Sep 17 00:00:00 2001 From: Joonas Satka Date: Thu, 20 Jan 2022 19:21:38 +0200 Subject: [PATCH 1/5] Add touchpad magnify support for macOS --- CHANGELOG.md | 1 + examples/touchpad_magnify.rs | 37 +++++++++++++++++++++++++++++++++ src/event.rs | 30 ++++++++++++++++++++++++++ src/platform_impl/macos/view.rs | 35 +++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 examples/touchpad_magnify.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index d7ccaba2b7..4edcb1ca90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. +- On macOS, add support for touchpad magnification gesture with new event `WindowEvent::TouchpadMagnify`. # 0.26.1 (2022-01-05) diff --git a/examples/touchpad_magnify.rs b/examples/touchpad_magnify.rs new file mode 100644 index 0000000000..801b3ade30 --- /dev/null +++ b/examples/touchpad_magnify.rs @@ -0,0 +1,37 @@ +use simple_logger::SimpleLogger; +use winit::{ + event::{Event, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, +}; + +fn main() { + SimpleLogger::new().init().unwrap(); + let event_loop = EventLoop::new(); + + let _window = WindowBuilder::new() + .with_title("Touchpad magnify events") + .build(&event_loop) + .unwrap(); + + println!("Only supported on macOS at the moment."); + + event_loop.run(move |event, _, control_flow| { + *control_flow = ControlFlow::Wait; + + match event { + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::TouchpadMagnify { delta, .. } => { + if delta > 0.0 { + println!("Zoomed in {}", delta); + } else { + println!("Zoomed out {}", delta); + } + }, + _ => (), + }, + _ => (), + } + }); +} diff --git a/src/event.rs b/src/event.rs index 6660e00688..eeb9a52a66 100644 --- a/src/event.rs +++ b/src/event.rs @@ -306,6 +306,18 @@ pub enum WindowEvent<'a> { modifiers: ModifiersState, }, + /// Touchpad magnification event with two-finger pinch gesture. + /// + /// Positive delta values indicate magnification (zooming in) and + /// negative delta values indicate shrinking (zooming out). + /// + /// At the moment, only supported on macOS. + TouchpadMagnify { + device_id: DeviceId, + delta: f64, + phase: TouchPhase, + }, + /// Touchpad pressure event. /// /// At the moment, only supported on Apple forcetouch-capable macbooks. @@ -418,6 +430,15 @@ impl Clone for WindowEvent<'static> { button: *button, modifiers: *modifiers, }, + TouchpadMagnify { + device_id, + delta, + phase + } => TouchpadMagnify { + device_id: *device_id, + delta: *delta, + phase: *phase, + }, TouchpadPressure { device_id, pressure, @@ -504,6 +525,15 @@ impl<'a> WindowEvent<'a> { button, modifiers, }), + TouchpadMagnify { + device_id, + delta, + phase + } => Some(TouchpadMagnify { + device_id, + delta, + phase, + }), TouchpadPressure { device_id, pressure, diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 20f18b6408..035981cb26 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -237,6 +237,10 @@ lazy_static! { sel!(scrollWheel:), scroll_wheel as extern "C" fn(&Object, Sel, id), ); + decl.add_method( + sel!(magnifyWithEvent:), + magnify_with_event as extern "C" fn(&Object, Sel, id), + ); decl.add_method( sel!(pressureChangeWithEvent:), pressure_change_with_event as extern "C" fn(&Object, Sel, id), @@ -1046,6 +1050,37 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) { trace!("Completed `scrollWheel`"); } +extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { + trace!("Triggered `magnifyWithEvent`"); + + mouse_motion(this, event); + + unsafe { + let state_ptr: *mut c_void = *this.get_ivar("winitState"); + let state = &mut *(state_ptr as *mut ViewState); + + let delta = event.magnification(); + let phase = match event.phase() { + NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, + NSEventPhase::NSEventPhaseChanged => TouchPhase::Moved, + NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, + _ => return + }; + + let window_event = Event::WindowEvent { + window_id: WindowId(get_window_id(state.ns_window)), + event: WindowEvent::TouchpadMagnify { + device_id: DEVICE_ID, + delta, + phase, + }, + }; + + AppState::queue_event(EventWrapper::StaticEvent(window_event)); + } + trace!("Completed `magnifyWithEvent`"); +} + extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { trace!("Triggered `pressureChangeWithEvent`"); From c8a4411cb25dd6a6a1cae71a562d43ca823b3a01 Mon Sep 17 00:00:00 2001 From: Joonas Satka Date: Thu, 20 Jan 2022 23:03:37 +0200 Subject: [PATCH 2/5] Add touchpad rotate support for macOS --- CHANGELOG.md | 2 +- ...uchpad_magnify.rs => touchpad_gestures.rs} | 11 +++++- src/event.rs | 34 ++++++++++++++++- src/platform_impl/macos/view.rs | 37 +++++++++++++++++-- 4 files changed, 76 insertions(+), 8 deletions(-) rename examples/{touchpad_magnify.rs => touchpad_gestures.rs} (74%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4edcb1ca90..439b6fc52d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Unreleased - **Breaking:** Rename the `Exit` variant of `ControlFlow` to `ExitWithCode`, which holds a value to control the exit code after running. Add an `Exit` constant which aliases to `ExitWithCode(0)` instead to avoid major breakage. This shouldn't affect most existing programs. -- On macOS, add support for touchpad magnification gesture with new event `WindowEvent::TouchpadMagnify`. +- On macOS, add support for two-finger touchpad magnification and rotation gestures with new events `WindowEvent::TouchpadMagnify` and `WindowEvent::TouchpadRotate`. # 0.26.1 (2022-01-05) diff --git a/examples/touchpad_magnify.rs b/examples/touchpad_gestures.rs similarity index 74% rename from examples/touchpad_magnify.rs rename to examples/touchpad_gestures.rs index 801b3ade30..1a4e5490c7 100644 --- a/examples/touchpad_magnify.rs +++ b/examples/touchpad_gestures.rs @@ -10,7 +10,7 @@ fn main() { let event_loop = EventLoop::new(); let _window = WindowBuilder::new() - .with_title("Touchpad magnify events") + .with_title("Touchpad gestures") .build(&event_loop) .unwrap(); @@ -28,7 +28,14 @@ fn main() { } else { println!("Zoomed out {}", delta); } - }, + } + WindowEvent::TouchpadRotate { delta, .. } => { + if delta > 0.0 { + println!("Rotated left {}", delta); + } else { + println!("Rotated right {}", delta); + } + } _ => (), }, _ => (), diff --git a/src/event.rs b/src/event.rs index eeb9a52a66..8a2cf14e1a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -318,6 +318,18 @@ pub enum WindowEvent<'a> { phase: TouchPhase, }, + /// Touchpad rotation event with two-finger rotation gesture. + /// + /// Positive delta values indicate rotation to left (counterclockwise) and + /// negative delta values indicate rotation to right (clockwise). + /// + /// At the moment, only supported on macOS. + TouchpadRotate { + device_id: DeviceId, + delta: f32, + phase: TouchPhase, + }, + /// Touchpad pressure event. /// /// At the moment, only supported on Apple forcetouch-capable macbooks. @@ -433,12 +445,21 @@ impl Clone for WindowEvent<'static> { TouchpadMagnify { device_id, delta, - phase + phase, } => TouchpadMagnify { device_id: *device_id, delta: *delta, phase: *phase, }, + TouchpadRotate { + device_id, + delta, + phase, + } => TouchpadRotate { + device_id: *device_id, + delta: *delta, + phase: *phase, + }, TouchpadPressure { device_id, pressure, @@ -528,12 +549,21 @@ impl<'a> WindowEvent<'a> { TouchpadMagnify { device_id, delta, - phase + phase, } => Some(TouchpadMagnify { device_id, delta, phase, }), + TouchpadRotate { + device_id, + delta, + phase, + } => Some(TouchpadRotate { + device_id, + delta, + phase, + }), TouchpadPressure { device_id, pressure, diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 035981cb26..822739e3c9 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -241,6 +241,10 @@ lazy_static! { sel!(magnifyWithEvent:), magnify_with_event as extern "C" fn(&Object, Sel, id), ); + decl.add_method( + sel!(rotateWithEvent:), + rotate_with_event as extern "C" fn(&Object, Sel, id), + ); decl.add_method( sel!(pressureChangeWithEvent:), pressure_change_with_event as extern "C" fn(&Object, Sel, id), @@ -1053,8 +1057,6 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) { extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { trace!("Triggered `magnifyWithEvent`"); - mouse_motion(this, event); - unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); let state = &mut *(state_ptr as *mut ViewState); @@ -1064,7 +1066,7 @@ extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, NSEventPhase::NSEventPhaseChanged => TouchPhase::Moved, NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, - _ => return + _ => return, }; let window_event = Event::WindowEvent { @@ -1081,6 +1083,35 @@ extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { trace!("Completed `magnifyWithEvent`"); } +extern "C" fn rotate_with_event(this: &Object, _sel: Sel, event: id) { + trace!("Triggered `rotateWithEvent`"); + + unsafe { + let state_ptr: *mut c_void = *this.get_ivar("winitState"); + let state = &mut *(state_ptr as *mut ViewState); + + let delta = event.rotation(); + let phase = match event.phase() { + NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, + NSEventPhase::NSEventPhaseChanged => TouchPhase::Moved, + NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, + _ => return, + }; + + let window_event = Event::WindowEvent { + window_id: WindowId(get_window_id(state.ns_window)), + event: WindowEvent::TouchpadRotate { + device_id: DEVICE_ID, + delta, + phase, + }, + }; + + AppState::queue_event(EventWrapper::StaticEvent(window_event)); + } + trace!("Completed `rotateWithEvent`"); +} + extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { trace!("Triggered `pressureChangeWithEvent`"); From d71f1ec3c20a91b50b457f0cae6f07a8c7f25d9b Mon Sep 17 00:00:00 2001 From: Joonas Satka Date: Sun, 23 Jan 2022 17:19:22 +0200 Subject: [PATCH 3/5] Add macOS rotate and magnify gesture cancelled phases --- src/platform_impl/macos/view.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 822739e3c9..787101033c 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -1065,6 +1065,7 @@ extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { let phase = match event.phase() { NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, NSEventPhase::NSEventPhaseChanged => TouchPhase::Moved, + NSEventPhase::NSEventPhaseCancelled => TouchPhase::Cancelled, NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, _ => return, }; @@ -1094,6 +1095,7 @@ extern "C" fn rotate_with_event(this: &Object, _sel: Sel, event: id) { let phase = match event.phase() { NSEventPhase::NSEventPhaseBegan => TouchPhase::Started, NSEventPhase::NSEventPhaseChanged => TouchPhase::Moved, + NSEventPhase::NSEventPhaseCancelled => TouchPhase::Cancelled, NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended, _ => return, }; From b7bc945916da5cf665294a64a6d18d7d0479bdce Mon Sep 17 00:00:00 2001 From: Joonas Satka Date: Tue, 16 Aug 2022 13:41:32 +0300 Subject: [PATCH 4/5] Correct docs for TouchpadRotate event --- examples/touchpad_gestures.rs | 4 ++-- src/event.rs | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/examples/touchpad_gestures.rs b/examples/touchpad_gestures.rs index 1a4e5490c7..7ab1b50aae 100644 --- a/examples/touchpad_gestures.rs +++ b/examples/touchpad_gestures.rs @@ -31,9 +31,9 @@ fn main() { } WindowEvent::TouchpadRotate { delta, .. } => { if delta > 0.0 { - println!("Rotated left {}", delta); + println!("Rotated counterclockwise {}", delta); } else { - println!("Rotated right {}", delta); + println!("Rotated clockwise {}", delta); } } _ => (), diff --git a/src/event.rs b/src/event.rs index b131bdedaf..579a8f5f48 100644 --- a/src/event.rs +++ b/src/event.rs @@ -331,10 +331,12 @@ pub enum WindowEvent<'a> { /// Touchpad rotation event with two-finger rotation gesture. /// - /// Positive delta values indicate rotation to left (counterclockwise) and - /// negative delta values indicate rotation to right (clockwise). + /// Positive delta values indicate rotation counterclockwise and + /// negative delta values indicate rotation clockwise. /// - /// At the moment, only supported on macOS. + /// ## Platform-specific + /// + /// - Only available on **macOS**. TouchpadRotate { device_id: DeviceId, delta: f32, From 03577dac97392e5fc982e4b88b46daf103d79d08 Mon Sep 17 00:00:00 2001 From: Joonas Satka Date: Tue, 16 Aug 2022 16:59:49 +0300 Subject: [PATCH 5/5] Fix tracing macros --- src/event.rs | 4 +++- src/platform_impl/macos/view.rs | 6 ++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/event.rs b/src/event.rs index 7e0b01ee64..d54b1b6c32 100644 --- a/src/event.rs +++ b/src/event.rs @@ -431,7 +431,9 @@ pub enum WindowEvent<'a> { /// Positive delta values indicate magnification (zooming in) and /// negative delta values indicate shrinking (zooming out). /// - /// At the moment, only supported on macOS. + /// ## Platform-specific + /// + /// - Only available on **macOS**. TouchpadMagnify { device_id: DeviceId, delta: f64, diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 31585646d6..16bc457ecc 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -1205,7 +1205,7 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) { } extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { - trace!("Triggered `magnifyWithEvent`"); + trace_scope!("magnifyWithEvent:"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -1231,11 +1231,10 @@ extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) { AppState::queue_event(EventWrapper::StaticEvent(window_event)); } - trace!("Completed `magnifyWithEvent`"); } extern "C" fn rotate_with_event(this: &Object, _sel: Sel, event: id) { - trace!("Triggered `rotateWithEvent`"); + trace_scope!("rotateWithEvent:"); unsafe { let state_ptr: *mut c_void = *this.get_ivar("winitState"); @@ -1261,7 +1260,6 @@ extern "C" fn rotate_with_event(this: &Object, _sel: Sel, event: id) { AppState::queue_event(EventWrapper::StaticEvent(window_event)); } - trace!("Completed `rotateWithEvent`"); } extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {