Added modifier support to mouse events (#328)

This commit is contained in:
Bryan Gilbert 2017-12-26 16:46:28 -05:00 committed by Pierre Krieger
parent d92666c188
commit 011720848a
7 changed files with 116 additions and 33 deletions

View file

@ -4,6 +4,7 @@
- Added support for `DroppedFile`, `HoveredFile`, and `HoveredFileCancelled` to X11 backend.
- **Breaking:** `unix::WindowExt` no longer returns pointers for things that aren't actually pointers; `get_xlib_window` now returns `Option<std::os::raw::c_ulong>` and `get_xlib_screen_id` returns `Option<std::os::raw::c_int>`. Additionally, methods that previously returned `libc::c_void` have been changed to return `std::os::raw::c_void`, which are not interchangeable types, so users wanting the former will need to explicitly cast.
- Added `set_decorations` method to `Window` to allow decorations to be toggled after the window is built. Presently only implemented on X11.
- Added `modifiers` field to `MouseInput`, `MouseWheel`, and `CursorMoved` events to track the modifiers state (`ModifiersState`).
# Version 0.9.0 (2017-12-01)

View file

@ -61,6 +61,7 @@ pub enum WindowEvent {
/// 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),
modifiers: ModifiersState
},
/// The cursor has entered the window.
@ -70,10 +71,11 @@ pub enum WindowEvent {
CursorLeft { device_id: DeviceId },
/// A mouse wheel movement or touchpad scroll occurred.
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase },
MouseWheel { device_id: DeviceId, delta: MouseScrollDelta, phase: TouchPhase, modifiers: ModifiersState },
/// An mouse button press has been received.
MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton },
MouseInput { device_id: DeviceId, state: ElementState, button: MouseButton, modifiers: ModifiersState },
/// Touchpad pressure event.
///

View file

