Skip to content

Commit 9d9d21c

Browse files
dhardykchibisov
authored andcommitted
winit-core: revise MouseButton type
Unify the values of `MouseButton` and thus remove `Other` variant in limit possible buttons to 32, which was picked based on platform capabilities, where 32 is the highest. For the reference, SDL has identical limit.
1 parent 779f52a commit 9d9d21c

File tree

8 files changed

+192
-230
lines changed

8 files changed

+192
-230
lines changed

winit-appkit/src/view.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,14 +1095,11 @@ fn mouse_button(event: &NSEvent) -> MouseButton {
10951095
// For the other events, it's always set to 0.
10961096
// MacOS only defines the left, right and middle buttons, 3..=31 are left as generic buttons,
10971097
// but 3 and 4 are very commonly used as Back and Forward by hardware vendors and applications.
1098-
match event.buttonNumber() {
1099-
0 => MouseButton::Left,
1100-
1 => MouseButton::Right,
1101-
2 => MouseButton::Middle,
1102-
3 => MouseButton::Back,
1103-
4 => MouseButton::Forward,
1104-
n => MouseButton::Other(n as u16),
1105-
}
1098+
let b: isize = event.buttonNumber();
1099+
b.try_into()
1100+
.ok()
1101+
.and_then(MouseButton::try_from_u8)
1102+
.expect("expected MacOS button number in the range 0..=31")
11061103
}
11071104

11081105
// NOTE: to get option as alt working we need to rewrite events

winit-core/src/event.rs

Lines changed: 115 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -531,26 +531,22 @@ pub enum ButtonSource {
531531
button: TabletToolButton,
532532
data: TabletToolData,
533533
},
534+
/// A pointer button of unknown source.
535+
///
536+
/// Codes are undefined and may not be reproducible across platforms or winit versions.
534537
Unknown(u16),
535538
}
536539

537540
impl ButtonSource {
538-
/// Convert any [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
541+
/// Try to convert a [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
539542
/// special handling in an application, this method can be used to handle it like any generic
540543
/// mouse input.
541-
pub fn mouse_button(self) -> MouseButton {
544+
pub fn mouse_button(self) -> Option<MouseButton> {
542545
match self {
543-
ButtonSource::Mouse(mouse) => mouse,
544-
ButtonSource::Touch { .. } => MouseButton::Left,
546+
ButtonSource::Mouse(mouse) => Some(mouse),
547+
ButtonSource::Touch { .. } => Some(MouseButton::Left),
545548
ButtonSource::TabletTool { button, .. } => button.into(),
546-
ButtonSource::Unknown(button) => match button {
547-
0 => MouseButton::Left,
548-
1 => MouseButton::Middle,
549-
2 => MouseButton::Right,
550-
3 => MouseButton::Back,
551-
4 => MouseButton::Forward,
552-
_ => MouseButton::Other(button),
553-
},
549+
ButtonSource::Unknown(_) => None,
554550
}
555551
}
556552
}
@@ -1323,21 +1319,114 @@ impl ElementState {
13231319
}
13241320
}
13251321

