1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
3pub enum MouseButton {
4 Left,
6 Right,
8 Middle,
10}
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum MouseKind {
15 Down(MouseButton),
17 Up(MouseButton),
19 Drag(MouseButton),
21 Moved,
23 ScrollUp,
25 ScrollDown,
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
34pub struct MouseEvent {
35 pub x: u16,
37 pub y: u16,
39 pub kind: MouseKind,
41 pub mods: KeyMods,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
47pub struct MouseMoveEvent {
48 pub x: u16,
50 pub y: u16,
52 pub local_x: u16,
54 pub local_y: u16,
56 pub target_w: u16,
58 pub target_h: u16,
60 pub mods: KeyMods,
62}
63
64#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
66pub struct MouseDragEvent {
67 pub from_x: u16,
69 pub from_y: u16,
71 pub from_local_x: u16,
73 pub from_local_y: u16,
75 pub x: u16,
77 pub y: u16,
79 pub local_x: u16,
81 pub local_y: u16,
83 pub delta_x: i16,
85 pub delta_y: i16,
87 pub target_w: u16,
89 pub target_h: u16,
91 pub mods: KeyMods,
93}
94
95#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
97pub struct KeyMods {
98 pub ctrl: bool,
100 pub alt: bool,
102 pub shift: bool,
104 pub super_key: bool,
106}
107
108impl KeyMods {
109 pub const NONE: Self = Self {
111 ctrl: false,
112 alt: false,
113 shift: false,
114 super_key: false,
115 };
116
117 pub const SHIFT: Self = Self {
119 ctrl: false,
120 alt: false,
121 shift: true,
122 super_key: false,
123 };
124
125 pub const CTRL: Self = Self {
127 ctrl: true,
128 alt: false,
129 shift: false,
130 super_key: false,
131 };
132
133 pub const ALT: Self = Self {
135 ctrl: false,
136 alt: true,
137 shift: false,
138 super_key: false,
139 };
140
141 pub fn is_empty(&self) -> bool {
143 !self.ctrl && !self.alt && !self.shift && !self.super_key
144 }
145}
146
147#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
149pub enum KeyCode {
150 Char(char),
152 Insert,
154 Enter,
156 Esc,
158 Tab,
160 BackTab,
162 Backspace,
164 Delete,
166 Home,
168 End,
170 PageUp,
172 PageDown,
174 Up,
176 Down,
178 Left,
180 Right,
182 F(u8),
184}
185
186#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
192pub struct KeyEvent {
193 pub code: KeyCode,
195 pub mods: KeyMods,
197}
198
199impl KeyEvent {
200 pub fn is(&self, code: KeyCode) -> bool {
202 self.code == code && self.mods.is_empty()
203 }
204
205 pub fn is_with(&self, code: KeyCode, mods: KeyMods) -> bool {
207 self.code == code && self.mods == mods
208 }
209
210 pub fn to_formatted_string(&self, lowercase: bool) -> String {
214 let mut parts = Vec::new();
215
216 if self.mods.ctrl {
217 parts.push("Ctrl");
218 }
219 if self.mods.alt {
220 parts.push("Alt");
221 }
222 if self.mods.super_key {
223 parts.push("Super");
224 }
225 if self.mods.shift {
226 parts.push("Shift");
227 }
228
229 let code_str = match self.code {
230 KeyCode::Char(c) => {
231 if c == ' ' {
232 "Space".to_string()
233 } else {
234 c.to_uppercase().to_string()
235 }
236 }
237 KeyCode::Insert => "Insert".to_string(),
238 KeyCode::Enter => "Enter".to_string(),
239 KeyCode::Esc => "Esc".to_string(),
240 KeyCode::Tab => "Tab".to_string(),
241 KeyCode::BackTab => "BackTab".to_string(),
242 KeyCode::Backspace => "Backspace".to_string(),
243 KeyCode::Delete => "Delete".to_string(),
244 KeyCode::Home => "Home".to_string(),
245 KeyCode::End => "End".to_string(),
246 KeyCode::PageUp => "PageUp".to_string(),
247 KeyCode::PageDown => "PageDown".to_string(),
248 KeyCode::Up => "Up".to_string(),
249 KeyCode::Down => "Down".to_string(),
250 KeyCode::Left => "Left".to_string(),
251 KeyCode::Right => "Right".to_string(),
252 KeyCode::F(n) => format!("F{n}"),
253 };
254 parts.push(&code_str);
255
256 let result = parts.join("+");
257 if lowercase {
258 result.to_lowercase()
259 } else {
260 result
261 }
262 }
263}
264
265impl std::fmt::Display for KeyEvent {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 write!(f, "{}", self.to_formatted_string(false))
268 }
269}
270
271#[cfg(test)]
272mod tests {
273 use super::*;
274
275 #[test]
276 fn test_key_event_formatting() {
277 let key1 = KeyEvent {
278 code: KeyCode::Char('e'),
279 mods: KeyMods {
280 ctrl: true,
281 alt: false,
282 shift: false,
283 super_key: false,
284 },
285 };
286 assert_eq!(key1.to_formatted_string(false), "Ctrl+E");
287 assert_eq!(key1.to_formatted_string(true), "ctrl+e");
288 assert_eq!(key1.to_string(), "Ctrl+E");
289
290 let key2 = KeyEvent {
291 code: KeyCode::Enter,
292 mods: KeyMods {
293 ctrl: true,
294 alt: true,
295 shift: true,
296 super_key: false,
297 },
298 };
299 assert_eq!(key2.to_formatted_string(false), "Ctrl+Alt+Shift+Enter");
300 assert_eq!(key2.to_formatted_string(true), "ctrl+alt+shift+enter");
301 assert_eq!(key2.to_string(), "Ctrl+Alt+Shift+Enter");
302
303 let key3 = KeyEvent {
304 code: KeyCode::Char(' '),
305 mods: KeyMods {
306 ctrl: false,
307 alt: false,
308 shift: false,
309 super_key: false,
310 },
311 };
312 assert_eq!(key3.to_formatted_string(false), "Space");
313 assert_eq!(key3.to_string(), "Space");
314
315 let key4 = KeyEvent {
316 code: KeyCode::F(12),
317 mods: KeyMods {
318 ctrl: false,
319 alt: false,
320 shift: false,
321 super_key: false,
322 },
323 };
324 assert_eq!(key4.to_formatted_string(false), "F12");
325 assert_eq!(key4.to_formatted_string(true), "f12");
326 assert_eq!(key4.to_string(), "F12");
327 }
328
329 #[test]
330 fn test_key_event_matching_helpers_and_mod_constants() {
331 let plain_enter = KeyEvent {
332 code: KeyCode::Enter,
333 mods: KeyMods::NONE,
334 };
335 assert!(plain_enter.is(KeyCode::Enter));
336 assert!(plain_enter.is_with(KeyCode::Enter, KeyMods::NONE));
337
338 let shift_enter = KeyEvent {
339 code: KeyCode::Enter,
340 mods: KeyMods::SHIFT,
341 };
342 assert!(!shift_enter.is(KeyCode::Enter));
343 assert!(shift_enter.is_with(KeyCode::Enter, KeyMods::SHIFT));
344 assert!(!shift_enter.is_with(KeyCode::Enter, KeyMods::NONE));
345
346 assert!(KeyMods::NONE.is_empty());
347 assert!(!KeyMods::SHIFT.is_empty());
348 }
349}