Skip to main content

orbclient/
event.rs

1// SPDX-License-Identifier: MIT
2
3use core::ops::{Deref, DerefMut};
4use core::{char, mem, slice};
5
6pub const EVENT_NONE: i64 = 0;
7pub const EVENT_KEY: i64 = 1;
8pub const EVENT_MOUSE: i64 = 2;
9pub const EVENT_BUTTON: i64 = 3;
10pub const EVENT_SCROLL: i64 = 4;
11pub const EVENT_QUIT: i64 = 5;
12pub const EVENT_FOCUS: i64 = 6;
13pub const EVENT_MOVE: i64 = 7;
14pub const EVENT_RESIZE: i64 = 8;
15pub const EVENT_SCREEN: i64 = 9;
16pub const EVENT_CLIPBOARD: i64 = 10;
17pub const EVENT_MOUSE_RELATIVE: i64 = 11;
18pub const EVENT_DROP: i64 = 12;
19pub const EVENT_TEXT_INPUT: i64 = 13;
20pub const EVENT_CLIPBOARD_UPDATE: i64 = 14;
21pub const EVENT_HOVER: i64 = 15;
22
23/// An optional event
24#[derive(Copy, Clone, Debug)]
25pub enum EventOption {
26    /// A key event
27    Key(KeyEvent),
28    /// A text input event
29    TextInput(TextInputEvent),
30    /// A mouse event (absolute)
31    Mouse(MouseEvent),
32    /// A mouse event (relative)
33    MouseRelative(MouseRelativeEvent),
34    /// A mouse button event
35    Button(ButtonEvent),
36    /// A mouse scroll event
37    Scroll(ScrollEvent),
38    /// A quit request event
39    Quit(QuitEvent),
40    /// A focus event
41    Focus(FocusEvent),
42    /// A move event
43    Move(MoveEvent),
44    /// A resize event
45    Resize(ResizeEvent),
46    /// A screen report event
47    Screen(ScreenEvent),
48    /// A clipboard event
49    Clipboard(ClipboardEvent),
50    /// A clipboard update event
51    ClipboardUpdate(ClipboardUpdateEvent),
52    /// A drop file / text event (available on linux, windows and macOS)
53    Drop(DropEvent),
54    /// A hover event
55    Hover(HoverEvent),
56    /// An unknown event
57    Unknown(Event),
58    /// No event
59    None,
60}
61
62/// An event
63#[derive(Copy, Clone, Debug)]
64#[repr(packed)]
65pub struct Event {
66    pub code: i64,
67    pub a: i64,
68    pub b: i64,
69}
70
71#[allow(clippy::new_without_default)]
72impl Event {
73    /// Create a null event
74    pub fn new() -> Event {
75        Event {
76            code: 0,
77            a: 0,
78            b: 0,
79        }
80    }
81
82    /// Convert the event ot an optional event
83    // TODO: Consider doing this via a From trait.
84    pub fn to_option(self) -> EventOption {
85        match self.code {
86            EVENT_NONE => EventOption::None,
87            EVENT_KEY => EventOption::Key(KeyEvent::from_event(self)),
88            EVENT_TEXT_INPUT => EventOption::TextInput(TextInputEvent::from_event(self)),
89            EVENT_MOUSE => EventOption::Mouse(MouseEvent::from_event(self)),
90            EVENT_MOUSE_RELATIVE => {
91                EventOption::MouseRelative(MouseRelativeEvent::from_event(self))
92            }
93            EVENT_BUTTON => EventOption::Button(ButtonEvent::from_event(self)),
94            EVENT_SCROLL => EventOption::Scroll(ScrollEvent::from_event(self)),
95            EVENT_QUIT => EventOption::Quit(QuitEvent::from_event(self)),
96            EVENT_FOCUS => EventOption::Focus(FocusEvent::from_event(self)),
97            EVENT_MOVE => EventOption::Move(MoveEvent::from_event(self)),
98            EVENT_RESIZE => EventOption::Resize(ResizeEvent::from_event(self)),
99            EVENT_SCREEN => EventOption::Screen(ScreenEvent::from_event(self)),
100            EVENT_CLIPBOARD => EventOption::Clipboard(ClipboardEvent::from_event(self)),
101            EVENT_CLIPBOARD_UPDATE => {
102                EventOption::ClipboardUpdate(ClipboardUpdateEvent::from_event(self))
103            }
104            EVENT_DROP => EventOption::Drop(DropEvent::from_event(self)),
105            EVENT_HOVER => EventOption::Hover(HoverEvent::from_event(self)),
106            _ => EventOption::Unknown(self),
107        }
108    }
109}
110
111impl Deref for Event {
112    type Target = [u8];
113    fn deref(&self) -> &[u8] {
114        unsafe {
115            slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::<Event>())
116                as &[u8]
117        }
118    }
119}
120
121impl DerefMut for Event {
122    fn deref_mut(&mut self) -> &mut [u8] {
123        unsafe {
124            slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::<Event>())
125                as &mut [u8]
126        }
127    }
128}
129
130// Mapped closely with scancodes from XT keyboard.
131// Unconventional ranges should be in 0x60-0x7F, 0x80 and above are for media keys
132// See https://aeb.win.tue.nl/linux/kbd/scancodes-10.html
133
134pub const K_A: u8 = 0x1E;
135pub const K_B: u8 = 0x30;
136pub const K_C: u8 = 0x2E;
137pub const K_D: u8 = 0x20;
138pub const K_E: u8 = 0x12;
139pub const K_F: u8 = 0x21;
140pub const K_G: u8 = 0x22;
141pub const K_H: u8 = 0x23;
142pub const K_I: u8 = 0x17;
143pub const K_J: u8 = 0x24;
144pub const K_K: u8 = 0x25;
145pub const K_L: u8 = 0x26;
146pub const K_M: u8 = 0x32;
147pub const K_N: u8 = 0x31;
148pub const K_O: u8 = 0x18;
149pub const K_P: u8 = 0x19;
150pub const K_Q: u8 = 0x10;
151pub const K_R: u8 = 0x13;
152pub const K_S: u8 = 0x1F;
153pub const K_T: u8 = 0x14;
154pub const K_U: u8 = 0x16;
155pub const K_V: u8 = 0x2F;
156pub const K_W: u8 = 0x11;
157pub const K_X: u8 = 0x2D;
158pub const K_Y: u8 = 0x15;
159pub const K_Z: u8 = 0x2C;
160pub const K_0: u8 = 0x0B;
161pub const K_1: u8 = 0x02;
162pub const K_2: u8 = 0x03;
163pub const K_3: u8 = 0x04;
164pub const K_4: u8 = 0x05;
165pub const K_5: u8 = 0x06;
166pub const K_6: u8 = 0x07;
167pub const K_7: u8 = 0x08;
168pub const K_8: u8 = 0x09;
169pub const K_9: u8 = 0x0A;
170
171// Numpad keys (codes 0x70-0x7f)
172
173pub const K_NUM_0: u8 = 0x70;
174pub const K_NUM_1: u8 = 0x71;
175pub const K_NUM_2: u8 = 0x72;
176pub const K_NUM_3: u8 = 0x73;
177pub const K_NUM_4: u8 = 0x74;
178pub const K_NUM_5: u8 = 0x75;
179pub const K_NUM_6: u8 = 0x76;
180pub const K_NUM_7: u8 = 0x77;
181pub const K_NUM_8: u8 = 0x78;
182pub const K_NUM_9: u8 = 0x79;
183pub const K_NUM_PERIOD: u8 = 0x7a;
184pub const K_NUM_PLUS: u8 = 0x7c;
185pub const K_NUM_MINUS: u8 = 0x7b;
186pub const K_NUM_ASTERISK: u8 = 0x7d;
187pub const K_NUM_SLASH: u8 = 0x7e;
188pub const K_NUM_ENTER: u8 = 0x7f;
189
190/// Tick/tilde key
191pub const K_TICK: u8 = 0x29;
192/// Minus/underline key
193pub const K_MINUS: u8 = 0x0C;
194/// Equals/plus key
195pub const K_EQUALS: u8 = 0x0D;
196/// Backslash/pipe key
197pub const K_BACKSLASH: u8 = 0x2B;
198/// Bracket open key
199pub const K_BRACE_OPEN: u8 = 0x1A;
200/// Bracket close key
201pub const K_BRACE_CLOSE: u8 = 0x1B;
202/// Semicolon key
203pub const K_SEMICOLON: u8 = 0x27;
204/// Quote key
205pub const K_QUOTE: u8 = 0x28;
206/// Comma key
207pub const K_COMMA: u8 = 0x33;
208/// Period key
209pub const K_PERIOD: u8 = 0x34;
210/// Slash key
211pub const K_SLASH: u8 = 0x35;
212/// Backspace key
213pub const K_BKSP: u8 = 0x0E;
214/// Space key
215pub const K_SPACE: u8 = 0x39;
216/// Tab key
217pub const K_TAB: u8 = 0x0F;
218/// Capslock
219pub const K_CAPS: u8 = 0x3A;
220/// Left shift
221pub const K_LEFT_SHIFT: u8 = 0x2A;
222/// Right shift
223pub const K_RIGHT_SHIFT: u8 = 0x36;
224/// Control key (deprecated)
225pub const K_CTRL: u8 = 0x1D;
226/// Left control key
227pub const K_LEFT_CTRL: u8 = 0x1D;
228/// Right control key
229pub const K_RIGHT_CTRL: u8 = 0x64;
230/// Alt key
231pub const K_ALT: u8 = 0x38;
232/// AltGr key
233pub const K_ALT_GR: u8 = 0x64;
234/// Enter key
235pub const K_ENTER: u8 = 0x1C;
236/// Escape key
237pub const K_ESC: u8 = 0x01;
238/// Print screen key
239pub const K_PRTSC: u8 = 0x37;
240/// F1 key
241pub const K_F1: u8 = 0x3B;
242/// F2 key
243pub const K_F2: u8 = 0x3C;
244/// F3 key
245pub const K_F3: u8 = 0x3D;
246/// F4 key
247pub const K_F4: u8 = 0x3E;
248/// F5 key
249pub const K_F5: u8 = 0x3F;
250/// F6 key
251pub const K_F6: u8 = 0x40;
252/// F7 key
253pub const K_F7: u8 = 0x41;
254/// F8 key
255pub const K_F8: u8 = 0x42;
256/// F9 key
257pub const K_F9: u8 = 0x43;
258/// F10 key
259pub const K_F10: u8 = 0x44;
260/// Num lock key
261pub const K_NUM: u8 = 0x45;
262/// Scroll lock key
263pub const K_SCROLL: u8 = 0x46;
264/// Home key
265pub const K_HOME: u8 = 0x47;
266/// Up key
267pub const K_UP: u8 = 0x48;
268/// Page up key
269pub const K_PGUP: u8 = 0x49;
270/// Left key
271pub const K_LEFT: u8 = 0x4B;
272/// Right key
273pub const K_RIGHT: u8 = 0x4D;
274/// End key
275pub const K_END: u8 = 0x4F;
276/// Down key
277pub const K_DOWN: u8 = 0x50;
278/// Page down key
279pub const K_PGDN: u8 = 0x51;
280/// Insert key
281pub const K_INS: u8 = 0x52;
282/// Delete key
283pub const K_DEL: u8 = 0x53;
284/// F11 key
285pub const K_F11: u8 = 0x57;
286/// F12 key
287pub const K_F12: u8 = 0x58;
288/// SUPER/META/WIN Key (deprecated)
289pub const K_SUPER: u8 = 0x5B;
290/// SUPER/META/WIN Left Key
291pub const K_LEFT_SUPER: u8 = 0x5B;
292/// SUPER/META/WIN Right Key
293pub const K_RIGHT_SUPER: u8 = 0x5C;
294/// Application key
295pub const K_APP: u8 = 0x5D;
296/// Power off key
297pub const K_POWER: u8 = 0x5E;
298/// Sleep key
299pub const K_SLEEP: u8 = 0x5F;
300
301// Media keys are derived from MF II keyboards
302// See https://www.scs.stanford.edu/10wi-cs140/pintos/specs/kbd/scancodes-5.html
303
304/// Media Key for Volume toggle (mute/unmute)
305pub const K_VOLUME_TOGGLE: u8 = 0x80 + 0x20;
306/// Media Key for Volume Down
307pub const K_VOLUME_DOWN: u8 = 0x80 + 0x2E;
308/// Media Key for Volume Up
309pub const K_VOLUME_UP: u8 = 0x80 + 0x30;
310/// Media Key for Play/pause
311pub const K_MEDIA_PLAY_PAUSE: u8 = 0x80 + 0x22;
312/// Media Key for Stop
313pub const K_MEDIA_STOP: u8 = 0x80 + 0x24;
314/// Media Key for Fast forward/next track
315pub const K_MEDIA_FAST_FORWARD: u8 = 0x80 + 0x19;
316/// Media Key for Rewind/previous track
317pub const K_MEDIA_REWIND: u8 = 0x80 + 0x10;
318
319/// A key event (such as a pressed key)
320#[derive(Copy, Clone, Debug)]
321pub struct KeyEvent {
322    /// The character of the key
323    pub character: char,
324    /// The scancode of the key
325    pub scancode: u8,
326    /// Was it pressed?
327    pub pressed: bool,
328}
329
330impl KeyEvent {
331    /// Convert to an `Event`
332    pub fn to_event(&self) -> Event {
333        Event {
334            code: EVENT_KEY,
335            a: self.character as i64,
336            b: self.scancode as i64 | (self.pressed as i64) << 8,
337        }
338    }
339
340    /// Convert from an `Event`
341    pub fn from_event(event: Event) -> KeyEvent {
342        KeyEvent {
343            character: char::from_u32(event.a as u32).unwrap_or('\0'),
344            scancode: event.b as u8,
345            pressed: event.b & 1 << 8 == 1 << 8,
346        }
347    }
348}
349
350#[derive(Copy, Clone, Debug)]
351pub struct TextInputEvent {
352    pub character: char,
353}
354
355impl TextInputEvent {
356    /// Convert to an `Event`
357    pub fn to_event(&self) -> Event {
358        Event {
359            code: EVENT_TEXT_INPUT,
360            a: self.character as i64,
361            b: 0,
362        }
363    }
364
365    /// Convert from an `Event`
366    pub fn from_event(event: Event) -> TextInputEvent {
367        TextInputEvent {
368            character: char::from_u32(event.a as u32).unwrap_or('\0'),
369        }
370    }
371}
372
373/// A event related to the mouse (absolute position)
374#[derive(Copy, Clone, Debug)]
375pub struct MouseEvent {
376    /// The x coordinate of the mouse
377    pub x: i32,
378    /// The y coordinate of the mouse
379    pub y: i32,
380}
381
382impl MouseEvent {
383    /// Convert to an `Event`
384    pub fn to_event(&self) -> Event {
385        Event {
386            code: EVENT_MOUSE,
387            a: self.x as i64,
388            b: self.y as i64,
389        }
390    }
391
392    /// Convert an `Event` to a `MouseEvent`
393    pub fn from_event(event: Event) -> MouseEvent {
394        MouseEvent {
395            x: event.a as i32,
396            y: event.b as i32,
397        }
398    }
399}
400
401/// A event related to the mouse (relative position)
402#[derive(Copy, Clone, Debug)]
403pub struct MouseRelativeEvent {
404    /// The x coordinate of the mouse
405    pub dx: i32,
406    /// The y coordinate of the mouse
407    pub dy: i32,
408}
409
410impl MouseRelativeEvent {
411    /// Convert to an `Event`
412    pub fn to_event(&self) -> Event {
413        Event {
414            code: EVENT_MOUSE_RELATIVE,
415            a: self.dx as i64,
416            b: self.dy as i64,
417        }
418    }
419
420    /// Convert an `Event` to a `MouseRelativeEvent`
421    pub fn from_event(event: Event) -> MouseRelativeEvent {
422        MouseRelativeEvent {
423            dx: event.a as i32,
424            dy: event.b as i32,
425        }
426    }
427}
428
429/// A event for clicking the mouse
430#[derive(Copy, Clone, Debug)]
431pub struct ButtonEvent {
432    /// Was the left button pressed?
433    pub left: bool,
434    /// Was the middle button pressed?
435    pub middle: bool,
436    /// Was the right button pressed?
437    pub right: bool,
438}
439
440impl ButtonEvent {
441    /// Convert to an `Event`
442    pub fn to_event(&self) -> Event {
443        Event {
444            code: EVENT_BUTTON,
445            a: self.left as i64 | (self.middle as i64) << 1 | (self.right as i64) << 2,
446            b: 0,
447        }
448    }
449
450    /// Convert an `Event` to a `ButtonEvent`
451    pub fn from_event(event: Event) -> ButtonEvent {
452        ButtonEvent {
453            left: event.a & 1 == 1,
454            middle: event.a & 2 == 2,
455            right: event.a & 4 == 4,
456        }
457    }
458}
459
460/// A event for scrolling the mouse
461#[derive(Copy, Clone, Debug)]
462pub struct ScrollEvent {
463    /// The x distance of the scroll
464    pub x: i32,
465    /// The y distance of the scroll
466    pub y: i32,
467}
468
469impl ScrollEvent {
470    /// Convert to an `Event`
471    pub fn to_event(&self) -> Event {
472        Event {
473            code: EVENT_SCROLL,
474            a: self.x as i64,
475            b: self.y as i64,
476        }
477    }
478
479    /// Convert an `Event` to a `ScrollEvent`
480    pub fn from_event(event: Event) -> ScrollEvent {
481        ScrollEvent {
482            x: event.a as i32,
483            y: event.b as i32,
484        }
485    }
486}
487
488#[derive(Copy, Clone, Debug)]
489pub struct QuitEvent;
490
491impl QuitEvent {
492    pub fn to_event(&self) -> Event {
493        Event {
494            code: EVENT_QUIT,
495            a: 0,
496            b: 0,
497        }
498    }
499
500    pub fn from_event(_: Event) -> QuitEvent {
501        QuitEvent
502    }
503}
504
505/// A focus event
506#[derive(Copy, Clone, Debug)]
507pub struct FocusEvent {
508    /// True if window has been focused, false if not
509    pub focused: bool,
510}
511
512impl FocusEvent {
513    pub fn to_event(&self) -> Event {
514        Event {
515            code: EVENT_FOCUS,
516            a: self.focused as i64,
517            b: 0,
518        }
519    }
520
521    pub fn from_event(event: Event) -> FocusEvent {
522        FocusEvent {
523            focused: event.a > 0,
524        }
525    }
526}
527
528/// A move event
529#[derive(Copy, Clone, Debug)]
530pub struct MoveEvent {
531    pub x: i32,
532    pub y: i32,
533}
534
535impl MoveEvent {
536    pub fn to_event(&self) -> Event {
537        Event {
538            code: EVENT_MOVE,
539            a: self.x as i64,
540            b: self.y as i64,
541        }
542    }
543
544    pub fn from_event(event: Event) -> MoveEvent {
545        MoveEvent {
546            x: event.a as i32,
547            y: event.b as i32,
548        }
549    }
550}
551
552/// A resize event
553#[derive(Copy, Clone, Debug)]
554pub struct ResizeEvent {
555    pub width: u32,
556    pub height: u32,
557}
558
559impl ResizeEvent {
560    pub fn to_event(&self) -> Event {
561        Event {
562            code: EVENT_RESIZE,
563            a: self.width as i64,
564            b: self.height as i64,
565        }
566    }
567
568    pub fn from_event(event: Event) -> ResizeEvent {
569        ResizeEvent {
570            width: event.a as u32,
571            height: event.b as u32,
572        }
573    }
574}
575
576/// A screen report event
577#[derive(Copy, Clone, Debug)]
578pub struct ScreenEvent {
579    pub width: u32,
580    pub height: u32,
581}
582
583impl ScreenEvent {
584    pub fn to_event(&self) -> Event {
585        Event {
586            code: EVENT_SCREEN,
587            a: self.width as i64,
588            b: self.height as i64,
589        }
590    }
591
592    pub fn from_event(event: Event) -> ScreenEvent {
593        ScreenEvent {
594            width: event.a as u32,
595            height: event.b as u32,
596        }
597    }
598}
599
600pub const CLIPBOARD_COPY: u8 = 0;
601pub const CLIPBOARD_CUT: u8 = 1;
602pub const CLIPBOARD_PASTE: u8 = 2;
603
604/// A clipboard event
605#[derive(Copy, Clone, Debug)]
606pub struct ClipboardUpdateEvent;
607
608impl ClipboardUpdateEvent {
609    pub fn to_event(&self) -> Event {
610        Event {
611            code: EVENT_CLIPBOARD_UPDATE,
612            a: 0,
613            b: 0,
614        }
615    }
616
617    pub fn from_event(_: Event) -> ClipboardUpdateEvent {
618        ClipboardUpdateEvent
619    }
620}
621
622/// A clipboard event
623#[derive(Copy, Clone, Debug)]
624pub struct ClipboardEvent {
625    pub kind: u8,
626    pub size: usize,
627}
628
629impl ClipboardEvent {
630    pub fn to_event(&self) -> Event {
631        Event {
632            code: EVENT_CLIPBOARD,
633            a: self.kind as i64,
634            b: self.size as i64,
635        }
636    }
637
638    pub fn from_event(event: Event) -> ClipboardEvent {
639        ClipboardEvent {
640            kind: event.a as u8,
641            size: event.b as usize,
642        }
643    }
644}
645
646pub const DROP_FILE: u8 = 0;
647pub const DROP_TEXT: u8 = 1;
648
649/// A drop file event.
650#[derive(Copy, Clone, Debug)]
651pub struct DropEvent {
652    pub kind: u8,
653}
654
655impl DropEvent {
656    pub fn to_event(&self) -> Event {
657        Event {
658            code: EVENT_DROP,
659            a: self.kind as i64,
660            b: 0,
661        }
662    }
663
664    pub fn from_event(event: Event) -> DropEvent {
665        DropEvent {
666            kind: event.a as u8,
667        }
668    }
669}
670
671/// A hover event
672#[derive(Copy, Clone, Debug)]
673pub struct HoverEvent {
674    /// True if window has been entered, false if exited
675    pub entered: bool,
676}
677
678impl HoverEvent {
679    pub fn to_event(&self) -> Event {
680        Event {
681            code: EVENT_HOVER,
682            a: self.entered as i64,
683            b: 0,
684        }
685    }
686
687    pub fn from_event(event: Event) -> HoverEvent {
688        HoverEvent {
689            entered: event.a > 0,
690        }
691    }
692}