ui_events/pointer/
buttons.rs

1// Copyright 2025 the UI Events Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4/// An indicator of which pointer button was pressed.
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    pub fn extend(&mut self, buttons: Self) {
123        self.0 |= buttons.0;
124    }
125
126    /// Clear the set.
127    #[inline]
128    pub fn clear(&mut self) {
129        self.0 = 0;
130    }
131
132    /// Count the number of pressed buttons in the set.
133    #[inline]
134    pub fn count(self) -> u32 {
135        self.0.count_ones()
136    }
137}
138
139const NONZERO_VARIANTS: [PointerButton; 32] = [
140    PointerButton::Primary,
141    PointerButton::Secondary,
142    PointerButton::Auxiliary,
143    PointerButton::X1,
144    PointerButton::X2,
145    PointerButton::PenEraser,
146    PointerButton::B7,
147    PointerButton::B8,
148    PointerButton::B9,
149    PointerButton::B10,
150    PointerButton::B11,
151    PointerButton::B12,
152    PointerButton::B13,
153    PointerButton::B14,
154    PointerButton::B15,
155    PointerButton::B16,
156    PointerButton::B17,
157    PointerButton::B18,
158    PointerButton::B19,
159    PointerButton::B20,
160    PointerButton::B21,
161    PointerButton::B22,
162    PointerButton::B23,
163    PointerButton::B24,
164    PointerButton::B25,
165    PointerButton::B26,
166    PointerButton::B27,
167    PointerButton::B28,
168    PointerButton::B29,
169    PointerButton::B30,
170    PointerButton::B31,
171    PointerButton::B32,
172];
173
174impl core::fmt::Debug for PointerButtons {
175    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
176        if self.is_empty() {
177            return f.write_str("PointerButtons(None)");
178        }
179
180        f.write_str("PointerButtons(")?;
181
182        if f.alternate() && self.count() > 2 {
183            f.write_str("\n    ")?;
184        }
185
186        let mut first = true;
187        for button in NONZERO_VARIANTS {
188            if self.contains(button) {
189                if !first {
190                    if f.alternate() && self.count() > 2 {
191                        f.write_str("\n    | ")?;
192                    } else {
193                        f.write_str(" | ")?;
194                    }
195                }
196                first = false;
197                button.fmt(f)?;
198            }
199        }
200
201        if f.alternate() && self.count() > 2 {
202            f.write_str("\n)")
203        } else {
204            f.write_str(")")
205        }
206    }
207}
208impl core::fmt::Binary for PointerButtons {
209    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
210        core::fmt::Binary::fmt(&self.0, f)
211    }
212}
213
214impl core::ops::BitOr for PointerButton {
215    type Output = PointerButtons;
216
217    fn bitor(self, rhs: Self) -> Self::Output {
218        PointerButtons(self as u32 | rhs as u32)
219    }
220}
221
222impl core::ops::BitOr<PointerButton> for PointerButtons {
223    type Output = Self;
224
225    fn bitor(self, rhs: PointerButton) -> Self {
226        Self(self.0 | rhs as u32)
227    }
228}
229
230impl core::ops::BitOrAssign<PointerButton> for PointerButtons {
231    fn bitor_assign(&mut self, rhs: PointerButton) {
232        self.0 |= rhs as u32;
233    }
234}
235
236impl From<PointerButton> for PointerButtons {
237    fn from(button: PointerButton) -> Self {
238        Self(button as u32)
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    /// `PointerButtons` debug formatting behavior.
245    #[test]
246    fn debug_fmt() {
247        use crate::pointer::{PointerButton, PointerButtons};
248        extern crate std;
249        use std::format;
250
251        assert_eq!(
252            format!("{:?}", PointerButtons::default()),
253            "PointerButtons(None)"
254        );
255        assert_eq!(
256            format!("{:?}", PointerButtons::from(PointerButton::Primary)),
257            "PointerButtons(Primary)"
258        );
259        assert_eq!(
260            format!("{:?}", PointerButton::Primary | PointerButton::Auxiliary),
261            "PointerButtons(Primary | Auxiliary)"
262        );
263        assert_eq!(
264            format!(
265                "{:?}",
266                PointerButton::Primary | PointerButton::Auxiliary | PointerButton::Secondary
267            ),
268            "PointerButtons(Primary | Secondary | Auxiliary)"
269        );
270        assert_eq!(
271            format!(
272                "{:#?}",
273                (
274                    PointerButton::Primary | PointerButton::Auxiliary | PointerButton::Secondary,
275                    PointerButton::B7 | PointerButton::X2
276                )
277            ),
278            "(
279    PointerButtons(
280        Primary
281        | Secondary
282        | Auxiliary
283    ),
284    PointerButtons(X2 | B7),
285)"
286        );
287        assert_eq!(
288            format!("{:?}", PointerButton::B32 | PointerButton::Primary),
289            "PointerButtons(Primary | B32)"
290        );
291    }
292
293    /// Verify `PointerButton` is same size as `Option<PointerButton>`.
294    #[test]
295    fn option_niche_opt() {
296        use crate::pointer::PointerButton;
297        use core::mem::size_of;
298        assert_eq!(
299            size_of::<Option<PointerButton>>(),
300            size_of::<PointerButton>()
301        );
302    }
303}