kozan_core/input/
modifiers.rs1#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
23pub struct Modifiers(u16);
24
25const SHIFT: u16 = 1 << 0;
27const CTRL: u16 = 1 << 1;
28const ALT: u16 = 1 << 2;
29const META: u16 = 1 << 3; const CAPS_LOCK: u16 = 1 << 4;
31const NUM_LOCK: u16 = 1 << 5;
32
33const LEFT_BUTTON: u16 = 1 << 6;
36const RIGHT_BUTTON: u16 = 1 << 7;
37const MIDDLE_BUTTON: u16 = 1 << 8;
38
39const IS_AUTO_REPEAT: u16 = 1 << 9;
41
42impl Modifiers {
43 pub const EMPTY: Self = Self(0);
45
46 #[inline]
48 #[must_use]
49 pub const fn from_bits(bits: u16) -> Self {
50 Self(bits)
51 }
52
53 #[inline]
55 #[must_use]
56 pub const fn bits(self) -> u16 {
57 self.0
58 }
59
60 #[inline]
64 #[must_use]
65 pub const fn shift(self) -> bool {
66 self.0 & SHIFT != 0
67 }
68
69 #[inline]
71 #[must_use]
72 pub const fn ctrl(self) -> bool {
73 self.0 & CTRL != 0
74 }
75
76 #[inline]
78 #[must_use]
79 pub const fn alt(self) -> bool {
80 self.0 & ALT != 0
81 }
82
83 #[inline]
85 #[must_use]
86 pub const fn meta(self) -> bool {
87 self.0 & META != 0
88 }
89
90 #[inline]
92 #[must_use]
93 pub const fn caps_lock(self) -> bool {
94 self.0 & CAPS_LOCK != 0
95 }
96
97 #[inline]
99 #[must_use]
100 pub const fn num_lock(self) -> bool {
101 self.0 & NUM_LOCK != 0
102 }
103
104 #[inline]
108 #[must_use]
109 pub const fn left_button(self) -> bool {
110 self.0 & LEFT_BUTTON != 0
111 }
112
113 #[inline]
115 #[must_use]
116 pub const fn right_button(self) -> bool {
117 self.0 & RIGHT_BUTTON != 0
118 }
119
120 #[inline]
122 #[must_use]
123 pub const fn middle_button(self) -> bool {
124 self.0 & MIDDLE_BUTTON != 0
125 }
126
127 #[inline]
131 #[must_use]
132 pub const fn is_auto_repeat(self) -> bool {
133 self.0 & IS_AUTO_REPEAT != 0
134 }
135
136 #[inline]
139 #[must_use]
140 pub const fn with_shift(self) -> Self {
141 Self(self.0 | SHIFT)
142 }
143 #[inline]
144 #[must_use]
145 pub const fn with_ctrl(self) -> Self {
146 Self(self.0 | CTRL)
147 }
148 #[inline]
149 #[must_use]
150 pub const fn with_alt(self) -> Self {
151 Self(self.0 | ALT)
152 }
153 #[inline]
154 #[must_use]
155 pub const fn with_meta(self) -> Self {
156 Self(self.0 | META)
157 }
158 #[inline]
159 #[must_use]
160 pub const fn with_caps_lock(self) -> Self {
161 Self(self.0 | CAPS_LOCK)
162 }
163 #[inline]
164 #[must_use]
165 pub const fn with_num_lock(self) -> Self {
166 Self(self.0 | NUM_LOCK)
167 }
168 #[inline]
169 #[must_use]
170 pub const fn with_left_button(self) -> Self {
171 Self(self.0 | LEFT_BUTTON)
172 }
173 #[inline]
174 #[must_use]
175 pub const fn with_right_button(self) -> Self {
176 Self(self.0 | RIGHT_BUTTON)
177 }
178 #[inline]
179 #[must_use]
180 pub const fn with_middle_button(self) -> Self {
181 Self(self.0 | MIDDLE_BUTTON)
182 }
183 #[inline]
184 #[must_use]
185 pub const fn with_auto_repeat(self) -> Self {
186 Self(self.0 | IS_AUTO_REPEAT)
187 }
188
189 #[inline]
191 #[must_use]
192 pub const fn union(self, other: Self) -> Self {
193 Self(self.0 | other.0)
194 }
195
196 #[inline]
198 #[must_use]
199 pub const fn contains(self, other: Self) -> bool {
200 self.0 & other.0 == other.0
201 }
202}
203
204impl std::ops::BitOr for Modifiers {
205 type Output = Self;
206 #[inline]
207 fn bitor(self, rhs: Self) -> Self {
208 Self(self.0 | rhs.0)
209 }
210}
211
212impl std::ops::BitOrAssign for Modifiers {
213 #[inline]
214 fn bitor_assign(&mut self, rhs: Self) {
215 self.0 |= rhs.0;
216 }
217}
218
219impl std::fmt::Display for Modifiers {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 let mut parts = Vec::new();
222 if self.ctrl() {
223 parts.push("Ctrl");
224 }
225 if self.shift() {
226 parts.push("Shift");
227 }
228 if self.alt() {
229 parts.push("Alt");
230 }
231 if self.meta() {
232 parts.push("Meta");
233 }
234 if parts.is_empty() {
235 write!(f, "None")
236 } else {
237 write!(f, "{}", parts.join("+"))
238 }
239 }
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn empty_has_no_modifiers() {
248 let m = Modifiers::EMPTY;
249 assert!(!m.shift());
250 assert!(!m.ctrl());
251 assert!(!m.alt());
252 assert!(!m.meta());
253 assert!(!m.left_button());
254 assert_eq!(m.bits(), 0);
255 }
256
257 #[test]
258 fn builder_methods() {
259 let m = Modifiers::EMPTY.with_ctrl().with_shift();
260 assert!(m.ctrl());
261 assert!(m.shift());
262 assert!(!m.alt());
263 assert!(!m.meta());
264 }
265
266 #[test]
267 fn bitor_combines() {
268 let a = Modifiers::EMPTY.with_ctrl();
269 let b = Modifiers::EMPTY.with_shift();
270 let c = a | b;
271 assert!(c.ctrl());
272 assert!(c.shift());
273 }
274
275 #[test]
276 fn contains_checks_subset() {
277 let m = Modifiers::EMPTY.with_ctrl().with_shift().with_alt();
278 let subset = Modifiers::EMPTY.with_ctrl().with_shift();
279 assert!(m.contains(subset));
280 assert!(!subset.contains(m));
281 }
282
283 #[test]
284 fn display_format() {
285 let m = Modifiers::EMPTY.with_ctrl().with_shift();
286 assert_eq!(format!("{}", m), "Ctrl+Shift");
287 assert_eq!(format!("{}", Modifiers::EMPTY), "None");
288 }
289
290 #[test]
291 fn mouse_button_state() {
292 let m = Modifiers::EMPTY.with_left_button().with_ctrl();
293 assert!(m.left_button());
294 assert!(m.ctrl());
295 assert!(!m.right_button());
296 }
297
298 #[test]
299 fn auto_repeat_flag() {
300 let m = Modifiers::EMPTY.with_auto_repeat();
301 assert!(m.is_auto_repeat());
302 }
303
304 #[test]
305 fn size_is_two_bytes() {
306 assert_eq!(std::mem::size_of::<Modifiers>(), 2);
307 }
308}