Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 4.1 kB View raw
1use core::fmt; 2 3use serde::{Deserialize, Serialize}; 4 5#[derive( 6 Copy, Clone, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, 7)] 8#[serde(transparent)] 9pub struct ModifierMask(u8); 10 11impl ModifierMask { 12 pub const NONE: Self = Self(0); 13 pub const CTRL: Self = Self(1 << 0); 14 pub const SHIFT: Self = Self(1 << 1); 15 pub const ALT: Self = Self(1 << 2); 16 pub const META: Self = Self(1 << 3); 17 18 #[must_use] 19 pub const fn contains(self, other: Self) -> bool { 20 (self.0 & other.0) == other.0 21 } 22 23 #[must_use] 24 pub const fn union(self, other: Self) -> Self { 25 Self(self.0 | other.0) 26 } 27} 28 29impl core::ops::BitOr for ModifierMask { 30 type Output = Self; 31 fn bitor(self, rhs: Self) -> Self { 32 self.union(rhs) 33 } 34} 35 36impl fmt::Display for ModifierMask { 37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 38 for (flag, name) in [ 39 (Self::CTRL, "Ctrl"), 40 (Self::SHIFT, "Shift"), 41 (Self::ALT, "Alt"), 42 (Self::META, "Meta"), 43 ] { 44 if self.contains(flag) { 45 f.write_str(name)?; 46 f.write_str("+")?; 47 } 48 } 49 Ok(()) 50 } 51} 52 53#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] 54pub enum NamedKey { 55 Tab, 56 Enter, 57 Escape, 58 Backspace, 59 Delete, 60 Space, 61 ArrowUp, 62 ArrowDown, 63 ArrowLeft, 64 ArrowRight, 65 Home, 66 End, 67 PageUp, 68 PageDown, 69 F2, 70} 71 72impl NamedKey { 73 #[must_use] 74 pub const fn label(self) -> &'static str { 75 match self { 76 Self::Tab => "Tab", 77 Self::Enter => "Enter", 78 Self::Escape => "Esc", 79 Self::Backspace => "Backspace", 80 Self::Delete => "Delete", 81 Self::Space => "Space", 82 Self::ArrowUp => "Up", 83 Self::ArrowDown => "Down", 84 Self::ArrowLeft => "Left", 85 Self::ArrowRight => "Right", 86 Self::Home => "Home", 87 Self::End => "End", 88 Self::PageUp => "PageUp", 89 Self::PageDown => "PageDown", 90 Self::F2 => "F2", 91 } 92 } 93} 94 95impl fmt::Display for NamedKey { 96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 f.write_str(self.label()) 98 } 99} 100 101#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] 102#[serde(transparent)] 103pub struct KeyChar(char); 104 105impl KeyChar { 106 #[must_use] 107 pub fn from_char(c: char) -> Self { 108 Self(c.to_lowercase().next().unwrap_or(c)) 109 } 110 111 #[must_use] 112 pub const fn from_ascii(c: char) -> Self { 113 Self(c.to_ascii_lowercase()) 114 } 115 116 #[must_use] 117 pub const fn get(self) -> char { 118 self.0 119 } 120} 121 122#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] 123pub enum KeyCode { 124 Named(NamedKey), 125 Char(KeyChar), 126} 127 128impl fmt::Display for KeyCode { 129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 130 match self { 131 Self::Named(named) => fmt::Display::fmt(named, f), 132 Self::Char(c) => f.write_str(&c.get().to_uppercase().collect::<String>()), 133 } 134 } 135} 136 137#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] 138pub struct KeyEvent { 139 pub code: KeyCode, 140 pub modifiers: ModifierMask, 141} 142 143impl KeyEvent { 144 #[must_use] 145 pub const fn new(code: KeyCode, modifiers: ModifierMask) -> Self { 146 Self { code, modifiers } 147 } 148} 149 150#[cfg(test)] 151mod tests { 152 use super::{KeyChar, ModifierMask}; 153 154 #[test] 155 fn modifier_contains_self() { 156 let m = ModifierMask::CTRL | ModifierMask::SHIFT; 157 assert!(m.contains(ModifierMask::CTRL)); 158 assert!(m.contains(ModifierMask::SHIFT)); 159 assert!(!m.contains(ModifierMask::ALT)); 160 } 161 162 #[test] 163 fn key_char_normalizes_to_lower() { 164 assert_eq!(KeyChar::from_char('A').get(), 'a'); 165 assert_eq!(KeyChar::from_char('z').get(), 'z'); 166 assert_eq!(KeyChar::from_char('É').get(), 'é'); 167 } 168}