diff --git a/CHANGELOG.md b/CHANGELOG.md index 8412a83b..57e0bf1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/examples/grabbing.rs b/examples/grabbing.rs index f7e7c9b3..3a8ef886 100644 --- a/examples/grabbing.rs +++ b/examples/grabbing.rs @@ -30,7 +30,7 @@ fn main() { WindowEvent::Closed => return ControlFlow::Break, - a @ WindowEvent::MouseMoved { .. } => { + a @ WindowEvent::CursorMoved { .. } => { println!("{:?}", a); }, diff --git a/src/events.rs b/src/events.rs index f3c21238..8845e3e1 100644 --- a/src/events.rs +++ b/src/events.rs @@ -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 }, diff --git a/src/platform/linux/wayland/pointer.rs b/src/platform/linux/wayland/pointer.rs index e7abcf34..47b712a2 100644 --- a/src/platform/linux/wayland/pointer.rs +++ b/src/platform/linux/wayland/pointer.rs @@ -41,13 +41,13 @@ pub fn pointer_implementation() -> wl_pointer::Implementation { 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 { 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 { 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 { } }, } -} \ No newline at end of file +} diff --git a/src/platform/linux/x11/mod.rs b/src/platform/linux/x11/mod.rs index 5f749981..873c1508 100644 --- a/src/platform/linux/x11/mod.rs +++ b/src/platform/linux/x11/mod.rs @@ -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 } diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 2c1403c1..b74e7e6d 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -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"), diff --git a/src/platform/macos/events_loop.rs b/src/platform/macos/events_loop.rs index b8cf88ea..8aecbf46 100644 --- a/src/platform/macos/events_loop.rs +++ b/src/platform/macos/events_loop.rs @@ -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)) }, diff --git a/src/platform/windows/events_loop.rs b/src/platform/windows/events_loop.rs index 7213bcdc..ce9fdd8f 100644 --- a/src/platform/windows/events_loop.rs +++ b/src/platform/windows/events_loop.rs @@ -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::() 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