mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Mouse events (#344)
* Explicit mouse-related DeviceEvents This makes the API more intuitive for common use-cases and allows us to better propagate platform knowledge of motion semantics. * Improve event naming consistency * Clarify axis event forwards-compatibility * Rename WindowEvent::MouseMoved/Entered/Left to CursorMoved/... This emphasizes the difference between motion of the host GUI cursor, as used for clicking on things, and raw mouse(-like) input data, as used for first-person controls. * Add support for windows and OSX, fix merging * Fix warnings and errors on Linux * Remove unnecessary breaking changes * Add MouseWheel events to windows and OSX * Fix bad push call. * Fix docs, naming, and x11 events * Remove mutability warning * Add changelog entry
This commit is contained in:
parent
c61f9b75f8
commit
cfd087d9a5
|
@ -15,6 +15,9 @@
|
|||
- Impl `Clone` for `EventsLoopProxy`
|
||||
- `EventsLoop::get_primary_monitor()` on X11 will fallback to any available monitor if no primary is found
|
||||
- Support for touch event on wayland
|
||||
- `WindowEvent`s `MouseMoved`, `MouseEntered`, and `MouseLeft` have been renamed to
|
||||
`CursorMoved`, `CursorEntered`, and `CursorLeft`.
|
||||
- New `DeviceEvent`s added, `MouseMotion` and `MouseWheel`.
|
||||
|
||||
# Version 0.8.3 (2017-10-11)
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ fn main() {
|
|||
|
||||
WindowEvent::Closed => return ControlFlow::Break,
|
||||
|
||||
a @ WindowEvent::MouseMoved { .. } => {
|
||||
a @ WindowEvent::CursorMoved { .. } => {
|
||||
println!("{:?}", a);
|
||||
},
|
||||
|
||||
|
|
|
@ -54,17 +54,20 @@ pub enum WindowEvent {
|
|||
KeyboardInput { device_id: DeviceId, input: KeyboardInput },
|
||||
|
||||
/// The cursor has moved on the window.
|
||||
///
|
||||
/// `position` is (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this
|
||||
/// data is limited by the display area and it may have been transformed by the OS to implement effects such as
|
||||
/// mouse acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
|
||||
MouseMoved { device_id: DeviceId, position: (f64, f64) },
|
||||
CursorMoved {
|
||||
device_id: DeviceId,
|
||||
|
||||
/// (x,y) coords in pixels relative to the top-left corner of the window. Because the range of this data is
|
||||
/// limited by the display area and it may have been transformed by the OS to implement effects such as cursor
|
||||
/// acceleration, it should not be used to implement non-cursor-like interactions such as 3D camera control.
|
||||
position: (f64, f64),
|
||||
},
|
||||
|
||||
/// The cursor has entered the window.
|
||||
MouseEntered { device_id: DeviceId },
|
||||
CursorEntered { device_id: DeviceId },
|
||||
|
||||
/// The cursor has left the window.
|
||||
MouseLeft { device_id: DeviceId },
|
||||
CursorLeft { device_id: DeviceId },
|
||||
|
||||
/// A mouse wheel movement or touchpad scroll occurred.
|
||||
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase },
|
||||
|
@ -79,7 +82,7 @@ pub enum WindowEvent {
|
|||
/// is being pressed) and stage (integer representing the click level).
|
||||
TouchpadPressure { device_id: DeviceId, pressure: f32, stage: i64 },
|
||||
|
||||
/// Motion on some analog axis not otherwise handled. May overlap with mouse motion.
|
||||
/// Motion on some analog axis. May report data redundant to other, more specific events.
|
||||
AxisMotion { device_id: DeviceId, axis: AxisId, value: f64 },
|
||||
|
||||
/// The window needs to be redrawn.
|
||||
|
@ -110,10 +113,27 @@ pub enum WindowEvent {
|
|||
pub enum DeviceEvent {
|
||||
Added,
|
||||
Removed,
|
||||
/// Mouse devices yield `Motion` events where axis `0` is horizontal and axis `1` is vertical.
|
||||
/// A positive value means a movement to the right or the bottom, depending on the axis.
|
||||
/// Such events will be sent even if the mouse is in a corner of the screen.
|
||||
|
||||
/// Change in physical position of a pointing device.
|
||||
///
|
||||
/// This represents raw, unfiltered physical motion. Not to be confused with `WindowEvent::CursorMoved`.
|
||||
MouseMotion {
|
||||
/// (x, y) change in position in unspecified units.
|
||||
///
|
||||
/// Different devices may use different units.
|
||||
delta: (f64, f64),
|
||||
},
|
||||
|
||||
/// Physical scroll event
|
||||
MouseWheel {
|
||||
delta: MouseScrollDelta,
|
||||
},
|
||||
|
||||
/// Motion on some analog axis. This event will be reported for all arbitrary input devices
|
||||
/// that winit supports on this platform, including mouse devices. If the device is a mouse
|
||||
/// device then this will be reported alongside the MouseMotion event.
|
||||
Motion { axis: AxisId, value: f64 },
|
||||
|
||||
Button { button: ButtonId, state: ElementState },
|
||||
Key(KeyboardInput),
|
||||
Text { codepoint: char },
|
||||
|
|
|
@ -41,13 +41,13 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
|
|||
idata.mouse_focus = Some(wid);
|
||||
let mut guard = idata.sink.lock().unwrap();
|
||||
guard.send_event(
|
||||
Event::MouseEntered {
|
||||
Event::CursorEntered {
|
||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
guard.send_event(
|
||||
Event::MouseMoved {
|
||||
Event::CursorMoved {
|
||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||
position: (x, y),
|
||||
},
|
||||
|
@ -61,7 +61,7 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
|
|||
if let Some(wid) = wid {
|
||||
let mut guard = idata.sink.lock().unwrap();
|
||||
guard.send_event(
|
||||
Event::MouseLeft {
|
||||
Event::CursorLeft {
|
||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||
},
|
||||
wid,
|
||||
|
@ -71,7 +71,7 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
|
|||
motion: |_, idata, _, _, x, y| {
|
||||
if let Some(wid) = idata.mouse_focus {
|
||||
idata.sink.lock().unwrap().send_event(
|
||||
Event::MouseMoved {
|
||||
Event::CursorMoved {
|
||||
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
|
||||
position: (x, y)
|
||||
},
|
||||
|
@ -178,4 +178,4 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
|
|||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ impl EventsLoop {
|
|||
control_flow = ControlFlow::Break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
self.process_event(&mut xev, &mut cb);
|
||||
}
|
||||
|
||||
|
@ -342,7 +342,7 @@ impl EventsLoop {
|
|||
return;
|
||||
}
|
||||
|
||||
use events::WindowEvent::{Focused, MouseEntered, MouseInput, MouseLeft, MouseMoved, MouseWheel, AxisMotion};
|
||||
use events::WindowEvent::{Focused, CursorEntered, MouseInput, CursorLeft, CursorMoved, MouseWheel, AxisMotion};
|
||||
use events::ElementState::{Pressed, Released};
|
||||
use events::MouseButton::{Left, Right, Middle, Other};
|
||||
use events::MouseScrollDelta::LineDelta;
|
||||
|
@ -405,7 +405,7 @@ impl EventsLoop {
|
|||
true
|
||||
} else { false }
|
||||
} {
|
||||
callback(Event::WindowEvent { window_id: wid, event: MouseMoved {
|
||||
callback(Event::WindowEvent { window_id: wid, event: CursorMoved {
|
||||
device_id: did,
|
||||
position: new_cursor_pos
|
||||
}});
|
||||
|
@ -421,9 +421,10 @@ impl EventsLoop {
|
|||
let mut value = xev.valuators.values;
|
||||
for i in 0..xev.valuators.mask_len*8 {
|
||||
if ffi::XIMaskIsSet(mask, i) {
|
||||
let x = unsafe { *value };
|
||||
if let Some(&mut (_, ref mut info)) = physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i) {
|
||||
let delta = (unsafe { *value } - info.position) / info.increment;
|
||||
info.position = unsafe { *value };
|
||||
let delta = (x - info.position) / info.increment;
|
||||
info.position = x;
|
||||
events.push(Event::WindowEvent { window_id: wid, event: MouseWheel {
|
||||
device_id: did,
|
||||
delta: match info.orientation {
|
||||
|
@ -460,11 +461,11 @@ impl EventsLoop {
|
|||
}
|
||||
}
|
||||
|
||||
callback(Event::WindowEvent { window_id: mkwid(xev.event), event: MouseEntered { device_id: mkdid(xev.deviceid) } })
|
||||
callback(Event::WindowEvent { window_id: mkwid(xev.event), event: CursorEntered { device_id: mkdid(xev.deviceid) } })
|
||||
}
|
||||
ffi::XI_Leave => {
|
||||
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
||||
callback(Event::WindowEvent { window_id: mkwid(xev.event), event: MouseLeft { device_id: mkdid(xev.deviceid) } })
|
||||
callback(Event::WindowEvent { window_id: mkwid(xev.event), event: CursorLeft { device_id: mkdid(xev.deviceid) } })
|
||||
}
|
||||
ffi::XI_FocusIn => {
|
||||
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
@ -521,16 +522,38 @@ impl EventsLoop {
|
|||
let did = mkdid(xev.deviceid);
|
||||
|
||||
let mask = unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
||||
let mut value = xev.valuators.values;
|
||||
let mut value = xev.raw_values;
|
||||
let mut mouse_delta = (0.0, 0.0);
|
||||
let mut scroll_delta = (0.0, 0.0);
|
||||
for i in 0..xev.valuators.mask_len*8 {
|
||||
if ffi::XIMaskIsSet(mask, i) {
|
||||
let x = unsafe { *value };
|
||||
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
||||
// relative coordinates.
|
||||
match i {
|
||||
0 => mouse_delta.0 = x,
|
||||
1 => mouse_delta.1 = x,
|
||||
2 => scroll_delta.0 = x as f32,
|
||||
3 => scroll_delta.1 = x as f32,
|
||||
_ => {},
|
||||
}
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::Motion {
|
||||
axis: i as u32,
|
||||
value: unsafe { *value },
|
||||
value: x,
|
||||
}});
|
||||
value = unsafe { value.offset(1) };
|
||||
}
|
||||
}
|
||||
if mouse_delta != (0.0, 0.0) {
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseMotion {
|
||||
delta: mouse_delta,
|
||||
}});
|
||||
}
|
||||
if scroll_delta != (0.0, 0.0) {
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseWheel {
|
||||
delta: LineDelta(scroll_delta.0, scroll_delta.1),
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
||||
|
@ -709,7 +732,7 @@ impl Window {
|
|||
x_events_loop.display.check_errors().expect("Failed to call XSetICFocus");
|
||||
ic
|
||||
};
|
||||
|
||||
|
||||
x_events_loop.windows.lock().unwrap().insert(win.id(), WindowData {
|
||||
im: im,
|
||||
ic: ic,
|
||||
|
@ -736,7 +759,7 @@ impl Window {
|
|||
if let (Some(windows), Some(display)) = (self.windows.upgrade(), self.display.upgrade()) {
|
||||
let nspot = ffi::XPoint{x: x, y: y};
|
||||
let mut windows = windows.lock().unwrap();
|
||||
let mut w = windows.get_mut(&self.window.id()).unwrap();
|
||||
let w = windows.get_mut(&self.window.id()).unwrap();
|
||||
if w.ic_spot.x == x && w.ic_spot.y == y {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -559,7 +559,7 @@ impl Window2 {
|
|||
MouseCursor::NotAllowed => load("crossed_circle"),
|
||||
|
||||
|
||||
/// Resize cursors
|
||||
// Resize cursors
|
||||
MouseCursor::EResize => load("right_side"),
|
||||
MouseCursor::NResize => load("top_side"),
|
||||
MouseCursor::NeResize => load("top_right_corner"),
|
||||
|
|
|
@ -442,8 +442,8 @@ impl EventsLoop {
|
|||
appkit::NSOtherMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Middle })) },
|
||||
appkit::NSOtherMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Middle })) },
|
||||
|
||||
appkit::NSMouseEntered => { Some(into_event(WindowEvent::MouseEntered { device_id: DEVICE_ID })) },
|
||||
appkit::NSMouseExited => { Some(into_event(WindowEvent::MouseLeft { device_id: DEVICE_ID })) },
|
||||
appkit::NSMouseEntered => { Some(into_event(WindowEvent::CursorEntered { device_id: DEVICE_ID })) },
|
||||
appkit::NSMouseExited => { Some(into_event(WindowEvent::CursorLeft { device_id: DEVICE_ID })) },
|
||||
|
||||
appkit::NSMouseMoved |
|
||||
appkit::NSLeftMouseDragged |
|
||||
|
@ -474,7 +474,7 @@ impl EventsLoop {
|
|||
{
|
||||
let x = (scale_factor * view_point.x as f32) as f64;
|
||||
let y = (scale_factor * (view_rect.size.height - view_point.y) as f32) as f64;
|
||||
let window_event = WindowEvent::MouseMoved { device_id: DEVICE_ID, position: (x, y) };
|
||||
let window_event = WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y) };
|
||||
let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
|
||||
events.push_back(event);
|
||||
}
|
||||
|
@ -493,6 +493,12 @@ impl EventsLoop {
|
|||
events.push_back(event);
|
||||
}
|
||||
|
||||
if delta_x != 0.0 || delta_y != 0.0 {
|
||||
let motion_event = DeviceEvent::MouseMotion { delta: (delta_x, delta_y) };
|
||||
let event = Event::DeviceEvent{ device_id: DEVICE_ID, event: motion_event };
|
||||
events.push_back(event);
|
||||
}
|
||||
|
||||
let event = events.pop_front();
|
||||
self.shared.pending_events.lock().unwrap().extend(events.into_iter());
|
||||
event
|
||||
|
@ -519,7 +525,19 @@ impl EventsLoop {
|
|||
NSEventPhase::NSEventPhaseEnded => TouchPhase::Ended,
|
||||
_ => TouchPhase::Moved,
|
||||
};
|
||||
let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: delta, phase: phase };
|
||||
self.shared.pending_events.lock().unwrap().push_back(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: DeviceEvent::MouseWheel {
|
||||
delta: if ns_event.hasPreciseScrollingDeltas() == cocoa::base::YES {
|
||||
PixelDelta(ns_event.scrollingDeltaX() as f32,
|
||||
ns_event.scrollingDeltaY() as f32)
|
||||
} else {
|
||||
LineDelta(ns_event.scrollingDeltaX() as f32,
|
||||
ns_event.scrollingDeltaY() as f32)
|
||||
},
|
||||
}
|
||||
});
|
||||
let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta, phase };
|
||||
Some(into_event(window_event))
|
||||
},
|
||||
|
||||
|
|
|
@ -401,7 +401,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
}
|
||||
|
||||
winapi::WM_MOUSEMOVE => {
|
||||
use events::WindowEvent::{MouseEntered, MouseMoved};
|
||||
use events::WindowEvent::{CursorEntered, CursorMoved};
|
||||
let mouse_outside_window = CONTEXT_STASH.with(|context_stash| {
|
||||
let mut context_stash = context_stash.borrow_mut();
|
||||
if let Some(context_stash) = context_stash.as_mut() {
|
||||
|
@ -420,7 +420,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
if mouse_outside_window {
|
||||
send_event(Event::WindowEvent {
|
||||
window_id: SuperWindowId(WindowId(window)),
|
||||
event: MouseEntered { device_id: DEVICE_ID },
|
||||
event: CursorEntered { device_id: DEVICE_ID },
|
||||
});
|
||||
|
||||
// Calling TrackMouseEvent in order to receive mouse leave events.
|
||||
|
@ -437,14 +437,14 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
|
||||
send_event(Event::WindowEvent {
|
||||
window_id: SuperWindowId(WindowId(window)),
|
||||
event: MouseMoved { device_id: DEVICE_ID, position: (x, y) },
|
||||
event: CursorMoved { device_id: DEVICE_ID, position: (x, y) },
|
||||
});
|
||||
|
||||
0
|
||||
},
|
||||
|
||||
winapi::WM_MOUSELEAVE => {
|
||||
use events::WindowEvent::MouseLeft;
|
||||
use events::WindowEvent::CursorLeft;
|
||||
let mouse_in_window = CONTEXT_STASH.with(|context_stash| {
|
||||
let mut context_stash = context_stash.borrow_mut();
|
||||
if let Some(context_stash) = context_stash.as_mut() {
|
||||
|
@ -463,7 +463,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
if mouse_in_window {
|
||||
send_event(Event::WindowEvent {
|
||||
window_id: SuperWindowId(WindowId(window)),
|
||||
event: MouseLeft { device_id: DEVICE_ID }
|
||||
event: CursorLeft { device_id: DEVICE_ID }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -471,7 +471,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
},
|
||||
|
||||
winapi::WM_MOUSEWHEEL => {
|
||||
use events::WindowEvent::MouseWheel;
|
||||
use events::{DeviceEvent, WindowEvent};
|
||||
use events::MouseScrollDelta::LineDelta;
|
||||
use events::TouchPhase;
|
||||
|
||||
|
@ -481,7 +481,12 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
|
||||
send_event(Event::WindowEvent {
|
||||
window_id: SuperWindowId(WindowId(window)),
|
||||
event: MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved },
|
||||
event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved },
|
||||
});
|
||||
|
||||
send_event(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: DeviceEvent::MouseWheel { delta: LineDelta(0.0, value) },
|
||||
});
|
||||
|
||||
0
|
||||
|
@ -618,7 +623,7 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
},
|
||||
|
||||
winapi::WM_INPUT => {
|
||||
use events::DeviceEvent::Motion;
|
||||
use events::DeviceEvent::{Motion, MouseMotion};
|
||||
let mut data: winapi::RAWINPUT = mem::uninitialized();
|
||||
let mut data_size = mem::size_of::<winapi::RAWINPUT>() as winapi::UINT;
|
||||
user32::GetRawInputData(mem::transmute(lparam), winapi::RID_INPUT,
|
||||
|
@ -643,6 +648,13 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT,
|
|||
event: Motion { axis: 1, value: y }
|
||||
});
|
||||
}
|
||||
|
||||
if x != 0.0 || y != 0.0 {
|
||||
send_event(Event::DeviceEvent {
|
||||
device_id: DEVICE_ID,
|
||||
event: MouseMotion { delta: (x, y) }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
|
|
Loading…
Reference in a new issue