Skip to content

Commit 0f3f8c2

Browse files
committed
Revise MouseButton type: enum -> struct
1 parent b284d26 commit 0f3f8c2

File tree

6 files changed

+146
-69
lines changed

6 files changed

+146
-69
lines changed

winit-appkit/src/view.rs

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

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

winit-core/src/event.rs

Lines changed: 107 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -521,14 +521,14 @@ pub enum ButtonSource {
521521
}
522522

523523
impl ButtonSource {
524-
/// Convert any [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
524+
/// Try to convert a [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
525525
/// special handling in an application, this method can be used to handle it like any generic
526526
/// mouse input.
527-
pub fn mouse_button(self) -> MouseButton {
527+
pub fn mouse_button(self) -> Option<MouseButton> {
528528
match self {
529-
ButtonSource::Mouse(mouse) => mouse,
530-
ButtonSource::Touch { .. } => MouseButton::Left,
531-
ButtonSource::Unknown(code) => MouseButton::Other(code),
529+
ButtonSource::Mouse(mouse) => Some(mouse),
530+
ButtonSource::Touch { .. } => Some(MouseButton::Left),
531+
ButtonSource::Unknown(_) => None,
532532
}
533533
}
534534
}
@@ -1037,21 +1037,113 @@ impl ElementState {
10371037
}
10381038
}
10391039

1040-
/// Describes a button of a mouse controller.
1040+
/// Identifies a button of a mouse controller.
10411041
///
10421042
/// ## Platform-specific
10431043
///
1044-
/// **macOS:** `Back` and `Forward` might not work with all hardware.
1045-
/// **Orbital:** `Back` and `Forward` are unsupported due to orbital not supporting them.
1044+
/// The first three buttons should be supported on all platforms.
1045+
/// [`Self::Back`] and [`Self::Forward`] are supported on most platforms
1046+
/// (when using a compatible mouse).
1047+
///
1048+
/// - **Android, iOS:** Currently not supported.
1049+
/// - **Orbital:** Only left/right/middle buttons are supported at this time.
1050+
/// - **Web, Windows:** Supports left/right/middle/back/forward buttons.
1051+
/// - **Wayland:** Supports buttons 0..=15.
1052+
/// - **macOS, X11:** Supports all button variants.
1053+
/// - **X11:** Supports buttons 0..=250.
10461054
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
10471055
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1056+
#[repr(u8)]
10481057
pub enum MouseButton {
1049-
Left,
1050-
Right,
1051-
Middle,
1052-
Back,
1053-
Forward,
1054-
Other(u16),
1058+
/// The primary (usually left) button
1059+
Left = 0,
1060+
/// The secondary (usually right) button
1061+
Right = 1,
1062+
/// The tertiary (usually middle) button
1063+
Middle = 2,
1064+
/// The first side button, frequently assigned a back function
1065+
Back = 3,
1066+
/// The second side button, frequently assigned a forward function
1067+
Forward = 4,
1068+
/// The sixth button
1069+
Button5 = 5,
1070+
/// The seventh button
1071+
Button6 = 6,
1072+
/// The eighth button
1073+
Button7 = 7,
1074+
/// The ninth button
1075+
Button8 = 8,
1076+
/// The tenth button
1077+
Button9 = 9,
1078+
/// The eleventh button
1079+
Button10 = 10,
1080+
/// The twelfth button
1081+
Button11 = 11,
1082+
/// The thirteenth button
1083+
Button12 = 12,
1084+
/// The fourteenth button
1085+
Button13 = 13,
1086+
/// The fifteenth button
1087+
Button14 = 14,
1088+
/// The sixteenth button
1089+
Button15 = 15,
1090+
Button16 = 16,
1091+
Button17 = 17,
1092+
Button18 = 18,
1093+
Button19 = 19,
1094+
Button20 = 20,
1095+
Button21 = 21,
1096+
Button22 = 22,
1097+
Button23 = 23,
1098+
Button24 = 24,
1099+
Button25 = 25,
1100+
Button26 = 26,
1101+
Button27 = 27,
1102+
Button28 = 28,
1103+
Button29 = 29,
1104+
Button30 = 30,
1105+
Button31 = 31,
1106+
}
1107+
1108+
impl MouseButton {
1109+
/// Construct from a `u8` if within the range `0..=31`
1110+
pub fn try_from_u8(b: u8) -> Option<MouseButton> {
1111+
Some(match b {
1112+
0 => MouseButton::Left,
1113+
1 => MouseButton::Right,
1114+
2 => MouseButton::Middle,
1115+
3 => MouseButton::Back,
1116+
4 => MouseButton::Forward,
1117+
5 => MouseButton::Button5,
1118+
6 => MouseButton::Button6,
1119+
7 => MouseButton::Button7,
1120+
8 => MouseButton::Button8,
1121+
9 => MouseButton::Button9,
1122+
10 => MouseButton::Button10,
1123+
11 => MouseButton::Button11,
1124+
12 => MouseButton::Button12,
1125+
13 => MouseButton::Button13,
1126+
14 => MouseButton::Button14,
1127+
15 => MouseButton::Button15,
1128+
16 => MouseButton::Button16,
1129+
17 => MouseButton::Button17,
1130+
18 => MouseButton::Button18,
1131+
19 => MouseButton::Button19,
1132+
20 => MouseButton::Button20,
1133+
21 => MouseButton::Button21,
1134+
22 => MouseButton::Button22,
1135+
23 => MouseButton::Button23,
1136+
24 => MouseButton::Button24,
1137+
25 => MouseButton::Button25,
1138+
26 => MouseButton::Button26,
1139+
27 => MouseButton::Button27,
1140+
28 => MouseButton::Button28,
1141+
29 => MouseButton::Button29,
1142+
30 => MouseButton::Button30,
1143+
31 => MouseButton::Button31,
1144+
_ => return None,
1145+
})
1146+
}
10551147
}
10561148