@ -178,6 +178,13 @@ extern "C" fn mouse_callback(
unsafe {
let queue: &RefCell<VecDeque<::Event>> = mem::transmute(event_queue);
let modifiers = ::ModifiersState {
shift: (*event).shiftKey == ffi::EM_TRUE,
ctrl: (*event).ctrlKey == ffi::EM_TRUE,
alt: (*event).altKey == ffi::EM_TRUE,
logo: (*event).metaKey == ffi::EM_TRUE,
};
match event_type {
ffi::EMSCRIPTEN_EVENT_MOUSEMOVE => {
queue.borrow_mut().push_back(::Event::WindowEvent {
@ -185,6 +192,7 @@ extern "C" fn mouse_callback(
event: ::WindowEvent::CursorMoved {
device_id: ::DeviceId(DeviceId),
position: ((*event).canvasX as f64, (*event).canvasY as f64),
modifiers: modifiers,
}
});
queue.borrow_mut().push_back(::Event::DeviceEvent {
@ -211,8 +219,9 @@ extern "C" fn mouse_callback(
window_id: ::WindowId(WindowId(0)),
event: ::WindowEvent::MouseInput {
device_id: ::DeviceId(DeviceId),
state,
button,
state: state,
button: button,
modifiers: modifiers,
}
})
},

View file

@ -1,6 +1,7 @@
use std::sync::{Arc, Mutex};
use {WindowEvent as Event, ElementState, MouseButton, MouseScrollDelta, TouchPhase};
use events::ModifiersState;
use super::{WindowId, DeviceId};
use super::event_loop::EventsLoopSink;
@ -50,6 +51,8 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid,
);
@ -73,7 +76,9 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
idata.sink.lock().unwrap().send_event(
Event::CursorMoved {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
position: (x, y)
position: (x, y),
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
@ -97,6 +102,8 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
state: state,
button: button,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
@ -117,6 +124,8 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: TouchPhase::Moved,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
@ -145,6 +154,8 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);
@ -154,6 +165,8 @@ pub fn pointer_implementation() -> wl_pointer::Implementation<PointerIData> {
device_id: ::DeviceId(::platform::DeviceId::Wayland(DeviceId)),
delta: MouseScrollDelta::PixelDelta(x as f32, y as f32),
phase: idata.axis_state,
// TODO: replace dummy value with actual modifier state
modifiers: ModifiersState::default(),
},
wid
);

View file

@ -471,6 +471,8 @@ impl EventsLoop {
match xev.evtype {
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
use events::ModifiersState;
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
let wid = mkwid(xev.event);
let did = mkdid(xev.deviceid);
@ -478,6 +480,18 @@ impl EventsLoop {
// Deliver multi-touch events instead of emulated mouse events.
return;
}
let ev_mods = {
// Translate x mod state to mods
let state = xev.mods.effective as u32;
ModifiersState {
alt: state & ffi::Mod1Mask != 0,
shift: state & ffi::ShiftMask != 0,
ctrl: state & ffi::ControlMask != 0,
logo: state & ffi::Mod4Mask != 0,
}
};
let state = if xev.evtype == ffi::XI_ButtonPress {
Pressed
} else {
@ -485,11 +499,11 @@ impl EventsLoop {
};
match xev.detail as u32 {
ffi::Button1 => callback(Event::WindowEvent { window_id: wid, event:
MouseInput { device_id: did, state: state, button: Left } }),
MouseInput { device_id: did, state: state, button: Left, modifiers: ev_mods } }),
ffi::Button2 => callback(Event::WindowEvent { window_id: wid, event:
MouseInput { device_id: did, state: state, button: Middle } }),
MouseInput { device_id: did, state: state, button: Middle, modifiers: ev_mods} }),
ffi::Button3 => callback(Event::WindowEvent { window_id: wid, event:
MouseInput { device_id: did, state: state, button: Right } }),
MouseInput { device_id: did, state: state, button: Right, modifiers: ev_mods } }),
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
@ -505,18 +519,33 @@ impl EventsLoop {
_ => unreachable!()
},
phase: TouchPhase::Moved,
modifiers: ev_mods,
}});
},
x => callback(Event::WindowEvent { window_id: wid, event: MouseInput { device_id: did, state: state, button: Other(x as u8) } })
x => callback(Event::WindowEvent { window_id: wid,
event: MouseInput { device_id: did, state: state, button: Other(x as u8), modifiers: ev_mods } })
}
}
ffi::XI_Motion => {
use events::ModifiersState;
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
let did = mkdid(xev.deviceid);
let wid = mkwid(xev.event);
let new_cursor_pos = (xev.event_x, xev.event_y);
let ev_mods = {
// Translate x event state to mods
let state = xev.mods.effective as u32;
ModifiersState {
alt: state & ffi::Mod1Mask != 0,
shift: state & ffi::ShiftMask != 0,
ctrl: state & ffi::ControlMask != 0,
logo: state & ffi::Mod4Mask != 0,
}
};
// Gymnastics to ensure self.windows isn't locked when we invoke callback
if {
let mut windows = self.windows.lock().unwrap();
@ -528,7 +557,8 @@ impl EventsLoop {
} {
callback(Event::WindowEvent { window_id: wid, event: CursorMoved {
device_id: did,
position: new_cursor_pos
position: new_cursor_pos,
modifiers: ev_mods,
}});
}
@ -554,6 +584,7 @@ impl EventsLoop {
ScrollOrientation::Vertical => LineDelta(0.0, -delta as f32),
},
phase: TouchPhase::Moved,
modifiers: ev_mods,
}});
} else {
events.push(Event::WindowEvent { window_id: wid, event: AxisMotion {
@ -572,8 +603,20 @@ impl EventsLoop {
}
ffi::XI_Enter => {
use events::ModifiersState;
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
let ev_mods = {
// Translate x event state to mods
let state = xev.mods.effective as u32;
ModifiersState {
alt: state & ffi::Mod1Mask != 0,
shift: state & ffi::ShiftMask != 0,
ctrl: state & ffi::ControlMask != 0,
logo: state & ffi::Mod4Mask != 0,
}
};
let mut devices = self.devices.lock().unwrap();
let physical_device = devices.get_mut(&DeviceId(xev.sourceid)).unwrap();
for info in DeviceInfo::get(&self.display, ffi::XIAllDevices).iter() {
@ -586,7 +629,8 @@ impl EventsLoop {
let new_cursor_pos = (xev.event_x, xev.event_y);
callback(Event::WindowEvent { window_id: wid, event: CursorMoved {
device_id: mkdid(xev.deviceid),
position: new_cursor_pos
position: new_cursor_pos,
modifiers: ev_mods,
}})
}
ffi::XI_Leave => {
@ -594,7 +638,20 @@ impl EventsLoop {
callback(Event::WindowEvent { window_id: mkwid(xev.event), event: CursorLeft { device_id: mkdid(xev.deviceid) } })
}
ffi::XI_FocusIn => {
use events::ModifiersState;
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
let ev_mods = {
// Translate x event state to mods
let state = xev.mods.effective as u32;
ModifiersState {
alt: state & ffi::Mod1Mask != 0,
shift: state & ffi::ShiftMask != 0,
ctrl: state & ffi::ControlMask != 0,
logo: state & ffi::Mod4Mask != 0,
}
};
unsafe {
let mut windows = self.windows.lock().unwrap();
let window_data = windows.get_mut(&WindowId(xev.event)).unwrap();
@ -605,7 +662,8 @@ impl EventsLoop {
let new_cursor_pos = (xev.event_x, xev.event_y);
callback(Event::WindowEvent { window_id: wid, event: CursorMoved {
device_id: mkdid(xev.deviceid),
position: new_cursor_pos
position: new_cursor_pos,
modifiers: ev_mods,
}})
}
ffi::XI_FocusOut => {

View file

@ -435,12 +435,12 @@ impl EventsLoop {
event
},
appkit::NSLeftMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Left })) },
appkit::NSLeftMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Left })) },
appkit::NSRightMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Right })) },
appkit::NSRightMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Right })) },
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::NSLeftMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Left, modifiers: event_mods(ns_event) })) },
appkit::NSLeftMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Left, modifiers: event_mods(ns_event) })) },
appkit::NSRightMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Right, modifiers: event_mods(ns_event) })) },
appkit::NSRightMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Right, modifiers: event_mods(ns_event) })) },
appkit::NSOtherMouseDown => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Pressed, button: MouseButton::Middle, modifiers: event_mods(ns_event) })) },
appkit::NSOtherMouseUp => { Some(into_event(WindowEvent::MouseInput { device_id: DEVICE_ID, state: ElementState::Released, button: MouseButton::Middle, modifiers: event_mods(ns_event) })) },
appkit::NSMouseEntered => {
let window = match maybe_window.or_else(maybe_key_window) {
@ -462,7 +462,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::CursorMoved { device_id: DEVICE_ID, position: (x, y) };
let window_event = WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event_mods(ns_event) };
let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
self.shared.pending_events.lock().unwrap().push_back(event);
@ -499,7 +499,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::CursorMoved { device_id: DEVICE_ID, position: (x, y) };
let window_event = WindowEvent::CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event_mods(ns_event) };
let event = Event::WindowEvent { window_id: ::WindowId(window.id()), event: window_event };
events.push_back(event);
}
@ -562,7 +562,7 @@ impl EventsLoop {
},
}
});
let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta, phase };
let window_event = WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: delta, phase: phase, modifiers: event_mods(ns_event) };
Some(into_event(window_event))
},

View file

@ -442,7 +442,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorMoved { device_id: DEVICE_ID, position: (x, y) },
event: CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event::get_key_mods() },
});
0
@ -486,7 +486,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: WindowEvent::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, modifiers: event::get_key_mods() },
});
send_event(Event::DeviceEvent {
@ -552,7 +552,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Pressed;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left }
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }
});
0
},
@ -563,7 +563,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Released;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left }
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }
});
0
},
@ -574,7 +574,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Pressed;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right }
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }
});
0
},
@ -585,7 +585,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Released;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right }
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }
});
0
},
@ -596,7 +596,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Pressed;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle }
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }
});
0
},
@ -607,7 +607,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
use events::ElementState::Released;
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle }
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }
});
0
},
@ -619,7 +619,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8) }
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
});
0
},
@ -631,7 +631,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8) }
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
});
0
},
@ -690,7 +690,7 @@ pub unsafe extern "system" fn callback(window: HWND, msg: UINT,
send_event(Event::WindowEvent {
window_id: SuperWindowId(WindowId(window)),
event: CursorMoved { device_id: DEVICE_ID, position: (x, y) },
event: CursorMoved { device_id: DEVICE_ID, position: (x, y), modifiers: event::get_key_mods() },
});
0
},