Add touchpad magnify and rotate gestures support for macOS (#2157)

* Add touchpad magnify support for macOS

* Add touchpad rotate support for macOS

* Add macOS rotate and magnify gesture cancelled phases

* Correct docs for TouchpadRotate event

* Fix tracing macros
This commit is contained in:
Joonas Satka 2022-08-16 18:20:06 +03:00 committed by GitHub
parent 76f158d310
commit da2cef97a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 174 additions and 0 deletions

View file

@ -10,6 +10,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Windows, added `WindowExtWindows::set_undecorated_shadow` and `WindowBuilderExtWindows::with_undecorated_shadow` to draw the drop shadow behind a borderless window. - On Windows, added `WindowExtWindows::set_undecorated_shadow` and `WindowBuilderExtWindows::with_undecorated_shadow` to draw the drop shadow behind a borderless window.
- On Windows, fixed default window features (ie snap, animations, shake, etc.) when decorations are disabled. - On Windows, fixed default window features (ie snap, animations, shake, etc.) when decorations are disabled.
- On macOS, add support for two-finger touchpad magnification and rotation gestures with new events `WindowEvent::TouchpadMagnify` and `WindowEvent::TouchpadRotate`.
# 0.27.2 (2022-8-12) # 0.27.2 (2022-8-12)

View file

@ -0,0 +1,43 @@
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 gestures")
.build(&event_loop)
.unwrap();
println!("Only supported on macOS at the moment.");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
if let Event::WindowEvent { event, .. } = 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);
}
}
WindowEvent::TouchpadRotate { delta, .. } => {
if delta > 0.0 {
println!("Rotated counterclockwise {}", delta);
} else {
println!("Rotated clockwise {}", delta);
}
}
_ => (),
}
}
});
}

View file

@ -426,6 +426,34 @@ pub enum WindowEvent<'a> {
modifiers: ModifiersState, 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).
///
/// ## Platform-specific
///
/// - Only available on **macOS**.
TouchpadMagnify {
device_id: DeviceId,
delta: f64,
phase: TouchPhase,
},
/// Touchpad rotation event with two-finger rotation gesture.
///
/// Positive delta values indicate rotation counterclockwise and
/// negative delta values indicate rotation clockwise.
///
/// ## Platform-specific
///
/// - Only available on **macOS**.
TouchpadRotate {
device_id: DeviceId,
delta: f32,
phase: TouchPhase,
},
/// Touchpad pressure event. /// Touchpad pressure event.
/// ///
/// At the moment, only supported on Apple forcetouch-capable macbooks. /// At the moment, only supported on Apple forcetouch-capable macbooks.
@ -549,6 +577,24 @@ impl Clone for WindowEvent<'static> {
button: *button, button: *button,
modifiers: *modifiers, modifiers: *modifiers,
}, },
TouchpadMagnify {
device_id,
delta,
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 { TouchpadPressure {
device_id, device_id,
pressure, pressure,
@ -637,6 +683,24 @@ impl<'a> WindowEvent<'a> {
button, button,
modifiers, modifiers,
}), }),
TouchpadMagnify {
device_id,
delta,
phase,
} => Some(TouchpadMagnify {
device_id,
delta,
phase,
}),
TouchpadRotate {
device_id,
delta,
phase,
} => Some(TouchpadRotate {
device_id,
delta,
phase,
}),
TouchpadPressure { TouchpadPressure {
device_id, device_id,
pressure, pressure,

View file

@ -301,6 +301,14 @@ static VIEW_CLASS: Lazy<ViewClass> = Lazy::new(|| unsafe {
sel!(scrollWheel:), sel!(scrollWheel:),
scroll_wheel as extern "C" fn(&Object, Sel, id), 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!(rotateWithEvent:),
rotate_with_event as extern "C" fn(&Object, Sel, id),
);
decl.add_method( decl.add_method(
sel!(pressureChangeWithEvent:), sel!(pressureChangeWithEvent:),
pressure_change_with_event as extern "C" fn(&Object, Sel, id), pressure_change_with_event as extern "C" fn(&Object, Sel, id),
@ -1196,6 +1204,64 @@ extern "C" fn scroll_wheel(this: &Object, _sel: Sel, event: id) {
} }
} }
extern "C" fn magnify_with_event(this: &Object, _sel: Sel, event: id) {
trace_scope!("magnifyWithEvent:");
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::NSEventPhaseCancelled => TouchPhase::Cancelled,
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));
}
}
extern "C" fn rotate_with_event(this: &Object, _sel: Sel, event: id) {
trace_scope!("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::NSEventPhaseCancelled => TouchPhase::Cancelled,
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));
}
}
extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) { extern "C" fn pressure_change_with_event(this: &Object, _sel: Sel, event: id) {
trace_scope!("pressureChangeWithEvent:"); trace_scope!("pressureChangeWithEvent:");