Add MouseButton::{Back, Forward} to MouseInput

Add named variants for physical back and forward keys which could
be found on some mice. The macOS bits may not work on all the
hardware given that apple doesn't directly support such a thing.

Co-authored-by: daxpedda <daxpedda@gmail.com>
This commit is contained in:
bbb651 2023-06-16 11:51:09 +03:00 committed by GitHub
parent 6300cf915e
commit 4748890935
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 67 additions and 9 deletions

View file

@ -85,6 +85,8 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web, fix `DeviceEvent::MouseMotion` only being emitted for each canvas instead of the whole window. - On Web, fix `DeviceEvent::MouseMotion` only being emitted for each canvas instead of the whole window.
- On Web, add `DeviceEvent::Motion`, `DeviceEvent::MouseWheel`, `DeviceEvent::Button` and - On Web, add `DeviceEvent::Motion`, `DeviceEvent::MouseWheel`, `DeviceEvent::Button` and
`DeviceEvent::Key` support. `DeviceEvent::Key` support.
- **Breaking** `MouseButton` now supports `Back` and `Forward` variants, emitted from mouse events
on Wayland, X11, Windows, macOS and Web.
# 0.28.6 # 0.28.6

View file

@ -1202,12 +1202,19 @@ pub enum ElementState {
} }
/// Describes a button of a mouse controller. /// Describes a button of a mouse controller.
///
/// ## Platform-specific
///
/// **macOS:** `Back` and `Forward` might not work with all hardware.
/// **Orbital:** `Back` and `Forward` are unsupported due to orbital not supporting them.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum MouseButton { pub enum MouseButton {
Left, Left,
Right, Right,
Middle, Middle,
Back,
Forward,
Other(u16), Other(u16),
} }

View file

