Skip to content

Commit 5f9239e

Browse files
madsmtmpyfisch
authored andcommitted
Separate Key into Character and NamedKey
This makes most of the key Copy, and allows other crates like Winit to more easily use their own string types.
1 parent 48b40a2 commit 5f9239e

File tree

6 files changed

+201
-193
lines changed

6 files changed

+201
-193
lines changed

convert.py

+17-48
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def parse(text):
4242
code.replace_with(f"[`{text}`][Code::{text}]")
4343
for code in typical_usage.find_all(class_='key'):
4444
text = code.text.strip().strip('"')
45-
code.replace_with(f"[`{text}`][Key::{text}]")
45+
code.replace_with(f"[`{text}`][NamedKey::{text}]")
4646

4747
comment = re.sub(r"[ \t][ \t]+", "\n", typical_usage.decode_contents())
4848

@@ -106,15 +106,10 @@ def convert_key(text, file):
106106
///
107107
/// Specification:
108108
/// <https://w3c.github.io/uievents-key/>
109-
#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
109+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
110110
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
111111
#[non_exhaustive]
112-
pub enum Key {
113-
/// A key string that corresponds to the character typed by the user,
114-
/// taking into account the user’s current locale setting, modifier state,
115-
/// and any system-level keyboard mapping overrides that are in effect.
116-
Character(String),
117-
""", file=file)
112+
pub enum NamedKey {""", file=file)
118113
display = parse(text)
119114

120115
for i in range(1, 36):
@@ -130,64 +125,40 @@ def convert_key(text, file):
130125

131126
print("""
132127
133-
impl Display for Key {
128+
impl Display for NamedKey {
134129
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135-
use self::Key::*;
136-
match *self {
137-
Character(ref s) => write!(f, "{}", s),
138-
""", file=file)
130+
use self::NamedKey::*;
131+
match *self {""", file=file)
139132
print_display_entries(display, file)
140133
print("""
141134
}
142135
}
143136
}
144137
145-
impl FromStr for Key {
146-
type Err = UnrecognizedKeyError;
138+
impl FromStr for NamedKey {
139+
type Err = UnrecognizedNamedKeyError;
147140
148141
fn from_str(s: &str) -> Result<Self, Self::Err> {
149-
use crate::Key::*;
150-
match s {
151-
s if is_key_string(s) => Ok(Character(s.to_string())),""", file=file)
142+
use crate::NamedKey::*;
143+
match s {""", file=file)
152144
print_from_str_entries(display, file)
153145
print("""
154-
_ => Err(UnrecognizedKeyError),
146+
_ => Err(UnrecognizedNamedKeyError),
155147
}
156148
}
157149
}
158150
159151
/// Parse from string error, returned when string does not match to any Key variant.
160152
#[derive(Clone, Debug)]
161-
pub struct UnrecognizedKeyError;
153+
pub struct UnrecognizedNamedKeyError;
162154
163-
impl fmt::Display for UnrecognizedKeyError {
155+
impl fmt::Display for UnrecognizedNamedKeyError {
164156
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
165157
write!(f, "Unrecognized key")
166158
}
167159
}
168160
169-
impl Error for UnrecognizedKeyError {}
170-
171-
/// Check if string can be used as a `Key::Character` _keystring_.
172-
///
173-
/// This check is simple and is meant to prevents common mistakes like mistyped keynames
174-
/// (e.g. `Ennter`) from being recognized as characters.
175-
fn is_key_string(s: &str) -> bool {
176-
s.chars().all(|c| !c.is_control()) && s.chars().skip(1).all(|c| !c.is_ascii())
177-
}
178-
179-
#[cfg(test)]
180-
mod test {
181-
use super::*;
182-
183-
#[test]
184-
fn test_is_key_string() {
185-
assert!(is_key_string("A"));
186-
assert!(!is_key_string("AA"));
187-
assert!(!is_key_string("\t"));
188-
}
189-
}
190-
""", file=file)
161+
impl Error for UnrecognizedNamedKeyError {}""", file=file)
191162

192163

193164
def convert_code(text, file):
@@ -273,8 +244,7 @@ def convert_code(text, file):
273244
impl Display for Code {
274245
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275246
use self::Code::*;
276-
match *self {
277-
""", file=file)
247+
match *self {""", file=file)
278248
print_display_entries(display, file)
279249
print("""
280250
}
@@ -304,13 +274,12 @@ def convert_code(text, file):
304274
}
305275
}
306276
307-
impl Error for UnrecognizedCodeError {}
308-
""", file=file)
277+
impl Error for UnrecognizedCodeError {}""", file=file)
309278

310279

311280
if __name__ == '__main__':
312281
input = requests.get('https://w3c.github.io/uievents-key/').text
313-
with open('src/key.rs', 'w', encoding='utf-8') as output:
282+
with open('src/named_key.rs', 'w', encoding='utf-8') as output:
314283
convert_key(input, output)
315284
input = requests.get('https://w3c.github.io/uievents-code/').text
316285
with open('src/code.rs', 'w', encoding='utf-8') as output:

src/code.rs

