1use std::collections::HashSet;
10use std::hash::{BuildHasherDefault, DefaultHasher};
11
12use crate::{OH_NativeXComponent_KeyAction, OH_NativeXComponent_KeyCode};
13use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers, NamedKey};
14
15impl From<OH_NativeXComponent_KeyCode> for Code {
16 fn from(code: OH_NativeXComponent_KeyCode) -> Self {
17 use OH_NativeXComponent_KeyCode as OH_KeyCode;
18 match code {
19 OH_KeyCode::KEY_GRAVE => Code::Backquote,
20 OH_KeyCode::KEY_BACKSLASH => Code::Backslash,
21 OH_KeyCode::KEY_LEFT_BRACKET => Code::BracketLeft,
22 OH_KeyCode::KEY_RIGHT_BRACKET => Code::BracketRight,
23 OH_KeyCode::KEY_COMMA => Code::Comma,
24 OH_KeyCode::KEY_0 => Code::Digit0,
25 OH_KeyCode::KEY_1 => Code::Digit1,
26 OH_KeyCode::KEY_2 => Code::Digit2,
27 OH_KeyCode::KEY_3 => Code::Digit3,
28 OH_KeyCode::KEY_4 => Code::Digit4,
29 OH_KeyCode::KEY_5 => Code::Digit5,
30 OH_KeyCode::KEY_6 => Code::Digit6,
31 OH_KeyCode::KEY_7 => Code::Digit7,
32 OH_KeyCode::KEY_8 => Code::Digit8,
33 OH_KeyCode::KEY_9 => Code::Digit9,
34
35 OH_KeyCode::KEY_EQUALS => Code::Equal,
36 OH_KeyCode::KEY_RO => Code::IntlRo,
37 OH_KeyCode::KEY_YEN => Code::IntlYen,
38
39 OH_KeyCode::KEY_A => Code::KeyA,
40 OH_KeyCode::KEY_B => Code::KeyB,
41 OH_KeyCode::KEY_C => Code::KeyC,
42 OH_KeyCode::KEY_D => Code::KeyD,
43 OH_KeyCode::KEY_E => Code::KeyE,
44 OH_KeyCode::KEY_F => Code::KeyF,
45 OH_KeyCode::KEY_G => Code::KeyG,
46 OH_KeyCode::KEY_H => Code::KeyH,
47 OH_KeyCode::KEY_I => Code::KeyI,
48 OH_KeyCode::KEY_J => Code::KeyJ,
49 OH_KeyCode::KEY_K => Code::KeyK,
50 OH_KeyCode::KEY_L => Code::KeyL,
51 OH_KeyCode::KEY_M => Code::KeyM,
52 OH_KeyCode::KEY_N => Code::KeyN,
53 OH_KeyCode::KEY_O => Code::KeyO,
54 OH_KeyCode::KEY_P => Code::KeyP,
55 OH_KeyCode::KEY_Q => Code::KeyQ,
56 OH_KeyCode::KEY_R => Code::KeyR,
57 OH_KeyCode::KEY_S => Code::KeyS,
58 OH_KeyCode::KEY_T => Code::KeyT,
59 OH_KeyCode::KEY_U => Code::KeyU,
60 OH_KeyCode::KEY_V => Code::KeyV,
61 OH_KeyCode::KEY_W => Code::KeyW,
62 OH_KeyCode::KEY_X => Code::KeyX,
63 OH_KeyCode::KEY_Y => Code::KeyY,
64 OH_KeyCode::KEY_Z => Code::KeyZ,
65
66 OH_KeyCode::KEY_MINUS => Code::Minus,
67 OH_KeyCode::KEY_PERIOD => Code::Period,
68 OH_KeyCode::KEY_APOSTROPHE => Code::Quote,
69 OH_KeyCode::KEY_SEMICOLON => Code::Semicolon,
70 OH_KeyCode::KEY_SLASH => Code::Slash,
71 OH_KeyCode::KEY_ALT_LEFT => Code::AltLeft,
72 OH_KeyCode::KEY_ALT_RIGHT => Code::AltRight,
73 OH_KeyCode::KEY_DEL => Code::Backspace,
74 OH_KeyCode::KEY_CAPS_LOCK => Code::CapsLock,
75 OH_KeyCode::KEY_MENU => Code::ContextMenu,
76 OH_KeyCode::KEY_CTRL_LEFT => Code::ControlLeft,
77 OH_KeyCode::KEY_CTRL_RIGHT => Code::ControlRight,
78 OH_KeyCode::KEY_ENTER => Code::Enter,
79 OH_KeyCode::KEY_META_LEFT => Code::MetaLeft,
80 OH_KeyCode::KEY_META_RIGHT => Code::MetaRight,
81 OH_KeyCode::KEY_SHIFT_LEFT => Code::ShiftLeft,
82 OH_KeyCode::KEY_SHIFT_RIGHT => Code::ShiftRight,
83 OH_KeyCode::KEY_SPACE => Code::Space,
84 OH_KeyCode::KEY_TAB => Code::Tab,
85 OH_KeyCode::KEY_FORWARD_DEL => Code::Delete,
89 OH_KeyCode::KEY_MOVE_END => Code::End,
90 OH_KeyCode::KEY_HELP => Code::Help,
91 OH_KeyCode::KEY_HOME => Code::Home,
92 OH_KeyCode::KEY_MOVE_HOME => Code::Home,
93 OH_KeyCode::KEY_INSERT => Code::Insert,
94 OH_KeyCode::KEY_PAGE_DOWN => Code::PageDown,
95 OH_KeyCode::KEY_PAGE_UP => Code::PageUp,
96 OH_KeyCode::KEY_DPAD_DOWN => Code::ArrowDown,
97 OH_KeyCode::KEY_DPAD_UP => Code::ArrowUp,
98 OH_KeyCode::KEY_DPAD_LEFT => Code::ArrowLeft,
99 OH_KeyCode::KEY_DPAD_RIGHT => Code::ArrowRight,
100
101 OH_KeyCode::KEY_NUM_LOCK => Code::NumLock,
102 OH_KeyCode::KEY_NUMPAD_0 => Code::Numpad0,
103 OH_KeyCode::KEY_NUMPAD_1 => Code::Numpad1,
104 OH_KeyCode::KEY_NUMPAD_2 => Code::Numpad2,
105 OH_KeyCode::KEY_NUMPAD_3 => Code::Numpad3,
106 OH_KeyCode::KEY_NUMPAD_4 => Code::Numpad4,
107 OH_KeyCode::KEY_NUMPAD_5 => Code::Numpad5,
108 OH_KeyCode::KEY_NUMPAD_6 => Code::Numpad6,
109 OH_KeyCode::KEY_NUMPAD_7 => Code::Numpad7,
110 OH_KeyCode::KEY_NUMPAD_8 => Code::Numpad8,
111 OH_KeyCode::KEY_NUMPAD_9 => Code::Numpad9,
112 OH_KeyCode::KEY_NUMPAD_ADD => Code::NumpadAdd,
113 OH_KeyCode::KEY_NUMPAD_COMMA => Code::NumpadComma,
114 OH_KeyCode::KEY_NUMPAD_DIVIDE => Code::NumpadDivide,
115 OH_KeyCode::KEY_NUMPAD_DOT => Code::NumpadDecimal,
116 OH_KeyCode::KEY_NUMPAD_ENTER => Code::NumpadEnter,
117 OH_KeyCode::KEY_NUMPAD_EQUALS => Code::NumpadEqual,
118 OH_KeyCode::KEY_NUMPAD_LEFT_PAREN => Code::NumpadParenLeft,
119 OH_KeyCode::KEY_NUMPAD_RIGHT_PAREN => Code::NumpadParenRight,
120 OH_KeyCode::KEY_NUMPAD_MULTIPLY => Code::NumpadMultiply,
121 OH_KeyCode::KEY_NUMPAD_SUBTRACT => Code::NumpadSubtract,
123
124 OH_KeyCode::KEY_ESCAPE => Code::Escape,
125 OH_KeyCode::KEY_FN => Code::Fn,
126 OH_KeyCode::KEY_SYSRQ => Code::PrintScreen,
128 OH_KeyCode::KEY_PRINT => Code::PrintScreen,
129 OH_KeyCode::KEY_SCROLL_LOCK => Code::ScrollLock,
130 OH_KeyCode::KEY_BREAK => Code::Pause,
131 OH_KeyCode::KEY_FORWARD => Code::BrowserForward,
132 OH_KeyCode::KEY_MEDIA_EJECT => Code::Eject,
134 OH_KeyCode::KEY_ENVELOPE => Code::LaunchMail,
135 OH_KeyCode::KEY_MEDIA_PLAY_PAUSE => Code::MediaPlayPause,
137 OH_KeyCode::KEY_PLAYPAUSE => Code::MediaPlayPause,
138 OH_KeyCode::KEY_MEDIA_PAUSE => Code::MediaPause,
139 OH_KeyCode::KEY_MEDIA_PLAY => Code::MediaPlay,
140 OH_KeyCode::KEY_MEDIA_NEXT => Code::MediaTrackNext,
141 OH_KeyCode::KEY_MEDIA_PREVIOUS => Code::MediaTrackPrevious,
142 OH_KeyCode::KEY_MEDIA_STOP => Code::MediaStop,
143 OH_KeyCode::KEY_MEDIA_RECORD => Code::MediaRecord,
144 OH_KeyCode::KEY_MEDIA_REWIND => Code::MediaRewind,
145 OH_KeyCode::KEY_MEDIA_FAST_FORWARD => Code::MediaFastForward,
146
147 OH_KeyCode::KEY_POWER => Code::Power,
148 OH_KeyCode::KEY_SLEEP => Code::Sleep,
149
150 OH_KeyCode::KEY_VOLUME_DOWN => Code::AudioVolumeDown,
151 OH_KeyCode::KEY_VOLUME_UP => Code::AudioVolumeUp,
152 OH_KeyCode::KEY_VOLUME_MUTE => Code::AudioVolumeMute,
153
154 OH_KeyCode::KEY_WAKEUP => Code::WakeUp,
155 OH_KeyCode::KEY_SUSPEND => Code::Suspend,
157 OH_KeyCode::KEY_AGAIN => Code::Again,
158 OH_KeyCode::KEY_COPY => Code::Copy,
159 OH_KeyCode::KEY_CUT => Code::Cut,
160 OH_KeyCode::KEY_FIND => Code::Find,
161 OH_KeyCode::KEY_OPEN => Code::Open,
162 OH_KeyCode::KEY_PASTE => Code::Paste,
163 OH_KeyCode::KEY_PROPS => Code::Props,
164 OH_KeyCode::KEY_UNDO => Code::Undo,
166 OH_KeyCode::KEY_HIRAGANA => Code::Hiragana,
167 OH_KeyCode::KEY_KATAKANA => Code::Katakana,
168 OH_KeyCode::KEY_F1 => Code::F1,
169 OH_KeyCode::KEY_F2 => Code::F2,
170 OH_KeyCode::KEY_F3 => Code::F3,
171 OH_KeyCode::KEY_F4 => Code::F4,
172 OH_KeyCode::KEY_F5 => Code::F5,
173 OH_KeyCode::KEY_F6 => Code::F6,
174 OH_KeyCode::KEY_F7 => Code::F7,
175 OH_KeyCode::KEY_F8 => Code::F8,
176 OH_KeyCode::KEY_F9 => Code::F9,
177 OH_KeyCode::KEY_F10 => Code::F10,
178 OH_KeyCode::KEY_F11 => Code::F11,
179 OH_KeyCode::KEY_F12 => Code::F12,
180 OH_KeyCode::KEY_F13 => Code::F13,
181 OH_KeyCode::KEY_F14 => Code::F14,
182 OH_KeyCode::KEY_F15 => Code::F15,
183 OH_KeyCode::KEY_F16 => Code::F16,
184 OH_KeyCode::KEY_F17 => Code::F17,
185 OH_KeyCode::KEY_F18 => Code::F18,
186 OH_KeyCode::KEY_F19 => Code::F19,
187 OH_KeyCode::KEY_F20 => Code::F20,
188 OH_KeyCode::KEY_F21 => Code::F21,
189 OH_KeyCode::KEY_F22 => Code::F22,
190 OH_KeyCode::KEY_F23 => Code::F23,
191 OH_KeyCode::KEY_F24 => Code::F24,
192 OH_KeyCode::KEY_BRIGHTNESS_DOWN => Code::BrightnessDown,
193 OH_KeyCode::KEY_BRIGHTNESS_UP => Code::BrightnessUp,
194 OH_KeyCode::KEY_MUTE => Code::MicrophoneMuteToggle,
197 OH_KeyCode::KEY_APPSELECT => Code::SelectTask,
198 OH_KeyCode::KEY_CYCLEWINDOWS => Code::ShowAllWindows,
200 OH_KeyCode::KEY_UNKNOWN => Code::Unidentified,
202 _ => Code::Unidentified,
203 }
204 }
205}
206
207pub struct UnknownKeyState {}
208
209impl TryFrom<OH_NativeXComponent_KeyAction> for KeyState {
210 type Error = UnknownKeyState;
211
212 fn try_from(value: OH_NativeXComponent_KeyAction) -> Result<Self, Self::Error> {
213 use OH_NativeXComponent_KeyAction as KeyAction;
214 match value {
215 KeyAction::OH_NATIVEXCOMPONENT_KEY_ACTION_UP => Ok(KeyState::Up),
216 KeyAction::OH_NATIVEXCOMPONENT_KEY_ACTION_DOWN => Ok(KeyState::Down),
217 _ => Err(UnknownKeyState {}),
218 }
219 }
220}
221
222pub fn named_key(code: OH_NativeXComponent_KeyCode) -> Option<NamedKey> {
228 use OH_NativeXComponent_KeyCode as OH_KeyCode;
229 let key = match code {
230 OH_KeyCode::KEY_FN | OH_KeyCode::KEY_FUNCTION => NamedKey::Fn,
231 OH_KeyCode::KEY_HOME => NamedKey::GoHome,
232 OH_KeyCode::KEY_BACK => NamedKey::GoBack,
233 OH_KeyCode::KEY_MEDIA_PLAY_PAUSE | OH_KeyCode::KEY_PLAYPAUSE => NamedKey::MediaPlayPause,
234 OH_KeyCode::KEY_MEDIA_STOP => NamedKey::MediaStop,
235 OH_KeyCode::KEY_MEDIA_NEXT => NamedKey::MediaTrackNext,
236 OH_KeyCode::KEY_MEDIA_PREVIOUS => NamedKey::MediaTrackPrevious,
237 OH_KeyCode::KEY_MEDIA_REWIND => NamedKey::MediaRewind,
238 OH_KeyCode::KEY_MEDIA_FAST_FORWARD => NamedKey::MediaFastForward,
239 OH_KeyCode::KEY_VOLUME_UP => NamedKey::AudioVolumeUp,
240 OH_KeyCode::KEY_VOLUME_DOWN => NamedKey::AudioVolumeDown,
241 OH_KeyCode::KEY_POWER => NamedKey::Power,
242 OH_KeyCode::KEY_CAMERA => NamedKey::Camera,
243 OH_KeyCode::KEY_VOLUME_MUTE => NamedKey::AudioVolumeMute,
244 OH_KeyCode::KEY_MUTE => NamedKey::MicrophoneVolumeMute,
245 OH_KeyCode::KEY_BRIGHTNESS_UP => NamedKey::BrightnessUp,
246 OH_KeyCode::KEY_BRIGHTNESS_DOWN => NamedKey::BrightnessDown,
247 OH_KeyCode::KEY_DPAD_UP => NamedKey::ArrowUp,
248 OH_KeyCode::KEY_DPAD_DOWN => NamedKey::ArrowDown,
249 OH_KeyCode::KEY_DPAD_LEFT => NamedKey::ArrowLeft,
250 OH_KeyCode::KEY_DPAD_RIGHT => NamedKey::ArrowRight,
251 OH_KeyCode::KEY_DPAD_CENTER => NamedKey::Select,
252 OH_KeyCode::KEY_ALT_LEFT | OH_KeyCode::KEY_ALT_RIGHT => NamedKey::Alt,
253 OH_KeyCode::KEY_SHIFT_LEFT | OH_KeyCode::KEY_SHIFT_RIGHT => NamedKey::Shift,
254 OH_KeyCode::KEY_TAB => NamedKey::Tab,
255 OH_KeyCode::KEY_SYM => NamedKey::Symbol,
256 OH_KeyCode::KEY_EXPLORER => NamedKey::LaunchWebBrowser,
257 OH_KeyCode::KEY_ENVELOPE => NamedKey::LaunchMail,
258 OH_KeyCode::KEY_ENTER | OH_KeyCode::KEY_NUMPAD_ENTER => NamedKey::Enter,
259 OH_KeyCode::KEY_DEL => NamedKey::Backspace,
260 OH_KeyCode::KEY_MENU => NamedKey::ContextMenu,
261 OH_KeyCode::KEY_PAGE_UP => NamedKey::PageUp,
262 OH_KeyCode::KEY_PAGE_DOWN => NamedKey::PageDown,
263 OH_KeyCode::KEY_ESCAPE => NamedKey::Escape,
264 OH_KeyCode::KEY_FORWARD_DEL => NamedKey::Delete,
265 OH_KeyCode::KEY_CTRL_LEFT | OH_KeyCode::KEY_CTRL_RIGHT => NamedKey::Control,
266 OH_KeyCode::KEY_CAPS_LOCK => NamedKey::CapsLock,
267 OH_KeyCode::KEY_SCROLL_LOCK => NamedKey::ScrollLock,
268 OH_KeyCode::KEY_META_LEFT | OH_KeyCode::KEY_META_RIGHT => NamedKey::Meta,
269 OH_KeyCode::KEY_SYSRQ | OH_KeyCode::KEY_PRINT => NamedKey::PrintScreen,
270 OH_KeyCode::KEY_BREAK => NamedKey::Pause,
271 OH_KeyCode::KEY_MOVE_HOME => NamedKey::Home,
272 OH_KeyCode::KEY_MOVE_END => NamedKey::End,
273 OH_KeyCode::KEY_INSERT => NamedKey::Insert,
274 OH_KeyCode::KEY_FORWARD => NamedKey::BrowserForward,
275 OH_KeyCode::KEY_MEDIA_PLAY => NamedKey::MediaPlay,
276 OH_KeyCode::KEY_MEDIA_PAUSE => NamedKey::MediaPause,
277 OH_KeyCode::KEY_MEDIA_CLOSE => NamedKey::MediaClose,
278 OH_KeyCode::KEY_MEDIA_EJECT => NamedKey::Eject,
279 OH_KeyCode::KEY_MEDIA_RECORD => NamedKey::MediaRecord,
280 OH_KeyCode::KEY_F1 => NamedKey::F1,
281 OH_KeyCode::KEY_F2 => NamedKey::F2,
282 OH_KeyCode::KEY_F3 => NamedKey::F3,
283 OH_KeyCode::KEY_F4 => NamedKey::F4,
284 OH_KeyCode::KEY_F5 => NamedKey::F5,
285 OH_KeyCode::KEY_F6 => NamedKey::F6,
286 OH_KeyCode::KEY_F7 => NamedKey::F7,
287 OH_KeyCode::KEY_F8 => NamedKey::F8,
288 OH_KeyCode::KEY_F9 => NamedKey::F9,
289 OH_KeyCode::KEY_F10 => NamedKey::F10,
290 OH_KeyCode::KEY_F11 => NamedKey::F11,
291 OH_KeyCode::KEY_F12 => NamedKey::F12,
292 OH_KeyCode::KEY_F13 => NamedKey::F13,
293 OH_KeyCode::KEY_F14 => NamedKey::F14,
294 OH_KeyCode::KEY_F15 => NamedKey::F15,
295 OH_KeyCode::KEY_F16 => NamedKey::F16,
296 OH_KeyCode::KEY_F17 => NamedKey::F17,
297 OH_KeyCode::KEY_F18 => NamedKey::F18,
298 OH_KeyCode::KEY_F19 => NamedKey::F19,
299 OH_KeyCode::KEY_F20 => NamedKey::F20,
300 OH_KeyCode::KEY_F21 => NamedKey::F21,
301 OH_KeyCode::KEY_F22 => NamedKey::F22,
302 OH_KeyCode::KEY_F23 => NamedKey::F23,
303 OH_KeyCode::KEY_F24 => NamedKey::F24,
304 OH_KeyCode::KEY_NUM_LOCK => NamedKey::NumLock,
305 OH_KeyCode::KEY_SLEEP => NamedKey::Standby,
306 OH_KeyCode::KEY_WAKEUP => NamedKey::WakeUp,
307 OH_KeyCode::KEY_HELP => NamedKey::Help,
308 OH_KeyCode::KEY_AGAIN => NamedKey::Again,
309 OH_KeyCode::KEY_PROPS => NamedKey::Props,
310 OH_KeyCode::KEY_UNDO => NamedKey::Undo,
311 OH_KeyCode::KEY_COPY => NamedKey::Copy,
312 OH_KeyCode::KEY_OPEN => NamedKey::Open,
313 OH_KeyCode::KEY_PASTE => NamedKey::Paste,
314 OH_KeyCode::KEY_FIND => NamedKey::Find,
315 OH_KeyCode::KEY_CUT => NamedKey::Cut,
316 OH_KeyCode::KEY_HIRAGANA => NamedKey::Hiragana,
317 OH_KeyCode::KEY_KATAKANA => NamedKey::Katakana,
318 OH_KeyCode::KEY_APPSELECT => NamedKey::AppSwitch,
319 _ => return None,
320 };
321 Some(key)
322}
323
324fn numpad_nav_key(code: Code) -> Option<NamedKey> {
326 let key = match code {
327 Code::Numpad0 => NamedKey::Insert,
328 Code::Numpad1 => NamedKey::End,
329 Code::Numpad2 => NamedKey::ArrowDown,
330 Code::Numpad3 => NamedKey::PageDown,
331 Code::Numpad4 => NamedKey::ArrowLeft,
332 Code::Numpad5 => NamedKey::Clear,
333 Code::Numpad6 => NamedKey::ArrowRight,
334 Code::Numpad7 => NamedKey::Home,
335 Code::Numpad8 => NamedKey::ArrowUp,
336 Code::Numpad9 => NamedKey::PageUp,
337 Code::NumpadDecimal => NamedKey::Delete,
338 _ => return None,
339 };
340 Some(key)
341}
342
343pub fn location(code: OH_NativeXComponent_KeyCode) -> Location {
346 use OH_NativeXComponent_KeyCode as OH_KeyCode;
347 match code {
348 OH_KeyCode::KEY_ALT_LEFT
349 | OH_KeyCode::KEY_SHIFT_LEFT
350 | OH_KeyCode::KEY_CTRL_LEFT
351 | OH_KeyCode::KEY_META_LEFT => Location::Left,
352 OH_KeyCode::KEY_ALT_RIGHT
353 | OH_KeyCode::KEY_SHIFT_RIGHT
354 | OH_KeyCode::KEY_CTRL_RIGHT
355 | OH_KeyCode::KEY_META_RIGHT => Location::Right,
356 OH_KeyCode::KEY_NUMPAD_PLUSMINUS => Location::Numpad,
357 code if (OH_KeyCode::KEY_NUMPAD_0.0..=OH_KeyCode::KEY_NUMPAD_RIGHT_PAREN.0)
358 .contains(&code.0) =>
359 {
360 Location::Numpad
361 }
362 _ => Location::Standard,
363 }
364}
365
366fn us_char_pair(code: Code) -> Option<(char, char)> {
376 let pair = match code {
377 Code::Digit0 => ('0', ')'),
378 Code::Digit1 => ('1', '!'),
379 Code::Digit2 => ('2', '@'),
380 Code::Digit3 => ('3', '#'),
381 Code::Digit4 => ('4', '$'),
382 Code::Digit5 => ('5', '%'),
383 Code::Digit6 => ('6', '^'),
384 Code::Digit7 => ('7', '&'),
385 Code::Digit8 => ('8', '*'),
386 Code::Digit9 => ('9', '('),
387 Code::KeyA => ('a', 'A'),
388 Code::KeyB => ('b', 'B'),
389 Code::KeyC => ('c', 'C'),
390 Code::KeyD => ('d', 'D'),
391 Code::KeyE => ('e', 'E'),
392 Code::KeyF => ('f', 'F'),
393 Code::KeyG => ('g', 'G'),
394 Code::KeyH => ('h', 'H'),
395 Code::KeyI => ('i', 'I'),
396 Code::KeyJ => ('j', 'J'),
397 Code::KeyK => ('k', 'K'),
398 Code::KeyL => ('l', 'L'),
399 Code::KeyM => ('m', 'M'),
400 Code::KeyN => ('n', 'N'),
401 Code::KeyO => ('o', 'O'),
402 Code::KeyP => ('p', 'P'),
403 Code::KeyQ => ('q', 'Q'),
404 Code::KeyR => ('r', 'R'),
405 Code::KeyS => ('s', 'S'),
406 Code::KeyT => ('t', 'T'),
407 Code::KeyU => ('u', 'U'),
408 Code::KeyV => ('v', 'V'),
409 Code::KeyW => ('w', 'W'),
410 Code::KeyX => ('x', 'X'),
411 Code::KeyY => ('y', 'Y'),
412 Code::KeyZ => ('z', 'Z'),
413 Code::Comma => (',', '<'),
414 Code::Period => ('.', '>'),
415 Code::Backquote => ('`', '~'),
416 Code::Minus => ('-', '_'),
417 Code::Equal => ('=', '+'),
418 Code::BracketLeft => ('[', '{'),
419 Code::BracketRight => (']', '}'),
420 Code::Backslash => ('\\', '|'),
421 Code::Semicolon => (';', ':'),
422 Code::Quote => ('\'', '"'),
423 Code::Slash => ('/', '?'),
424 Code::Space => (' ', ' '),
425 Code::Numpad0 => ('0', '0'),
426 Code::Numpad1 => ('1', '1'),
427 Code::Numpad2 => ('2', '2'),
428 Code::Numpad3 => ('3', '3'),
429 Code::Numpad4 => ('4', '4'),
430 Code::Numpad5 => ('5', '5'),
431 Code::Numpad6 => ('6', '6'),
432 Code::Numpad7 => ('7', '7'),
433 Code::Numpad8 => ('8', '8'),
434 Code::Numpad9 => ('9', '9'),
435 Code::NumpadDivide => ('/', '/'),
436 Code::NumpadMultiply => ('*', '*'),
437 Code::NumpadSubtract => ('-', '-'),
438 Code::NumpadAdd => ('+', '+'),
439 Code::NumpadDecimal => ('.', '.'),
440 _ => return None,
441 };
442 Some(pair)
443}
444
445fn is_letter(code: Code) -> bool {
446 matches!(
447 code,
448 Code::KeyA
449 | Code::KeyB
450 | Code::KeyC
451 | Code::KeyD
452 | Code::KeyE
453 | Code::KeyF
454 | Code::KeyG
455 | Code::KeyH
456 | Code::KeyI
457 | Code::KeyJ
458 | Code::KeyK
459 | Code::KeyL
460 | Code::KeyM
461 | Code::KeyN
462 | Code::KeyO
463 | Code::KeyP
464 | Code::KeyQ
465 | Code::KeyR
466 | Code::KeyS
467 | Code::KeyT
468 | Code::KeyU
469 | Code::KeyV
470 | Code::KeyW
471 | Code::KeyX
472 | Code::KeyY
473 | Code::KeyZ
474 )
475}
476
477fn is_numpad_digit_or_decimal(code: Code) -> bool {
478 matches!(
479 code,
480 Code::Numpad0
481 | Code::Numpad1
482 | Code::Numpad2
483 | Code::Numpad3
484 | Code::Numpad4
485 | Code::Numpad5
486 | Code::Numpad6
487 | Code::Numpad7
488 | Code::Numpad8
489 | Code::Numpad9
490 | Code::NumpadDecimal
491 )
492}
493
494fn is_numpad_operator(code: Code) -> bool {
495 matches!(
496 code,
497 Code::NumpadDivide | Code::NumpadMultiply | Code::NumpadSubtract | Code::NumpadAdd
498 )
499}
500
501pub fn us_char(code: Code, shift: bool, caps_lock: bool, num_lock: bool) -> Option<char> {
513 let (unshifted, shifted) = us_char_pair(code)?;
514 if is_numpad_digit_or_decimal(code) {
515 return num_lock.then_some(unshifted);
516 }
517 if is_numpad_operator(code) {
518 return Some(unshifted);
519 }
520 let use_shifted = if is_letter(code) {
521 shift != caps_lock
522 } else {
523 shift
524 };
525 Some(if use_shifted { shifted } else { unshifted })
526}
527
528#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
530pub struct ModifierState {
531 pub shift: bool,
532 pub ctrl: bool,
533 pub alt: bool,
534 pub meta: Option<bool>,
538 pub caps_lock: bool,
539 pub num_lock: bool,
540 pub scroll_lock: bool,
541}
542
543#[derive(Clone, Debug, Default)]
577pub struct KeyEventConverter {
578 pressed: HashSet<OH_NativeXComponent_KeyCode, BuildHasherDefault<DefaultHasher>>,
579 meta_left: bool,
580 meta_right: bool,
581}
582
583impl KeyEventConverter {
584 pub const fn new() -> Self {
585 Self {
586 pressed: HashSet::with_hasher(BuildHasherDefault::new()),
587 meta_left: false,
588 meta_right: false,
589 }
590 }
591
592 pub fn clear(&mut self) {
594 self.pressed.clear();
595 self.meta_left = false;
596 self.meta_right = false;
597 }
598
599 pub fn convert(
600 &mut self,
601 action: OH_NativeXComponent_KeyAction,
602 key_code: OH_NativeXComponent_KeyCode,
603 modifiers: ModifierState,
604 ) -> Option<KeyboardEvent> {
605 use OH_NativeXComponent_KeyCode as OH_KeyCode;
606 let state = KeyState::try_from(action).ok()?;
607 let down = state == KeyState::Down;
608 if key_code == OH_KeyCode::KEY_META_LEFT {
609 self.meta_left = down;
610 } else if key_code == OH_KeyCode::KEY_META_RIGHT {
611 self.meta_right = down;
612 }
613 let repeat = if down {
614 !self.pressed.insert(key_code)
615 } else {
616 self.pressed.remove(&key_code);
617 false
618 };
619
620 let meta = modifiers.meta.unwrap_or(self.meta_left || self.meta_right);
621 let mut flags = Modifiers::empty();
622 flags.set(Modifiers::SHIFT, modifiers.shift);
623 flags.set(Modifiers::CONTROL, modifiers.ctrl);
624 flags.set(Modifiers::ALT, modifiers.alt);
625 flags.set(Modifiers::META, meta);
626 flags.set(Modifiers::CAPS_LOCK, modifiers.caps_lock);
627 flags.set(Modifiers::NUM_LOCK, modifiers.num_lock);
628 flags.set(Modifiers::SCROLL_LOCK, modifiers.scroll_lock);
629
630 let code = Code::from(key_code);
631 let key = match us_char(
632 code,
633 modifiers.shift,
634 modifiers.caps_lock,
635 modifiers.num_lock,
636 ) {
637 Some(character) => Key::Character(character.to_string()),
638 None => Key::Named(
639 numpad_nav_key(code)
640 .or_else(|| named_key(key_code))
641 .unwrap_or(NamedKey::Unidentified),
642 ),
643 };
644
645 Some(KeyboardEvent {
646 state,
647 key,
648 code,
649 location: location(key_code),
650 modifiers: flags,
651 repeat,
652 is_composing: false,
653 })
654 }
655}