@ -397,15 +397,21 @@ impl Default for WinitPointerDataInner {
/// Convert the Wayland button into winit. /// Convert the Wayland button into winit.
fn wayland_button_to_winit(button: u32) -> MouseButton { fn wayland_button_to_winit(button: u32) -> MouseButton {
// These values are comming from <linux/input-event-codes.h>. // These values are coming from <linux/input-event-codes.h>.
const BTN_LEFT: u32 = 0x110; const BTN_LEFT: u32 = 0x110;
const BTN_RIGHT: u32 = 0x111; const BTN_RIGHT: u32 = 0x111;
const BTN_MIDDLE: u32 = 0x112; const BTN_MIDDLE: u32 = 0x112;
const BTN_SIDE: u32 = 0x113;
const BTN_EXTRA: u32 = 0x114;
const BTN_FORWARD: u32 = 0x115;
const BTN_BACK: u32 = 0x116;
match button { match button {
BTN_LEFT => MouseButton::Left, BTN_LEFT => MouseButton::Left,
BTN_RIGHT => MouseButton::Right, BTN_RIGHT => MouseButton::Right,
BTN_MIDDLE => MouseButton::Middle, BTN_MIDDLE => MouseButton::Middle,
BTN_BACK | BTN_SIDE => MouseButton::Back,
BTN_FORWARD | BTN_EXTRA => MouseButton::Forward,
button => MouseButton::Other(button as u16), button => MouseButton::Other(button as u16),
} }
} }

View file

@ -579,7 +579,7 @@ impl<T: 'static> EventProcessor<T> {
use crate::event::{ use crate::event::{
ElementState::{Pressed, Released}, ElementState::{Pressed, Released},
MouseButton::{Left, Middle, Other, Right}, MouseButton::{Back, Forward, Left, Middle, Other, Right},
MouseScrollDelta::LineDelta, MouseScrollDelta::LineDelta,
Touch, Touch,
WindowEvent::{ WindowEvent::{
@ -651,6 +651,23 @@ impl<T: 'static> EventProcessor<T> {
} }
} }
8 => callback(Event::WindowEvent {
window_id,
event: MouseInput {
device_id,
state,
button: Back,
},
}),
9 => callback(Event::WindowEvent {
window_id,
event: MouseInput {
device_id,
state,
button: Forward,
},
}),
x => callback(Event::WindowEvent { x => callback(Event::WindowEvent {
window_id, window_id,
event: MouseInput { event: MouseInput {

View file

@ -1027,10 +1027,14 @@ fn mouse_button(event: &NSEvent) -> MouseButton {
// The buttonNumber property only makes sense for the mouse events: // The buttonNumber property only makes sense for the mouse events:
// NSLeftMouse.../NSRightMouse.../NSOtherMouse... // NSLeftMouse.../NSRightMouse.../NSOtherMouse...
// For the other events, it's always set to 0. // For the other events, it's always set to 0.
// MacOS only defines the left, right and middle buttons, 3..=31 are left as generic buttons,
// but 3 and 4 are very commonly used as Back and Forward by hardware vendors and applications.
match event.buttonNumber() { match event.buttonNumber() {
0 => MouseButton::Left, 0 => MouseButton::Left,
1 => MouseButton::Right, 1 => MouseButton::Right,
2 => MouseButton::Middle, 2 => MouseButton::Middle,
3 => MouseButton::Back,
4 => MouseButton::Forward,
n => MouseButton::Other(n as u16), n => MouseButton::Other(n as u16),
} }
} }

View file

@ -10,11 +10,14 @@ use wasm_bindgen::{JsCast, JsValue};
use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, PointerEvent, WheelEvent}; use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, PointerEvent, WheelEvent};
bitflags! { bitflags! {
// https://www.w3.org/TR/pointerevents3/#the-buttons-property
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ButtonsState: u16 { pub struct ButtonsState: u16 {
const LEFT = 0b001; const LEFT = 0b00001;
const RIGHT = 0b010; const RIGHT = 0b00010;
const MIDDLE = 0b100; const MIDDLE = 0b00100;
const BACK = 0b01000;
const FORWARD = 0b10000;
} }
} }
@ -24,6 +27,8 @@ impl From<ButtonsState> for MouseButton {
ButtonsState::LEFT => MouseButton::Left, ButtonsState::LEFT => MouseButton::Left,
ButtonsState::RIGHT => MouseButton::Right, ButtonsState::RIGHT => MouseButton::Right,
ButtonsState::MIDDLE => MouseButton::Middle, ButtonsState::MIDDLE => MouseButton::Middle,
ButtonsState::BACK => MouseButton::Back,
ButtonsState::FORWARD => MouseButton::Forward,
_ => MouseButton::Other(value.bits()), _ => MouseButton::Other(value.bits()),
} }
} }
@ -35,6 +40,8 @@ impl From<MouseButton> for ButtonsState {
MouseButton::Left => ButtonsState::LEFT, MouseButton::Left => ButtonsState::LEFT,
MouseButton::Right => ButtonsState::RIGHT, MouseButton::Right => ButtonsState::RIGHT,
MouseButton::Middle => ButtonsState::MIDDLE, MouseButton::Middle => ButtonsState::MIDDLE,
MouseButton::Back => ButtonsState::BACK,
MouseButton::Forward => ButtonsState::FORWARD,
MouseButton::Other(value) => ButtonsState::from_bits_retain(value), MouseButton::Other(value) => ButtonsState::from_bits_retain(value),
} }
} }
@ -45,11 +52,14 @@ pub fn mouse_buttons(event: &MouseEvent) -> ButtonsState {
} }
pub fn mouse_button(event: &MouseEvent) -> Option<MouseButton> { pub fn mouse_button(event: &MouseEvent) -> Option<MouseButton> {
// https://www.w3.org/TR/pointerevents3/#the-button-property
match event.button() { match event.button() {
-1 => None, -1 => None,
0 => Some(MouseButton::Left), 0 => Some(MouseButton::Left),
1 => Some(MouseButton::Middle), 1 => Some(MouseButton::Middle),
2 => Some(MouseButton::Right), 2 => Some(MouseButton::Right),
3 => Some(MouseButton::Back),
4 => Some(MouseButton::Forward),
i => Some(MouseButton::Other( i => Some(MouseButton::Other(
i.try_into() i.try_into()
.expect("unexpected negative mouse button value"), .expect("unexpected negative mouse button value"),
@ -63,6 +73,8 @@ impl MouseButton {
MouseButton::Left => 0, MouseButton::Left => 0,
MouseButton::Right => 1, MouseButton::Right => 1,
MouseButton::Middle => 2, MouseButton::Middle => 2,
MouseButton::Back => 3,
MouseButton::Forward => 4,
MouseButton::Other(value) => value.into(), MouseButton::Other(value) => value.into(),
} }
} }

View file

@ -1647,7 +1647,8 @@ unsafe fn public_window_callback_inner<T: 'static>(
WM_XBUTTONDOWN => { WM_XBUTTONDOWN => {
use crate::event::{ use crate::event::{
ElementState::Pressed, MouseButton::Other, WindowEvent::MouseInput, ElementState::Pressed, MouseButton::Back, MouseButton::Forward, MouseButton::Other,
WindowEvent::MouseInput,
}; };
let xbutton = super::get_xbutton_wparam(wparam as u32); let xbutton = super::get_xbutton_wparam(wparam as u32);
@ -1660,7 +1661,11 @@ unsafe fn public_window_callback_inner<T: 'static>(
event: MouseInput { event: MouseInput {
device_id: DEVICE_ID, device_id: DEVICE_ID,
state: Pressed, state: Pressed,
button: Other(xbutton), button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
}, },
}); });
result = ProcResult::Value(0); result = ProcResult::Value(0);
@ -1668,7 +1673,8 @@ unsafe fn public_window_callback_inner<T: 'static>(
WM_XBUTTONUP => { WM_XBUTTONUP => {
use crate::event::{ use crate::event::{
ElementState::Released, MouseButton::Other, WindowEvent::MouseInput, ElementState::Released, MouseButton::Back, MouseButton::Forward,
MouseButton::Other, WindowEvent::MouseInput,
}; };
let xbutton = super::get_xbutton_wparam(wparam as u32); let xbutton = super::get_xbutton_wparam(wparam as u32);
@ -1681,7 +1687,11 @@ unsafe fn public_window_callback_inner<T: 'static>(
event: MouseInput { event: MouseInput {
device_id: DEVICE_ID, device_id: DEVICE_ID,
state: Released, state: Released,
button: Other(xbutton), button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
}, },
}); });
result = ProcResult::Value(0); result = ProcResult::Value(0);