Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions winit-appkit/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1096,14 +1096,11 @@ fn mouse_button(event: &NSEvent) -> MouseButton {
// 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 unsafe { event.buttonNumber() } {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
3 => MouseButton::Back,
4 => MouseButton::Forward,
n => MouseButton::Other(n as u16),
}
let b: isize = unsafe { event.buttonNumber() };
b.try_into()
.ok()
.and_then(MouseButton::try_from_u8)
.expect("expected MacOS button number in the range 0..=31")
}

// NOTE: to get option as alt working we need to rewrite events
Expand Down
132 changes: 110 additions & 22 deletions winit-core/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,25 +514,21 @@ pub enum ButtonSource {
finger_id: FingerId,
force: Option<Force>,
},
/// A pointer button of unknown source.
///
/// Codes are undefined and may not be reproducible across platforms or winit versions.
Unknown(u16),
}

impl ButtonSource {
/// Convert any [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
/// Try to convert a [`ButtonSource`] to an equivalent [`MouseButton`]. If a pointer type has no
/// special handling in an application, this method can be used to handle it like any generic
/// mouse input.
pub fn mouse_button(self) -> MouseButton {
pub fn mouse_button(self) -> Option<MouseButton> {
Comment on lines -524 to +527
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ButtonSource::mouse_button now returns None on ButtonSource::Unknown (no other reasonable option).

match self {
ButtonSource::Mouse(mouse) => mouse,
ButtonSource::Touch { .. } => MouseButton::Left,
ButtonSource::Unknown(button) => match button {
0 => MouseButton::Left,
1 => MouseButton::Middle,
2 => MouseButton::Right,
3 => MouseButton::Back,
4 => MouseButton::Forward,
_ => MouseButton::Other(button),
},
ButtonSource::Mouse(mouse) => Some(mouse),
ButtonSource::Touch { .. } => Some(MouseButton::Left),
ButtonSource::Unknown(_) => None,
}
}
}
Expand Down Expand Up @@ -1041,21 +1037,113 @@ impl ElementState {
}
}

/// Describes a button of a mouse controller.
/// Identifies 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.
/// The first three buttons should be supported on all platforms.
/// [`Self::Back`] and [`Self::Forward`] are supported on most platforms
/// (when using a compatible mouse).
///
/// - **Android, iOS:** Currently not supported.
/// - **Orbital:** Only left/right/middle buttons are supported at this time.
/// - **Web, Windows:** Supports left/right/middle/back/forward buttons.
/// - **Wayland:** Supports buttons 0..=15.
/// - **macOS, X11:** Supports all button variants.
/// - **X11:** Supports buttons 0..=250.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum MouseButton {
Left,
Right,
Middle,
Back,
Forward,
Other(u16),
/// The primary (usually left) button
Left = 0,
/// The secondary (usually right) button
Right = 1,
/// The tertiary (usually middle) button
Middle = 2,
/// The first side button, frequently assigned a back function
Back = 3,
/// The second side button, frequently assigned a forward function
Forward = 4,
/// The sixth button
Button5 = 5,
/// The seventh button
Button6 = 6,
/// The eighth button
Button7 = 7,
/// The ninth button
Button8 = 8,
/// The tenth button
Button9 = 9,
/// The eleventh button
Button10 = 10,
/// The twelfth button
Button11 = 11,
/// The thirteenth button
Button12 = 12,
/// The fourteenth button
Button13 = 13,
/// The fifteenth button
Button14 = 14,
/// The sixteenth button
Button15 = 15,
Button16 = 16,
Button17 = 17,
Button18 = 18,
Button19 = 19,
Button20 = 20,
Button21 = 21,
Button22 = 22,
Button23 = 23,
Button24 = 24,
Button25 = 25,
Button26 = 26,
Button27 = 27,
Button28 = 28,
Button29 = 29,
Button30 = 30,
Button31 = 31,
}

impl MouseButton {
/// Construct from a `u8` if within the range `0..=31`
pub fn try_from_u8(b: u8) -> Option<MouseButton> {
Comment on lines +1108 to +1110
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An alternative would be to use the num_enum crate, I guess. I didn't use TryFrom since that returns a Result.

Some(match b {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
3 => MouseButton::Back,
4 => MouseButton::Forward,
5 => MouseButton::Button5,
6 => MouseButton::Button6,
7 => MouseButton::Button7,
8 => MouseButton::Button8,
9 => MouseButton::Button9,
10 => MouseButton::Button10,
11 => MouseButton::Button11,
12 => MouseButton::Button12,
13 => MouseButton::Button13,
14 => MouseButton::Button14,
15 => MouseButton::Button15,
16 => MouseButton::Button16,
17 => MouseButton::Button17,
18 => MouseButton::Button18,
19 => MouseButton::Button19,
20 => MouseButton::Button20,
21 => MouseButton::Button21,
22 => MouseButton::Button22,
23 => MouseButton::Button23,
24 => MouseButton::Button24,
25 => MouseButton::Button25,
26 => MouseButton::Button26,
27 => MouseButton::Button27,
28 => MouseButton::Button28,
29 => MouseButton::Button29,
30 => MouseButton::Button30,
31 => MouseButton::Button31,
_ => return None,
})
}
}