-2
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,6 @@ impl Display for Code {
475475
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
476476
use self::Code::*;
477477
match *self {
478-
479478
Backquote => f.write_str("Backquote"),
480479
Backslash => f.write_str("Backslash"),
481480
BracketLeft => f.write_str("BracketLeft"),
@@ -936,4 +935,3 @@ impl fmt::Display for UnrecognizedCodeError {
936935
}
937936

938937
impl Error for UnrecognizedCodeError {}
939-

src/lib.rs

+89-22
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,19 @@
66
77
#![warn(clippy::doc_markdown)]
88

9+
use core::fmt;
10+
use core::str::FromStr;
11+
912
pub use crate::code::{Code, UnrecognizedCodeError};
10-
pub use crate::key::{Key, UnrecognizedKeyError};
1113
pub use crate::location::Location;
1214
pub use crate::modifiers::Modifiers;
15+
pub use crate::named_key::{NamedKey, UnrecognizedNamedKeyError};
1316
pub use crate::shortcuts::ShortcutMatcher;
1417

1518
mod code;
16-
mod key;
1719
mod location;
1820
mod modifiers;
21+
mod named_key;
1922
mod shortcuts;
2023
#[cfg(feature = "webdriver")]
2124
pub mod webdriver;
@@ -149,6 +152,44 @@ pub struct CompositionEvent {
149152
pub data: String,
150153
}
151154

155+
/// The value recieved from the keypress.
156+
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
157+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
158+
pub enum Key {
159+
/// A key string that corresponds to the character typed by the user,
160+
/// taking into account the user’s current locale setting, modifier state,
161+
/// and any system-level keyboard mapping overrides that are in effect.
162+
Character(String),
163+
Named(NamedKey),
164+
}
165+
166+
/// Parse from string error, returned when string does not match to any Key variant.
167+
#[derive(Clone, Debug)]
168+
pub struct UnrecognizedKeyError;
169+
170+
impl fmt::Display for Key {
171+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172+
match self {
173+
Self::Character(s) => f.write_str(s),
174+
Self::Named(k) => k.fmt(f),
175+
}
176+
}
177+
}
178+
179+
impl FromStr for Key {
180+
type Err = UnrecognizedKeyError;
181+
182+
fn from_str(s: &str) -> Result<Self, Self::Err> {
183+
if is_key_string(s) {
184+
Ok(Self::Character(s.to_string()))
185+
} else {
186+
Ok(Self::Named(
187+
NamedKey::from_str(s).map_err(|_| UnrecognizedKeyError)?,
188+
))
189+
}
190+
}
191+
}
192+
152193
impl Key {
153194
/// Determine a *charCode* value for a key with a character value.
154195
///
@@ -161,7 +202,7 @@ impl Key {
161202
// otherwise 0
162203
match self {
163204
Key::Character(ref c) => c.chars().next().unwrap_or('\0') as u32,
164-
_ => 0,
205+
Key::Named(_) => 0,
165206
}
166207
}
167208

@@ -173,23 +214,23 @@ impl Key {
173214
pub fn legacy_keycode(&self) -> u32 {
174215
match self {
175216
// See: https://w3c.github.io/uievents/#fixed-virtual-key-codes
176-
Key::Backspace => 8,
177-
Key::Tab => 9,
178-
Key::Enter => 13,
179-
Key::Shift => 16,
180-
Key::Control => 17,
181-
Key::Alt => 18,
182-
Key::CapsLock => 20,
183-
Key::Escape => 27,
184-
Key::PageUp => 33,
185-
Key::PageDown => 34,
186-
Key::End => 35,
187-
Key::Home => 36,
188-
Key::ArrowLeft => 37,
189-
Key::ArrowUp => 38,
190-
Key::ArrowRight => 39,
191-
Key::ArrowDown => 40,
192-
Key::Delete => 46,
217+
Key::Named(NamedKey::Backspace) => 8,
218+
Key::Named(NamedKey::Tab) => 9,
219+
Key::Named(NamedKey::Enter) => 13,
220+
Key::Named(NamedKey::Shift) => 16,
221+
Key::Named(NamedKey::Control) => 17,
222+
Key::Named(NamedKey::Alt) => 18,
223+
Key::Named(NamedKey::CapsLock) => 20,
224+
Key::Named(NamedKey::Escape) => 27,
225+
Key::Named(NamedKey::PageUp) => 33,
226+
Key::Named(NamedKey::PageDown) => 34,
227+
Key::Named(NamedKey::End) => 35,
228+
Key::Named(NamedKey::Home) => 36,
229+
Key::Named(NamedKey::ArrowLeft) => 37,
230+
Key::Named(NamedKey::ArrowUp) => 38,
231+
Key::Named(NamedKey::ArrowRight) => 39,
232+
Key::Named(NamedKey::ArrowDown) => 40,
233+
Key::Named(NamedKey::Delete) => 46,
193234
Key::Character(ref c) if c.len() == 1 => match first_char(c) {
194235
' ' => 32,
195236
x @ '0'..='9' => x as u32,
@@ -221,8 +262,14 @@ impl Default for KeyState {
221262
}
222263

223264
impl Default for Key {
224-
fn default() -> Key {
225-
Key::Unidentified
265+
fn default() -> Self {
266+
Self::Named(NamedKey::default())
267+
}
268+
}
269+
270+
impl Default for NamedKey {
271+
fn default() -> Self {
272+
Self::Unidentified
226273
}
227274
}
228275

@@ -245,3 +292,23 @@ impl Default for Location {
245292
fn first_char(s: &str) -> char {
246293
s.chars().next().expect("empty string")
247294
}
295+
296+
/// Check if string can be used as a `Key::Character` _keystring_.
297+
///
298+
/// This check is simple and is meant to prevents common mistakes like mistyped keynames
299+
/// (e.g. `Ennter`) from being recognized as characters.
300+
fn is_key_string(s: &str) -> bool {
301+
s.chars().all(|c| !c.is_control()) && s.chars().skip(1).all(|c| !c.is_ascii())
302+
}
303+
304+
#[cfg(test)]
305+
mod test {
306+
use super::*;
307+
308+
#[test]
309+
fn test_is_key_string() {
310+
assert!(is_key_string("A"));
311+
assert!(!is_key_string("AA"));
312+
assert!(!is_key_string(" "));
313+
}
314+
}

0 commit comments

Comments
 (0)