Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 7 additions & 0 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}

Expand Down
8 changes: 7 additions & 1 deletion src/platform_impl/linux/wayland/seat/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 <linux/input-event-codes.h>.
// These values are coming from <linux/input-event-codes.h>.
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),
}
}
Expand Down
19 changes: 18 additions & 1 deletion src/platform_impl/linux/x11/event_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ impl<T: 'static> EventProcessor<T> {

use crate::event::{
ElementState::{Pressed, Released},
MouseButton::{Left, Middle, Other, Right},
MouseButton::{Back, Forward, Left, Middle, Other, Right},
MouseScrollDelta::LineDelta,
Touch,
WindowEvent::{
Expand Down Expand Up @@ -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 {
window_id,
event: MouseInput {
Expand Down
4 changes: 4 additions & 0 deletions src/platform_impl/macos/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
18 changes: 15 additions & 3 deletions src/platform_impl/web/web_sys/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Comment thread
daxpedda marked this conversation as resolved.
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;
}
}

Expand All @@ -24,6 +27,8 @@ impl From<ButtonsState> 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()),
}
}
Expand All @@ -35,6 +40,8 @@ impl From<MouseButton> 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),
}
}
Expand All @@ -45,11 +52,14 @@ pub fn mouse_buttons(event: &MouseEvent) -> ButtonsState {
}

pub fn mouse_button(event: &MouseEvent) -> Option<MouseButton> {
// 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"),
Expand All @@ -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(),
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/platform_impl/windows/event_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,8 @@ unsafe fn public_window_callback_inner<T: 'static>(

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);

Expand All @@ -1660,15 +1661,20 @@ unsafe fn public_window_callback_inner<T: 'static>(
event: MouseInput {
device_id: DEVICE_ID,
state: Pressed,
button: Other(xbutton),
button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
},
});
result = ProcResult::Value(0);
}

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);

Expand All @@ -1681,7 +1687,11 @@ unsafe fn public_window_callback_inner<T: 'static>(
event: MouseInput {
device_id: DEVICE_ID,
state: Released,
button: Other(xbutton),
button: match xbutton {
1 => Back,
2 => Forward,
_ => Other(xbutton),
},
},
});
result = ProcResult::Value(0);
Expand Down