ui_events/pointer/
buttons.rs

1// Copyright 2025 the UI Events Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4/// Describes a button of a pointer input device, such as a mouse or stylus pen.
5///
6/// B7..B32 exist for the purpose of supporting pointer devices with
7/// large numbers of buttons.
8/// These exotic pointer buttons top out around the 24 buttons range
9/// in practice, and Windows doesn't support more than 32 mouse buttons
10/// in most APIs, therefore 32 was chosen as the upper limit.
11#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
12#[repr(u32)]
13pub enum PointerButton {
14    /// Primary button, commonly the left mouse button, touch contact, pen contact.
15    Primary = 1,
16    /// Secondary button, commonly the right mouse button, pen barrel button.
17    Secondary = 1 << 1,
18    /// Auxiliary button, commonly the middle mouse button.
19    Auxiliary = 1 << 2,
20    /// X1 (back) Mouse.
21    X1 = 1 << 3,
22    /// X2 (forward) Mouse.
23    X2 = 1 << 4,
24    /// Pen erase button.
25    PenEraser = 1 << 5,
26    /// Button 7.
27    B7 = 1 << 6,
28    /// Button 8.
29    B8 = 1 << 7,
30    /// Button 9.
31    B9 = 1 << 8,
32    /// Button 10.
33    B10 = 1 << 9,
34    /// Button 11.
35    B11 = 1 << 10,
36    /// Button 12.
37    B12 = 1 << 11,
38    /// Button 13.
39    B13 = 1 << 12,
40    /// Button 14.
41    B14 = 1 << 13,
42    /// Button 15.
43    B15 = 1 << 14,
44    /// Button 16.
45    B16 = 1 << 15,
46    /// Button 17.
47    B17 = 1 << 16,
48    /// Button 18.
49    B18 = 1 << 17,
50    /// Button 19.
51    B19 = 1 << 18,
52    /// Button 20.
53    B20 = 1 << 19,
54    /// Button 21.
55    B21 = 1 << 20,
56    /// Button 22.
57    B22 = 1 << 21,
58    /// Button 23.
59    B23 = 1 << 22,
60    /// Button 24.
61    B24 = 1 << 23,
62    /// Button 25.
63    B25 = 1 << 24,
64    /// Button 26.
65    B26 = 1 << 25,
66    /// Button 27.
67    B27 = 1 << 26,
68    /// Button 28.
69    B28 = 1 << 27,
70    /// Button 29.
71    B29 = 1 << 28,
72    /// Button 30.
73    B30 = 1 << 29,
74    /// Button 31.
75    B31 = 1 << 30,
76    /// Button 32.
77    B32 = 1 << 31,
78}
79
80/// A set of [`PointerButton`]s.
81#[derive(Clone, Copy, Default, Eq, PartialEq)]
82pub struct PointerButtons(u32);
83
84impl PointerButtons {
85    /// Create a new empty set.
86    #[inline]
87    pub fn new() -> Self {
88        Self(0)
89    }
90
91    /// Add the `button` to the set.
92    #[inline]
93    pub fn insert(&mut self, button: PointerButton) {
94        self.0 |= button as u32;
95    }
96
97    /// Remove the `button` from the set.
98    #[inline]
99    pub fn remove(&mut self, button: PointerButton) {
100        self.0 &= !(button as u32);
101    }
102
103    /// Returns `true` if the `button` is in the set.
104    #[inline]
105    pub fn contains(self, button: PointerButton) -> bool {
106        (self.0 & button as u32) != 0
107    }
108
109    /// Returns `true` if the set is empty.
110    #[inline]
111    pub fn is_empty(self) -> bool {
112        self.0 == 0
113    }
114
115    /// Returns `true` if all the `buttons` are in the set.
116    #[inline]
117    pub fn contains_all(self, buttons: Self) -> bool {
118        self.0 & buttons.0 == buttons.0
119    }
120
121    /// Adds all the `buttons` to the set.
122    #[inline]
123    pub fn extend(&mut self, buttons: Self) {
124        self.0 |= buttons.0;
125    }
126
127    /// Clear the set.
128    #[inline]
129    pub fn clear(&mut self) {
130        self.0 = 0;
131    }
132
133    /// Count the number of buttons in the set.
134    #[inline]
135    pub fn count(self) -> u32 {
136        self.0.count_ones()
137    }
138}
139
140const NONZERO_VARIANTS: [PointerButton; 32] = [
141    PointerButton::Primary,
142    PointerButton::Secondary,
143    PointerButton::Auxiliary,
144    PointerButton::X1,
145    PointerButton::X2,
146    PointerButton::PenEraser,
147    PointerButton::B7,
148    PointerButton::B8,
149    PointerButton::B9,
150    PointerButton::B10,
151    PointerButton::B11,
152    PointerButton::B12,
153    PointerButton::B13,
154    PointerButton::B14,
155    PointerButton::B15,
156    PointerButton::B16,
157    PointerButton::B17,
158    PointerButton::B18,
159    PointerButton::B19,
160    PointerButton::B20,
161    PointerButton::B21,
162    PointerButton::B22,
163    PointerButton::B23,
164    PointerButton::B24,
165    PointerButton::B25,
166    PointerButton::B26,
167    PointerButton::B27,
168    PointerButton::B28,
169    PointerButton::B29,
170    PointerButton::B30,
171    PointerButton::B31,
172    PointerButton::B32,
173];
174
175impl core::fmt::Debug for PointerButtons {
176    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
177        if self.is_empty() {
178            return f.write_str("PointerButtons(None)");
179        }
180
181        f.write_str("PointerButtons(")?;
182
183        if f.alternate() && self.count() > 2 {
184            f.write_str("\n    ")?;
185        }
186
187        let mut first = true;
188        for button in NONZERO_VARIANTS {
189            if self.contains(button) {
190                if !first {
191                    if f.alternate() && self.count() > 2 {
192                        f.write_str("\n    | ")?;
193                    } else {
194                        f.write_str(" | ")?;
195                    }
196                }
197                first = false;
198                button.fmt(f)?;
199            }
200        }
201
202        if f.alternate() && self.count() > 2 {
203            f.write_str("\n)")
204        } else {
205            f.write_str(")")
206        }
207    }
208}
209impl core::fmt::Binary for PointerButtons {
210    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
211        core::fmt::Binary::fmt(&self.0, f)
212    }
213}
214
215impl core::ops::BitOr for PointerButton {
216    type Output = PointerButtons;
217
218    fn bitor(self, rhs: Self) -> Self::Output {
219        PointerButtons(self as u32 | rhs as u32)
220    }
221}
222
223impl core::ops::BitOr<PointerButton> for PointerButtons {
224    type Output = Self;
225
226    fn bitor(self, rhs: PointerButton) -> Self {
227        Self(self.0 | rhs as u32)
228    }
229}
230
231impl core::ops::BitOrAssign<PointerButton> for PointerButtons {
232    fn bitor_assign(&mut self, rhs: PointerButton) {
233        self.0 |= rhs as u32;
234    }
235}
236
237impl From<PointerButton> for PointerButtons {
238    fn from(button: PointerButton) -> Self {
239        Self(button as u32)
240    }
241}
242
243#[cfg(test)]
244mod tests {
245    /// `PointerButtons` debug formatting behavior.
246    #[test]
247    fn debug_fmt() {
248        use crate::pointer::{PointerButton, PointerButtons};
249        extern crate std;
250        use std::format;
251
252        assert_eq!(
253            format!("{:?}", PointerButtons::default()),
254            "PointerButtons(None)"
255        );
256        assert_eq!(
257            format!("{:?}", PointerButtons::from(PointerButton::Primary)),
258            "PointerButtons(Primary)"
259        );
260        assert_eq!(
261            format!("{:?}", PointerButton::Primary | PointerButton::Auxiliary),
262            "PointerButtons(Primary | Auxiliary)"
263        );
264        assert_eq!(
265            format!(
266                "{:?}",
267                PointerButton::Primary | PointerButton::Auxiliary | PointerButton::Secondary
268            ),
269            "PointerButtons(Primary | Secondary | Auxiliary)"
270        );
271        assert_eq!(
272            format!(
273                "{:#?}",
274                (
275                    PointerButton::Primary | PointerButton::Auxiliary | PointerButton::Secondary,
276                    PointerButton::B7 | PointerButton::X2
277                )
278            ),
279            "(
280    PointerButtons(
281        Primary
282        | Secondary
283        | Auxiliary
284    ),
285    PointerButtons(X2 | B7),
286)"
287        );
288        assert_eq!(
289            format!("{:?}", PointerButton::B32 | PointerButton::Primary),
290            "PointerButtons(Primary | B32)"
291        );
292    }
293
294    /// Verify `PointerButton` is same size as `Option<PointerButton>`.
295    #[test]
296    fn option_niche_opt() {
297        use crate::pointer::PointerButton;
298        use core::mem::size_of;
299        assert_eq!(
300            size_of::<Option<PointerButton>>(),
301            size_of::<PointerButton>()
302        );
303    }
304}