10571149
/// Describes a difference in the mouse scroll wheel state.
@@ -1184,7 +1276,7 @@ mod tests {
11841276
primary: true,
11851277
state: event::ElementState::Pressed,
11861278
position: (0, 0).into(),
1187-
button: event::MouseButton::Other(0).into(),
1279+
button: event::ButtonSource::Unknown(0),
11881280
});
11891281
with_window_event(PointerButton {
11901282
device_id: None,

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -404,22 +404,14 @@ impl Default for WinitPointerDataInner {
404404
/// Convert the Wayland button into winit.
405405
fn wayland_button_to_winit(button: u32) -> ButtonSource {
406406
// These values are coming from <linux/input-event-codes.h>.
407-
const BTN_LEFT: u32 = 0x110;
408-
const BTN_RIGHT: u32 = 0x111;
409-
const BTN_MIDDLE: u32 = 0x112;
410-
const BTN_SIDE: u32 = 0x113;
411-
const BTN_EXTRA: u32 = 0x114;
412-
413-
match button {
414-
BTN_LEFT => MouseButton::Left.into(),
415-
BTN_RIGHT => MouseButton::Right.into(),
416-
BTN_MIDDLE => MouseButton::Middle.into(),
417-
// Note that apps routinely handle BTN_SIDE/BTN_EXTRA as back/forward
418-
BTN_SIDE => MouseButton::Back.into(),
419-
BTN_EXTRA => MouseButton::Forward.into(),
420-
// Skip named buttons (0..=4); map others to 5..
421-
b @ 0x110..=0x11f => MouseButton::Other((b - 0x110) as u16).into(),
422-
other => ButtonSource::Unknown(other as u16),
407+
const BTN_MOUSE: u32 = 0x110;
408+
const BTN_JOYSTICK: u32 = 0x120;
409+
410+
if (BTN_MOUSE..BTN_JOYSTICK).contains(&button) {
411+
// Mapping orders match
412+
MouseButton::try_from_u8((button - BTN_MOUSE) as u8).unwrap().into()
413+
} else {
414+
ButtonSource::Unknown(button as u16)
423415
}
424416
}
425417

winit-win32/src/event_loop.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,7 @@ unsafe fn public_window_callback_inner(
17751775

17761776
WM_XBUTTONDOWN => {
17771777
use winit_core::event::ElementState::Pressed;
1778-
use winit_core::event::MouseButton::{Back, Forward, Other};
1778+
use winit_core::event::MouseButton;
17791779
use winit_core::event::WindowEvent::PointerButton;
17801780
let xbutton = util::get_xbutton_wparam(wparam as u32);
17811781

@@ -1787,25 +1787,25 @@ unsafe fn public_window_callback_inner(
17871787
let y = util::get_y_lparam(lparam as u32) as i32;
17881788
let position = PhysicalPosition::new(x as f64, y as f64);
17891789

1790+
// 1 is defined as back, 2 as forward; other codes are unexpected.
1791+
let b = xbutton as u8 + MouseButton::Back as u8 - 1;
1792+
17901793
userdata.send_window_event(window, PointerButton {
17911794
device_id: None,
17921795
primary: true,
17931796
state: Pressed,
17941797
position,
1795-
button: match xbutton {
1796-
1 => Back,
1797-
2 => Forward,
1798-
_ => Other(xbutton),
1799-
}
1800-
.into(),
1798+
// 1 is defined as back, 2 as forward; other codes are unexpected.
1799+
button: MouseButton::try_from_u8(b).unwrap().into(),
18011800
});
18021801
result = ProcResult::Value(0);
18031802
},
18041803

18051804
WM_XBUTTONUP => {
18061805
use winit_core::event::ElementState::Released;
1807-
use winit_core::event::MouseButton::{Back, Forward, Other};
1806+
use winit_core::event::MouseButton;
18081807
use winit_core::event::WindowEvent::PointerButton;
1808+
18091809
let xbutton = util::get_xbutton_wparam(wparam as u32);
18101810

18111811
unsafe { release_mouse(userdata.window_state_lock()) };
@@ -1816,17 +1816,16 @@ unsafe fn public_window_callback_inner(
18161816
let y = util::get_y_lparam(lparam as u32) as i32;
18171817
let position = PhysicalPosition::new(x as f64, y as f64);
18181818

1819+
// 1 is defined as back, 2 as forward; other codes are unexpected.
1820+
let b = xbutton as u8 + MouseButton::Back as u8 - 1;
1821+
18191822
userdata.send_window_event(window, PointerButton {
18201823
device_id: None,
18211824
primary: true,
18221825
state: Released,
18231826
position,
1824-
button: match xbutton {
1825-
1 => Back,
1826-
2 => Forward,
1827-
_ => Other(xbutton),
1828-
}
1829-
.into(),
1827+
// 1 is defined as back, 2 as forward; other codes are unexpected.
1828+
button: MouseButton::try_from_u8(b).unwrap().into(),
18301829
});
18311830
result = ProcResult::Value(0);
18321831
},

winit-x11/src/event_processor.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,6 @@ impl EventProcessor {
996996
position,
997997
button: MouseButton::Middle.into(),
998998
},
999-
1000999
xlib::Button3 => WindowEvent::PointerButton {
10011000
device_id,
10021001
primary: true,
@@ -1020,28 +1019,23 @@ impl EventProcessor {
10201019
},
10211020
phase: TouchPhase::Moved,
10221021
},
1023-
8 => WindowEvent::PointerButton {
1024-
device_id,
1025-
primary: true,
1026-
state,
1027-
position,
1028-
button: MouseButton::Back.into(),
1029-
},
10301022

1031-
9 => WindowEvent::PointerButton {
1023+
x @ 8..37 => WindowEvent::PointerButton {
10321024
device_id,
10331025
primary: true,
10341026
state,
10351027
position,
1036-
button: MouseButton::Forward.into(),
1028+
// Button 8 maps to MouseButton::BACK = 3; 36 maps to MouseButton::Button::Button31.
1029+
// 255 is the largest code yielded on X11 (tested).
1030+
button: MouseButton::try_from_u8((x - 5) as u8).unwrap().into(),
10371031
},
1038-
x @ 10..=0xffff => WindowEvent::PointerButton {
1032+
x @ 37..=0xff => WindowEvent::PointerButton {
10391033
device_id,
10401034
primary: true,
10411035
state,
10421036
position,
1043-
// Skip named buttons (0..=4), map 10 to 5, 11 to 6, ...
1044-
button: MouseButton::Other((x - 5) as u16).into(),
1037+
// 255 is the largest code yielded on X11 (tested).
1038+
button: ButtonSource::Unknown(x as u16),
10451039
},
10461040
_ => return,
10471041
};

winit/examples/application.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! Note that a real application accepting text input **should** support
44
//! the IME interface. See the `ime` example.
55
6+
use std::borrow::Cow;
67
use std::collections::HashMap;
78
use std::error::Error;
89
use std::fmt::Debug;
@@ -485,8 +486,9 @@ impl ApplicationHandler for Application {
485486
let mods = window.modifiers;
486487
if let Some(action) = state
487488
.is_pressed()
488-
.then(|| Self::process_mouse_binding(button.mouse_button(), &mods))
489+
.then(|| button.mouse_button())
489490
.flatten()
491+
.and_then(|button| Self::process_mouse_binding(button, &mods))
490492
{
491493
self.handle_action_with_window(event_loop, window_id, action);
492494
}
@@ -1145,15 +1147,16 @@ fn modifiers_to_string(mods: ModifiersState) -> String {
11451147
mods_line
11461148
}
11471149

1148-
fn mouse_button_to_string(button: MouseButton) -> &'static str {
1150+
fn mouse_button_to_string(button: MouseButton) -> Cow<'static, str> {
11491151
match button {
11501152
MouseButton::Left => "LMB",
11511153
MouseButton::Right => "RMB",
11521154
MouseButton::Middle => "MMB",
11531155
MouseButton::Back => "Back",
11541156
MouseButton::Forward => "Forward",
1155-
MouseButton::Other(_) => "",
1157+
other => return format!("button {}", other as u8 + 1).into(),
11561158
}
1159+
.into()
11571160
}
11581161

11591162
#[cfg(web_platform)]

0 commit comments

Comments
 (0)