1use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};
7
8use bitfield_struct::bitfield;
9use postcard::experimental::max_size::MaxSize;
10use serde::{Deserialize, Serialize};
11
12#[bitfield(u8, order = Lsb, defmt = cfg(feature = "defmt"))]
14#[derive(Serialize, Deserialize, MaxSize, Eq, PartialEq)]
15
16pub struct ModifierCombination {
17 #[bits(1)]
18 pub left_ctrl: bool,
19 #[bits(1)]
20 pub left_shift: bool,
21 #[bits(1)]
22 pub left_alt: bool,
23 #[bits(1)]
24 pub left_gui: bool,
25 #[bits(1)]
26 pub right_ctrl: bool,
27 #[bits(1)]
28 pub right_shift: bool,
29 #[bits(1)]
30 pub right_alt: bool,
31 #[bits(1)]
32 pub right_gui: bool,
33}
34
35impl BitOr for ModifierCombination {
36 type Output = Self;
37
38 fn bitor(self, rhs: Self) -> Self::Output {
39 Self::from_bits(self.into_bits() | rhs.into_bits())
40 }
41}
42
43impl BitAnd for ModifierCombination {
44 type Output = Self;
45
46 fn bitand(self, rhs: Self) -> Self::Output {
47 Self::from_bits(self.into_bits() & rhs.into_bits())
48 }
49}
50
51impl BitAndAssign for ModifierCombination {
52 fn bitand_assign(&mut self, rhs: Self) {
53 *self = *self & rhs;
54 }
55}
56
57impl BitOrAssign for ModifierCombination {
58 fn bitor_assign(&mut self, rhs: Self) {
59 *self = *self | rhs;
60 }
61}
62
63impl Not for ModifierCombination {
64 type Output = Self;
65
66 fn not(self) -> Self::Output {
67 Self::from_bits(!self.into_bits())
68 }
69}
70
71impl ModifierCombination {
72 pub const LCTRL: Self = Self::new().with_left_ctrl(true);
73 pub const LSHIFT: Self = Self::new().with_left_shift(true);
74 pub const LALT: Self = Self::new().with_left_alt(true);
75 pub const LGUI: Self = Self::new().with_left_gui(true);
76
77 pub const RCTRL: Self = Self::new().with_right_ctrl(true);
78 pub const RSHIFT: Self = Self::new().with_right_shift(true);
79 pub const RALT: Self = Self::new().with_right_alt(true);
80 pub const RGUI: Self = Self::new().with_right_gui(true);
81
82 pub const fn new_from(right: bool, gui: bool, alt: bool, shift: bool, ctrl: bool) -> Self {
83 if right {
84 ModifierCombination::new()
85 .with_right_gui(gui)
86 .with_right_alt(alt)
87 .with_right_shift(shift)
88 .with_right_ctrl(ctrl)
89 } else {
90 ModifierCombination::new()
91 .with_left_gui(gui)
92 .with_left_alt(alt)
93 .with_left_shift(shift)
94 .with_left_ctrl(ctrl)
95 }
96 }
97
98 #[allow(clippy::too_many_arguments)]
99 pub const fn new_from_vals(
100 left_ctrl: bool,
101 left_shift: bool,
102 left_alt: bool,
103 left_gui: bool,
104 right_ctrl: bool,
105 right_shift: bool,
106 right_alt: bool,
107 right_gui: bool,
108 ) -> Self {
109 ModifierCombination::new()
110 .with_left_ctrl(left_ctrl)
111 .with_left_shift(left_shift)
112 .with_left_alt(left_alt)
113 .with_left_gui(left_gui)
114 .with_right_ctrl(right_ctrl)
115 .with_right_shift(right_shift)
116 .with_right_alt(right_alt)
117 .with_right_gui(right_gui)
118 }
119
120 pub const fn into_packed_bits(self) -> u8 {
129 let bits = self.into_bits();
130 if bits == 0 {
131 return 0;
132 }
133 let left_bits = bits & 0x0F; let right_bits = bits >> 4; if left_bits != 0 {
138 left_bits
139 } else {
140 right_bits | 0x10 }
142 }
143
144 pub const fn from_packed_bits(bits: u8) -> Self {
152 let modifier_bits = bits & 0x0F; let is_right = (bits & 0x10) != 0; if is_right {
156 Self::from_bits(modifier_bits << 4) } else {
158 Self::from_bits(modifier_bits) }
160 }
161}