1use std::fmt;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
14pub struct KeyMod(pub u8);
15
16impl KeyMod {
17 pub const SHIFT: KeyMod = KeyMod(1 << 0);
21 pub const ALT: KeyMod = KeyMod(1 << 1);
23 pub const CTRL: KeyMod = KeyMod(1 << 2);
25 pub const META: KeyMod = KeyMod(1 << 3);
27 pub const HYPER: KeyMod = KeyMod(1 << 4);
29 pub const SUPER: KeyMod = KeyMod(1 << 5);
31 pub const CAPS_LOCK: KeyMod = KeyMod(1 << 6);
33 pub const NUM_LOCK: KeyMod = KeyMod(1 << 7);
35
36 pub fn contains(&self, flag: KeyMod) -> bool {
38 (self.0 & flag.0) != 0
39 }
40}
41
42pub const KEY_UP: char = '\u{E000}';
44pub const KEY_DOWN: char = '\u{E001}';
46pub const KEY_RIGHT: char = '\u{E002}';
48pub const KEY_LEFT: char = '\u{E003}';
50pub const KEY_HOME: char = '\u{E004}';
52pub const KEY_END: char = '\u{E005}';
54pub const KEY_PG_UP: char = '\u{E006}';
56pub const KEY_PG_DOWN: char = '\u{E007}';
58pub const KEY_ENTER: char = '\r';
60pub const KEY_TAB: char = '\t';
62pub const KEY_BACKSPACE: char = '\u{007F}';
64pub const KEY_ESCAPE: char = '\u{001B}';
66pub const KEY_SPACE: char = ' ';
68
69#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct Key {
72 pub text: String,
74 pub mod_keys: KeyMod,
76 pub code: char,
78 pub shifted_code: Option<char>,
80 pub base_code: Option<char>,
82 pub is_repeat: bool,
84}
85
86impl Key {
87 pub fn new(code: char, text: &str, mod_keys: KeyMod) -> Self {
89 Self {
90 text: text.to_string(),
91 mod_keys,
92 code,
93 shifted_code: None,
94 base_code: None,
95 is_repeat: false,
96 }
97 }
98
99 pub fn string(&self) -> String {
101 if self.code == ' ' {
102 "space".to_string()
103 } else if !self.text.is_empty() {
104 self.text.clone()
105 } else {
106 self.keystroke()
107 }
108 }
109
110 pub fn keystroke(&self) -> String {
112 let mut parts: Vec<String> = Vec::new();
113 if self.mod_keys.contains(KeyMod::CTRL) {
114 parts.push("ctrl".to_string());
115 }
116 if self.mod_keys.contains(KeyMod::ALT) {
117 parts.push("alt".to_string());
118 }
119 if self.mod_keys.contains(KeyMod::SHIFT) {
120 parts.push("shift".to_string());
121 }
122 if self.mod_keys.contains(KeyMod::META) {
123 parts.push("meta".to_string());
124 }
125
126 let name = match self.code {
127 KEY_UP => "up".to_string(),
128 KEY_DOWN => "down".to_string(),
129 KEY_RIGHT => "right".to_string(),
130 KEY_LEFT => "left".to_string(),
131 KEY_HOME => "home".to_string(),
132 KEY_END => "end".to_string(),
133 KEY_PG_UP => "pgup".to_string(),
134 KEY_PG_DOWN => "pgdown".to_string(),
135 KEY_ENTER => "enter".to_string(),
136 KEY_TAB => "tab".to_string(),
137 KEY_BACKSPACE => "backspace".to_string(),
138 KEY_ESCAPE => "esc".to_string(),
139 ' ' => "space".to_string(),
140 c => c.to_string(),
141 };
142
143 if parts.is_empty() {
144 name
145 } else {
146 parts.push(name);
147 parts.join("+")
148 }
149 }
150}
151
152impl fmt::Display for Key {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(f, "{}", self.string())
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct KeyPressMsg(pub Key);
161
162impl fmt::Display for KeyPressMsg {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 write!(f, "{}", self.0.string())
165 }
166}
167
168#[derive(Debug, Clone, PartialEq, Eq)]
170pub struct KeyReleaseMsg(pub Key);
171
172impl fmt::Display for KeyReleaseMsg {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 write!(f, "{}", self.0.string())
175 }
176}
177
178#[derive(Debug, Clone, PartialEq, Eq)]
180pub enum KeyMsg {
181 Press(KeyPressMsg),
183 Release(KeyReleaseMsg),
185}
186
187impl KeyMsg {
188 pub fn key(&self) -> &Key {
190 match self {
191 KeyMsg::Press(k) => &k.0,
192 KeyMsg::Release(k) => &k.0,
193 }
194 }
195}
196
197impl fmt::Display for KeyMsg {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(f, "{}", self.key().string())
200 }
201}