1326-
/// Describes a button of a mouse controller.
1322+
/// Identifies a button of a mouse controller.
13271323
///
13281324
/// ## Platform-specific
13291325
///
1330-
/// **macOS:** `Back` and `Forward` might not work with all hardware.
1331-
/// **Orbital:** `Back` and `Forward` are unsupported due to orbital not supporting them.
1326+
/// The first three buttons should be supported on all platforms.
1327+
/// [`Self::Back`] and [`Self::Forward`] are supported on most platforms
1328+
/// (when using a compatible mouse).
1329+
///
1330+
/// - **Android, iOS:** Currently not supported.
1331+
/// - **Orbital:** Only left/right/middle buttons are supported at this time.
1332+
/// - **Web, Windows:** Supports left/right/middle/back/forward buttons.
1333+
/// - **Wayland:** Supports buttons 0..=15.
1334+
/// - **macOS:** Supports all button variants.
1335+
/// - **X11:** Technically supports further buttons than this (0..=250), these are emitted in
1336+
/// `ButtonSource::Unknown`.
13321337
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
13331338
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1339+
#[repr(u8)]
13341340
pub enum MouseButton {
1335-
Left,
1336-
Right,
1337-
Middle,
1338-
Back,
1339-
Forward,
1340-
Other(u16),
1341+
/// The primary (usually left) button
1342+
Left = 0,
1343+
/// The secondary (usually right) button
1344+
Right = 1,
1345+
/// The tertiary (usually middle) button
1346+
Middle = 2,
1347+
/// The first side button, frequently assigned a back function
1348+
Back = 3,
1349+
/// The second side button, frequently assigned a forward function
1350+
Forward = 4,
1351+
/// The sixth button
1352+
Button6 = 5,
1353+
/// The seventh button
1354+
Button7 = 6,
1355+
/// The eighth button
1356+
Button8 = 7,
1357+
/// The ninth button
1358+
Button9 = 8,
1359+
/// The tenth button
1360+
Button10 = 9,
1361+
/// The eleventh button
1362+
Button11 = 10,
1363+
/// The twelfth button
1364+
Button12 = 11,
1365+
/// The thirteenth button
1366+
Button13 = 12,
1367+
/// The fourteenth button
1368+
Button14 = 13,
1369+
/// The fifteenth button
1370+
Button15 = 14,
1371+
/// The sixteenth button
1372+
Button16 = 15,
1373+
Button17 = 16,
1374+
Button18 = 17,
1375+
Button19 = 18,
1376+
Button20 = 19,
1377+
Button21 = 20,
1378+
Button22 = 21,
1379+
Button23 = 22,
1380+
Button24 = 23,
1381+
Button25 = 24,
1382+
Button26 = 25,
1383+
Button27 = 26,
1384+
Button28 = 27,
1385+
Button29 = 28,
1386+
Button30 = 29,
1387+
Button31 = 30,
1388+
Button32 = 31,
1389+
}
1390+
1391+
impl MouseButton {
1392+
/// Construct from a `u8` if within the range `0..=31`
1393+
pub fn try_from_u8(b: u8) -> Option<MouseButton> {
1394+
Some(match b {
1395+
0 => MouseButton::Left,
1396+
1 => MouseButton::Right,
1397+
2 => MouseButton::Middle,
1398+
3 => MouseButton::Back,
1399+
4 => MouseButton::Forward,
1400+
5 => MouseButton::Button6,
1401+
6 => MouseButton::Button7,
1402+
7 => MouseButton::Button8,
1403+
8 => MouseButton::Button9,
1404+
9 => MouseButton::Button10,
1405+
10 => MouseButton::Button11,
1406+
11 => MouseButton::Button12,
1407+
12 => MouseButton::Button13,
1408+
13 => MouseButton::Button14,
1409+
14 => MouseButton::Button15,
1410+
15 => MouseButton::Button16,
1411+
16 => MouseButton::Button17,
1412+
17 => MouseButton::Button18,
1413+
18 => MouseButton::Button19,
1414+
19 => MouseButton::Button20,
1415+
20 => MouseButton::Button21,
1416+
21 => MouseButton::Button22,
1417+
22 => MouseButton::Button23,
1418+
23 => MouseButton::Button24,
1419+
24 => MouseButton::Button25,
1420+
25 => MouseButton::Button26,
1421+
26 => MouseButton::Button27,
1422+
27 => MouseButton::Button28,
1423+
28 => MouseButton::Button29,
1424+
29 => MouseButton::Button30,
1425+
30 => MouseButton::Button31,
1426+
31 => MouseButton::Button32,
1427+
_ => return None,
1428+
})
1429+
}
13411430
}
13421431

13431432
/// Describes a button of a tool, e.g. a pen.
@@ -1349,16 +1438,16 @@ pub enum TabletToolButton {
13491438
Other(u16),
13501439
}
13511440

