1#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
8#[repr(transparent)]
9pub struct KeyMod(pub u16);
10
11impl KeyMod {
12 pub const NONE: KeyMod = KeyMod(0x0000);
13 pub const LSHIFT: KeyMod = KeyMod(0x0001);
14 pub const RSHIFT: KeyMod = KeyMod(0x0002);
15 pub const LEVEL5: KeyMod = KeyMod(0x0004);
16 pub const LCTRL: KeyMod = KeyMod(0x0040);
17 pub const RCTRL: KeyMod = KeyMod(0x0080);
18 pub const LALT: KeyMod = KeyMod(0x0100);
19 pub const RALT: KeyMod = KeyMod(0x0200);
20 pub const LGUI: KeyMod = KeyMod(0x0400);
21 pub const RGUI: KeyMod = KeyMod(0x0800);
22 pub const NUM: KeyMod = KeyMod(0x1000);
23 pub const CAPS: KeyMod = KeyMod(0x2000);
24 pub const MODE: KeyMod = KeyMod(0x4000);
25 pub const SCROLL: KeyMod = KeyMod(0x8000);
26
27 pub const SHIFT: KeyMod = KeyMod(Self::LSHIFT.0 | Self::RSHIFT.0);
28 pub const CTRL: KeyMod = KeyMod(Self::LCTRL.0 | Self::RCTRL.0);
29 pub const ALT: KeyMod = KeyMod(Self::LALT.0 | Self::RALT.0);
30 pub const GUI: KeyMod = KeyMod(Self::LGUI.0 | Self::RGUI.0);
31
32 #[inline]
33 pub const fn new(raw: u16) -> Self {
34 Self(raw)
35 }
36
37 #[inline]
38 pub const fn raw(self) -> u16 {
39 self.0
40 }
41
42 #[inline]
43 pub const fn contains(self, other: KeyMod) -> bool {
44 (self.0 & other.0) == other.0
45 }
46
47 #[inline]
48 pub const fn intersects(self, other: KeyMod) -> bool {
49 (self.0 & other.0) != 0
50 }
51
52 #[inline]
53 pub const fn is_empty(self) -> bool {
54 self.0 == 0
55 }
56
57 #[inline]
59 pub const fn shift(self) -> bool {
60 self.intersects(Self::SHIFT)
61 }
62
63 #[inline]
65 pub const fn ctrl(self) -> bool {
66 self.intersects(Self::CTRL)
67 }
68
69 #[inline]
71 pub const fn alt(self) -> bool {
72 self.intersects(Self::ALT)
73 }
74
75 #[inline]
77 pub const fn gui(self) -> bool {
78 self.intersects(Self::GUI)
79 }
80
81 #[inline]
84 pub const fn altgr(self) -> bool {
85 self.intersects(KeyMod(Self::MODE.0 | Self::RALT.0))
86 }
87
88 #[inline]
90 pub const fn caps(self) -> bool {
91 self.contains(Self::CAPS)
92 }
93
94 #[inline]
96 pub const fn num(self) -> bool {
97 self.contains(Self::NUM)
98 }
99}
100
101impl std::ops::BitOr for KeyMod {
102 type Output = KeyMod;
103 #[inline]
104 fn bitor(self, rhs: KeyMod) -> KeyMod {
105 KeyMod(self.0 | rhs.0)
106 }
107}
108
109impl std::ops::BitAnd for KeyMod {
110 type Output = KeyMod;
111 #[inline]
112 fn bitand(self, rhs: KeyMod) -> KeyMod {
113 KeyMod(self.0 & rhs.0)
114 }
115}
116
117impl std::ops::BitOrAssign for KeyMod {
118 #[inline]
119 fn bitor_assign(&mut self, rhs: KeyMod) {
120 self.0 |= rhs.0;
121 }
122}
123
124impl std::ops::BitAndAssign for KeyMod {
125 #[inline]
126 fn bitand_assign(&mut self, rhs: KeyMod) {
127 self.0 &= rhs.0;
128 }
129}
130
131impl std::ops::Not for KeyMod {
132 type Output = KeyMod;
133 #[inline]
134 fn not(self) -> KeyMod {
135 KeyMod(!self.0)
136 }
137}
138
139impl From<u16> for KeyMod {
140 #[inline]
141 fn from(value: u16) -> Self {
142 KeyMod(value)
143 }
144}
145
146impl From<KeyMod> for u16 {
147 #[inline]
148 fn from(value: KeyMod) -> Self {
149 value.0
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn sdl_compatible_values() {
159 assert_eq!(KeyMod::LSHIFT.raw(), 0x0001);
160 assert_eq!(KeyMod::LCTRL.raw(), 0x0040);
161 assert_eq!(KeyMod::LALT.raw(), 0x0100);
162 assert_eq!(KeyMod::LGUI.raw(), 0x0400);
163 assert_eq!(KeyMod::NUM.raw(), 0x1000);
164 assert_eq!(KeyMod::CAPS.raw(), 0x2000);
165 assert_eq!(KeyMod::MODE.raw(), 0x4000);
166 }
167
168 #[test]
169 fn modifier_groups() {
170 assert!((KeyMod::LSHIFT | KeyMod::LCTRL).shift());
171 assert!((KeyMod::LSHIFT | KeyMod::LCTRL).ctrl());
172 assert!((KeyMod::RALT).altgr());
173 assert!((KeyMod::MODE).altgr());
174 assert!(!(KeyMod::LALT).altgr());
175 }
176}