/// Describes a difference in the mouse scroll wheel state.
Expand Down Expand Up @@ -1188,7 +1276,7 @@ mod tests {
primary: true,
state: event::ElementState::Pressed,
position: (0, 0).into(),
button: event::MouseButton::Other(0).into(),
button: event::ButtonSource::Unknown(0),
});
with_window_event(PointerButton {
device_id: None,
Expand Down
33 changes: 13 additions & 20 deletions winit-wayland/src/seat/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use sctk::seat::SeatState;
use dpi::{LogicalPosition, PhysicalPosition};
use winit_core::event::{
ElementState, MouseButton, MouseScrollDelta, PointerKind, PointerSource, TouchPhase,
WindowEvent,
WindowEvent, ButtonSource,
};

use crate::state::WinitState;
Expand Down Expand Up @@ -108,8 +108,8 @@ impl PointerHandler for WinitState {
if parent_surface != surface =>
{
let click = match wayland_button_to_winit(button) {
MouseButton::Left => FrameClick::Normal,
MouseButton::Right => FrameClick::Alternate,
ButtonSource::Mouse(MouseButton::Left) => FrameClick::Normal,
ButtonSource::Mouse(MouseButton::Right) => FrameClick::Alternate,
_ => continue,
};
let pressed = matches!(kind, PointerEventKind::Press { .. });
Expand Down Expand Up @@ -186,7 +186,7 @@ impl PointerHandler for WinitState {
device_id: None,
state,
position,
button: button.into(),
button,
},
window_id,
);
Expand Down Expand Up @@ -402,23 +402,16 @@ impl Default for WinitPointerDataInner {
}

/// Convert the Wayland button into winit.
fn wayland_button_to_winit(button: u32) -> MouseButton {
fn wayland_button_to_winit(button: u32) -> ButtonSource {
// 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),
const BTN_MOUSE: u32 = 0x110;
const BTN_JOYSTICK: u32 = 0x120;

if (BTN_MOUSE..BTN_JOYSTICK).contains(&button) {
// Mapping orders match
MouseButton::try_from_u8((button - BTN_MOUSE) as u8).unwrap().into()
} else {
ButtonSource::Unknown(button as u16)
}
}

Expand Down
12 changes: 4 additions & 8 deletions winit-web/src/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use crate::event_loop::ActiveEventLoop;
use crate::main_thread::MainThreadMarker;
use crate::monitor::MonitorHandler;
use crate::r#async::DispatchRunner;
use crate::web_sys::event::mouse_button_to_id;
use crate::window::Inner;
use crate::{backend, event, EventLoop, PollStrategy, WaitUntilStrategy};

Expand Down Expand Up @@ -319,18 +318,15 @@ impl Shared {
let device_id = event::mkdid(event.pointer_id());

if let Some(button) = backend::event::mouse_button(&event) {
let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
let state = if backend::event::mouse_buttons(&event).contains(button.state()) {
ElementState::Pressed
} else {
ElementState::Released
};

runner.send_event(Event::DeviceEvent {
device_id,
event: DeviceEvent::Button {
button: mouse_button_to_id(button).into(),
state,
},
event: DeviceEvent::Button { button: button.raw().into(), state },
});

return;
Expand Down Expand Up @@ -379,7 +375,7 @@ impl Shared {
runner.send_event(Event::DeviceEvent {
device_id: event::mkdid(event.pointer_id()),
event: DeviceEvent::Button {
button: mouse_button_to_id(button).into(),
button: button.raw().into(),
state: ElementState::Pressed,
},
});
Expand All @@ -398,7 +394,7 @@ impl Shared {
runner.send_event(Event::DeviceEvent {
device_id: event::mkdid(event.pointer_id()),
event: DeviceEvent::Button {
button: mouse_button_to_id(button).into(),
button: button.raw().into(),
state: ElementState::Released,
},
});
Expand Down
Loading
Loading