diff --git a/CHANGELOG.md b/CHANGELOG.md index eb1d4fe934..9229c5f24c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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, add `DeviceEvent::Motion`, `DeviceEvent::MouseWheel`, `DeviceEvent::Button` and `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 diff --git a/src/event.rs b/src/event.rs index a658dc4d6c..4111e1f64a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1202,12 +1202,19 @@ pub enum ElementState { } /// 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)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum MouseButton { Left, Right, Middle, + Back, + Forward, Other(u16), } diff --git a/src/platform_impl/linux/wayland/seat/pointer/mod.rs b/src/platform_impl/linux/wayland/seat/pointer/mod.rs index 1b933028e8..607b0e1b12 100644 --- a/src/platform_impl/linux/wayland/seat/pointer/mod.rs +++ b/src/platform_impl/linux/wayland/seat/pointer/mod.rs @@ -397,15 +397,21 @@ impl Default for WinitPointerDataInner { /// Convert the Wayland button into winit. fn wayland_button_to_winit(button: u32) -> MouseButton { - // These values are comming from . + // These values are coming from . const BTN_LEFT: u32 = 0x110; const BTN_RIGHT: u32 = 0x111; 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 { BTN_LEFT => MouseButton::Left, BTN_RIGHT => MouseButton::Right, BTN_MIDDLE => MouseButton::Middle, + BTN_BACK | BTN_SIDE => MouseButton::Back, + BTN_FORWARD | BTN_EXTRA => MouseButton::Forward, button => MouseButton::Other(button as u16), } } diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index a32f3d9e3e..67e321b406 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -579,7 +579,7 @@ impl EventProcessor { use crate::event::{ ElementState::{Pressed, Released}, - MouseButton::{Left, Middle, Other, Right}, + MouseButton::{Back, Forward, Left, Middle, Other, Right}, MouseScrollDelta::LineDelta, Touch, WindowEvent::{ @@ -651,6 +651,23 @@ impl EventProcessor { } } + 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 { window_id, event: MouseInput { diff --git a/src/platform_impl/macos/view.rs b/src/platform_impl/macos/view.rs index 314dc2cfbb..faecdd1593 100644 --- a/src/platform_impl/macos/view.rs +++ b/src/platform_impl/macos/view.rs @@ -1027,10 +1027,14 @@ fn mouse_button(event: &NSEvent) -> MouseButton { // The buttonNumber property only makes sense for the mouse events: // NSLeftMouse.../NSRightMouse.../NSOtherMouse... // 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() { 0 => MouseButton::Left, 1 => MouseButton::Right, 2 => MouseButton::Middle, + 3 => MouseButton::Back, + 4 => MouseButton::Forward, n => MouseButton::Other(n as u16), } } diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 920204637a..70ece5fea8 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -10,11 +10,14 @@ use wasm_bindgen::{JsCast, JsValue}; use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, PointerEvent, WheelEvent}; bitflags! { + // https://www.w3.org/TR/pointerevents3/#the-buttons-property #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ButtonsState: u16 { - const LEFT = 0b001; - const RIGHT = 0b010; - const MIDDLE = 0b100; + const LEFT = 0b00001; + const RIGHT = 0b00010; + const MIDDLE = 0b00100; + const BACK = 0b01000; + const FORWARD = 0b10000; } } @@ -24,6 +27,8 @@ impl From for MouseButton { ButtonsState::LEFT => MouseButton::Left, ButtonsState::RIGHT => MouseButton::Right, ButtonsState::MIDDLE => MouseButton::Middle, + ButtonsState::BACK => MouseButton::Back, + ButtonsState::FORWARD => MouseButton::Forward, _ => MouseButton::Other(value.bits()), } } @@ -35,6 +40,8 @@ impl From for ButtonsState { MouseButton::Left => ButtonsState::LEFT, MouseButton::Right => ButtonsState::RIGHT, MouseButton::Middle => ButtonsState::MIDDLE, + MouseButton::Back => ButtonsState::BACK, + MouseButton::Forward => ButtonsState::FORWARD, 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 { + // https://www.w3.org/TR/pointerevents3/#the-button-property match event.button() { -1 => None, 0 => Some(MouseButton::Left), 1 => Some(MouseButton::Middle), 2 => Some(MouseButton::Right), + 3 => Some(MouseButton::Back), + 4 => Some(MouseButton::Forward), i => Some(MouseButton::Other( i.try_into() .expect("unexpected negative mouse button value"), @@ -63,6 +73,8 @@ impl MouseButton { MouseButton::Left => 0, MouseButton::Right => 1, MouseButton::Middle => 2, + MouseButton::Back => 3, + MouseButton::Forward => 4, MouseButton::Other(value) => value.into(), } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 7ed5b820db..d3b4bf6a82 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -1647,7 +1647,8 @@ unsafe fn public_window_callback_inner( WM_XBUTTONDOWN => { 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); @@ -1660,7 +1661,11 @@ unsafe fn public_window_callback_inner( event: MouseInput { device_id: DEVICE_ID, state: Pressed, - button: Other(xbutton), + button: match xbutton { + 1 => Back, + 2 => Forward, + _ => Other(xbutton), + }, }, }); result = ProcResult::Value(0); @@ -1668,7 +1673,8 @@ unsafe fn public_window_callback_inner( WM_XBUTTONUP => { 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); @@ -1681,7 +1687,11 @@ unsafe fn public_window_callback_inner( event: MouseInput { device_id: DEVICE_ID, state: Released, - button: Other(xbutton), + button: match xbutton { + 1 => Back, + 2 => Forward, + _ => Other(xbutton), + }, }, }); result = ProcResult::Value(0);