1352-
impl From<TabletToolButton> for MouseButton {
1441+
impl From<TabletToolButton> for Option<MouseButton> {
13531442
fn from(tool: TabletToolButton) -> Self {
1354-
match tool {
1443+
Some(match tool {
13551444
TabletToolButton::Contact => MouseButton::Left,
13561445
TabletToolButton::Barrel => MouseButton::Right,
13571446
TabletToolButton::Other(1) => MouseButton::Middle,
13581447
TabletToolButton::Other(3) => MouseButton::Back,
13591448
TabletToolButton::Other(4) => MouseButton::Forward,
1360-
TabletToolButton::Other(other) => MouseButton::Other(other),
1361-
}
1449+
TabletToolButton::Other(_) => return None,
1450+
})
13621451
}
13631452
}
13641453

@@ -1492,7 +1581,7 @@ mod tests {
14921581
primary: true,
14931582
state: event::ElementState::Pressed,
14941583
position: (0, 0).into(),
1495-
button: event::MouseButton::Other(0).into(),
1584+
button: event::ButtonSource::Unknown(0),
14961585
});
14971586
with_window_event(PointerButton {
14981587
device_id: None,

winit-wayland/src/seat/pointer/mod.rs

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use sctk::seat::SeatState;
3030
use dpi::{LogicalPosition, PhysicalPosition};
3131
use winit_core::event::{
3232
ElementState, MouseButton, MouseScrollDelta, PointerKind, PointerSource, TouchPhase,
33-
WindowEvent,
33+
WindowEvent, ButtonSource,
3434
};
3535

3636
use crate::state::WinitState;
@@ -108,8 +108,8 @@ impl PointerHandler for WinitState {
108108
if parent_surface != surface =>
109109
{
110110
let click = match wayland_button_to_winit(button) {
111-
MouseButton::Left => FrameClick::Normal,
112-
MouseButton::Right => FrameClick::Alternate,
111+
ButtonSource::Mouse(MouseButton::Left) => FrameClick::Normal,
112+
ButtonSource::Mouse(MouseButton::Right) => FrameClick::Alternate,
113113
_ => continue,
114114
};
115115
let pressed = matches!(kind, PointerEventKind::Press { .. });
@@ -186,7 +186,7 @@ impl PointerHandler for WinitState {
186186
device_id: None,
187187
state,
188188
position,
189-
button: button.into(),
189+
button,
190190
},
191191
window_id,
192192
);
@@ -409,23 +409,16 @@ impl Default for WinitPointerDataInner {
409409
}
410410

411411
/// Convert the Wayland button into winit.
412-
fn wayland_button_to_winit(button: u32) -> MouseButton {
412+
fn wayland_button_to_winit(button: u32) -> ButtonSource {
413413
// These values are coming from <linux/input-event-codes.h>.
414-
const BTN_LEFT: u32 = 0x110;
415-
const BTN_RIGHT: u32 = 0x111;
416-
const BTN_MIDDLE: u32 = 0x112;
417-
const BTN_SIDE: u32 = 0x113;
418-
const BTN_EXTRA: u32 = 0x114;
419-
const BTN_FORWARD: u32 = 0x115;
420-
const BTN_BACK: u32 = 0x116;
421-
422-
match button {
423-
BTN_LEFT => MouseButton::Left,
424-
BTN_RIGHT => MouseButton::Right,
425-
BTN_MIDDLE => MouseButton::Middle,
426-
BTN_BACK | BTN_SIDE => MouseButton::Back,
427-
BTN_FORWARD | BTN_EXTRA => MouseButton::Forward,
428-
button => MouseButton::Other(button as u16),
414+
const BTN_MOUSE: u32 = 0x110;
415+
const BTN_JOYSTICK: u32 = 0x120;
416+
417+
if (BTN_MOUSE..BTN_JOYSTICK).contains(&button) {
418+
// Mapping orders match
419+
MouseButton::try_from_u8((button - BTN_MOUSE) as u8).unwrap().into()
420+
} else {
421+
ButtonSource::Unknown(button as u16)
429422
}
430423
}
431424

winit-web/src/web_sys/event.rs

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,7 @@ bitflags::bitflags! {
2727
const BACK = 0b001000;
2828
const FORWARD = 0b010000;
2929
const ERASER = 0b100000;
30-
}
31-
}
32-
33-
impl From<ButtonsState> for MouseButton {
34-
fn from(value: ButtonsState) -> Self {
35-
match value {
36-
ButtonsState::LEFT => MouseButton::Left,
37-
ButtonsState::RIGHT => MouseButton::Right,
38-
ButtonsState::MIDDLE => MouseButton::Middle,
39-
ButtonsState::BACK => MouseButton::Back,
40-
ButtonsState::FORWARD => MouseButton::Forward,
41-
_ => MouseButton::Other(value.bits()),
42-
}
43-
}
44-
}
45-
46-
impl From<ButtonSource> for ButtonsState {
47-
fn from(value: ButtonSource) -> Self {
48-
match value {
49-
ButtonSource::TabletTool { button, .. } => button.into(),
50-
other => ButtonsState::from(other.mouse_button()),
51-
}
52-
}
53-
}
54-
55-
impl From<MouseButton> for ButtonsState {
56-
fn from(value: MouseButton) -> Self {
57-
match value {
58-
MouseButton::Left => ButtonsState::LEFT,
59-
MouseButton::Right => ButtonsState::RIGHT,
60-
MouseButton::Middle => ButtonsState::MIDDLE,
61-
MouseButton::Back => ButtonsState::BACK,
62-
MouseButton::Forward => ButtonsState::FORWARD,
63-
MouseButton::Other(value) => ButtonsState::from_bits_retain(value),
64-
}
65-
}
66-
}
30+
}}
6731

6832
impl From<TabletToolButton> for ButtonsState {
6933
fn from(tool: TabletToolButton) -> Self {
@@ -92,14 +56,16 @@ pub fn raw_button(event: &MouseEvent) -> Option<u16> {
9256
}
9357
}
9458

95-
pub fn mouse_button(button: u16) -> MouseButton {
59+
pub fn mouse_button(button: u16) -> ButtonSource {
9660
match button {
97-
0 => MouseButton::Left,
98-
1 => MouseButton::Middle,
99-
2 => MouseButton::Right,
100-
3 => MouseButton::Back,
101-
4 => MouseButton::Forward,
102-
other => MouseButton::Other(other),
61+
0 => MouseButton::Left.into(),
62+
1 => MouseButton::Middle.into(),
63+
2 => MouseButton::Right.into(),
64+
3 => MouseButton::Back.into(),
65+
4 => MouseButton::Forward.into(),
66+
// Codes above 4 are not observed on Firefox or Chromium. 5 is defined as an eraser,
67+
// which is not a mouse button. No other codes are defined.
68+
i => ButtonSource::Unknown(i),
10369
}
10470
}
10571

winit-web/src/web_sys/pointer.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ use winit_core::event::{ButtonSource, DeviceId, ElementState, PointerKind, Point
77
use winit_core::keyboard::ModifiersState;
88

99
use super::canvas::Common;
10-
use super::event;
10+
use super::event::{self, ButtonsState};
1111
use super::event_handle::EventListenerHandle;
1212
use crate::event::mkdid;
13-
use crate::web_sys::event::ButtonsState;
1413

1514
#[allow(dead_code)]
1615
pub(super) struct PointerHandler {
@@ -84,7 +83,7 @@ impl PointerHandler {
8483
let button = event::raw_button(&event).expect("no button pressed");
8584

8685
let source = match event::pointer_source(&event, kind) {
87-
PointerSource::Mouse => ButtonSource::Mouse(event::mouse_button(button)),
86+
PointerSource::Mouse => event::mouse_button(button),
8887
PointerSource::Touch { finger_id, force } => {
8988
ButtonSource::Touch { finger_id, force }
9089
},
@@ -138,7 +137,7 @@ impl PointerHandler {
138137
// care if it fails.
139138
let _e = canvas.set_pointer_capture(pointer_id);
140139

141-
ButtonSource::Mouse(event::mouse_button(button))
140+
event::mouse_button(button)
142141
},
143142
PointerSource::Touch { finger_id, force } => {
144143
ButtonSource::Touch { finger_id, force }
@@ -217,7 +216,7 @@ impl PointerHandler {
217216
};
218217

219218
let button = match event::pointer_source(&event, kind) {
220-
PointerSource::Mouse => ButtonSource::Mouse(event::mouse_button(button)),
219+
PointerSource::Mouse => event::mouse_button(button),
221220
PointerSource::Touch { finger_id, force } => {
222221
if button != 0 {
223222
tracing::error!("unexpected touch button id: {button}");

0 commit comments

Comments
 (0)