dioxus_html/events/keyboard.rs
1use dioxus_core::Event;
2use keyboard_types::{Code, Key, Location, Modifiers};
3use std::fmt::Debug;
4
5use crate::ModifiersInteraction;
6
7#[cfg(feature = "serialize")]
8fn resilient_deserialize_code<'de, D>(deserializer: D) -> Result<Code, D::Error>
9where
10 D: serde::Deserializer<'de>,
11{
12 use serde::Deserialize;
13 // If we fail to deserialize the code for any reason, just return Unidentified instead of failing.
14 Ok(Code::deserialize(deserializer).unwrap_or(Code::Unidentified))
15}
16
17pub type KeyboardEvent = Event<KeyboardData>;
18pub struct KeyboardData {
19 inner: Box<dyn HasKeyboardData>,
20}
21
22impl<E: HasKeyboardData> From<E> for KeyboardData {
23 fn from(e: E) -> Self {
24 Self { inner: Box::new(e) }
25 }
26}
27
28impl std::fmt::Debug for KeyboardData {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("KeyboardData")
31 .field("key", &self.key())
32 .field("code", &self.code())
33 .field("modifiers", &self.modifiers())
34 .field("location", &self.location())
35 .field("is_auto_repeating", &self.is_auto_repeating())
36 .field("is_composing", &self.is_composing())
37 .finish()
38 }
39}
40
41impl PartialEq for KeyboardData {
42 fn eq(&self, other: &Self) -> bool {
43 self.key() == other.key()
44 && self.code() == other.code()
45 && self.modifiers() == other.modifiers()
46 && self.location() == other.location()
47 && self.is_auto_repeating() == other.is_auto_repeating()
48 && self.is_composing() == other.is_composing()
49 }
50}
51
52impl KeyboardData {
53 /// Create a new KeyboardData
54 pub fn new(inner: impl HasKeyboardData + 'static) -> Self {
55 Self {
56 inner: Box::new(inner),
57 }
58 }
59
60 /// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout.
61 pub fn key(&self) -> Key {
62 self.inner.key()
63 }
64
65 /// A physical key on the keyboard (as opposed to the character generated by pressing the key). In other words, this property returns a value that isn't altered by keyboard layout or the state of the modifier keys.
66 pub fn code(&self) -> Code {
67 self.inner.code()
68 }
69
70 /// The location of the key on the keyboard or other input device.
71 pub fn location(&self) -> Location {
72 self.inner.location()
73 }
74
75 /// `true` iff the key is being held down such that it is automatically repeating.
76 pub fn is_auto_repeating(&self) -> bool {
77 self.inner.is_auto_repeating()
78 }
79
80 /// Indicates whether the key is fired within a composition session.
81 pub fn is_composing(&self) -> bool {
82 self.inner.is_composing()
83 }
84
85 /// Downcast this KeyboardData to a concrete type.
86 #[inline(always)]
87 pub fn downcast<T: 'static>(&self) -> Option<&T> {
88 self.inner.as_any().downcast_ref::<T>()
89 }
90}
91
92impl ModifiersInteraction for KeyboardData {
93 fn modifiers(&self) -> Modifiers {
94 self.inner.modifiers()
95 }
96}
97
98#[cfg(feature = "serialize")]
99/// A serialized version of KeyboardData
100#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
101pub struct SerializedKeyboardData {
102 char_code: u32,
103 is_composing: bool,
104 key: String,
105 key_code: KeyCode,
106 #[serde(deserialize_with = "resilient_deserialize_code")]
107 code: Code,
108 alt_key: bool,
109 ctrl_key: bool,
110 meta_key: bool,
111 shift_key: bool,
112 location: usize,
113 repeat: bool,
114 which: usize,
115}
116
117#[cfg(feature = "serialize")]
118impl SerializedKeyboardData {
119 /// Create a new SerializedKeyboardData
120 pub fn new(
121 key: Key,
122 code: Code,
123 location: Location,
124 is_auto_repeating: bool,
125 modifiers: Modifiers,
126 is_composing: bool,
127 ) -> Self {
128 Self {
129 char_code: key.legacy_charcode(),
130 is_composing,
131 key: key.to_string(),
132 key_code: KeyCode::from_raw_code(
133 std::convert::TryInto::try_into(key.legacy_keycode())
134 .expect("could not convert keycode to u8"),
135 ),
136 code,
137 alt_key: modifiers.contains(Modifiers::ALT),
138 ctrl_key: modifiers.contains(Modifiers::CONTROL),
139 meta_key: modifiers.contains(Modifiers::META),
140 shift_key: modifiers.contains(Modifiers::SHIFT),
141 location: crate::input_data::encode_key_location(location),
142 repeat: is_auto_repeating,
143 which: std::convert::TryInto::try_into(key.legacy_charcode())
144 .expect("could not convert charcode to usize"),
145 }
146 }
147}
148
149#[cfg(feature = "serialize")]
150impl From<&KeyboardData> for SerializedKeyboardData {
151 fn from(data: &KeyboardData) -> Self {
152 Self::new(
153 data.key(),
154 data.code(),
155 data.location(),
156 data.is_auto_repeating(),
157 data.modifiers(),
158 data.is_composing(),
159 )
160 }
161}
162
163#[cfg(feature = "serialize")]
164impl HasKeyboardData for SerializedKeyboardData {
165 fn key(&self) -> Key {
166 std::str::FromStr::from_str(&self.key)
167 .unwrap_or(Key::Named(keyboard_types::NamedKey::Unidentified))
168 }
169
170 fn code(&self) -> Code {
171 self.code
172 }
173
174 fn location(&self) -> Location {
175 crate::input_data::decode_key_location(self.location)
176 }
177
178 fn is_auto_repeating(&self) -> bool {
179 self.repeat
180 }
181
182 fn is_composing(&self) -> bool {
183 self.is_composing
184 }
185
186 fn as_any(&self) -> &dyn std::any::Any {
187 self
188 }
189}
190
191#[cfg(feature = "serialize")]
192impl ModifiersInteraction for SerializedKeyboardData {
193 fn modifiers(&self) -> Modifiers {
194 let mut modifiers = Modifiers::empty();
195
196 if self.alt_key {
197 modifiers.insert(Modifiers::ALT);
198 }
199 if self.ctrl_key {
200 modifiers.insert(Modifiers::CONTROL);
201 }
202 if self.meta_key {
203 modifiers.insert(Modifiers::META);
204 }
205 if self.shift_key {
206 modifiers.insert(Modifiers::SHIFT);
207 }
208
209 modifiers
210 }
211}
212
213#[cfg(feature = "serialize")]
214impl serde::Serialize for KeyboardData {
215 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
216 SerializedKeyboardData::from(self).serialize(serializer)
217 }
218}
219
220#[cfg(feature = "serialize")]
221impl<'de> serde::Deserialize<'de> for KeyboardData {
222 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
223 let data = SerializedKeyboardData::deserialize(deserializer)?;
224 Ok(Self {
225 inner: Box::new(data),
226 })
227 }
228}
229
230pub trait HasKeyboardData: ModifiersInteraction + std::any::Any {
231 /// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout.
232 fn key(&self) -> Key;
233
234 /// A physical key on the keyboard (as opposed to the character generated by pressing the key). In other words, this property returns a value that isn't altered by keyboard layout or the state of the modifier keys.
235 fn code(&self) -> Code;
236
237 /// The location of the key on the keyboard or other input device.
238 fn location(&self) -> Location;
239
240 /// `true` iff the key is being held down such that it is automatically repeating.
241 fn is_auto_repeating(&self) -> bool;
242
243 /// Indicates whether the key is fired within a composition session.
244 fn is_composing(&self) -> bool;
245
246 /// return self as Any
247 fn as_any(&self) -> &dyn std::any::Any;
248}
249
250#[cfg(feature = "serialize")]
251impl<'de> serde::Deserialize<'de> for KeyCode {
252 fn deserialize<D>(deserializer: D) -> Result<KeyCode, D::Error>
253 where
254 D: serde::Deserializer<'de>,
255 {
256 // We could be deserializing a unicode character, so we need to use u64 even if the output only takes u8
257 let value = u64::deserialize(deserializer)?;
258
259 if let Ok(smaller_uint) = value.try_into() {
260 Ok(KeyCode::from_raw_code(smaller_uint))
261 } else {
262 Ok(KeyCode::Unknown)
263 }
264 }
265}
266
267#[cfg_attr(feature = "serialize", derive(serde_repr::Serialize_repr))]
268#[derive(Clone, Copy, Debug, Eq, PartialEq)]
269#[repr(u8)]
270pub enum KeyCode {
271 // That key has no keycode, = 0
272 // break, = 3
273 // backspace / delete, = 8
274 // tab, = 9
275 // clear, = 12
276 // enter, = 13
277 // shift, = 16
278 // ctrl, = 17
279 // alt, = 18
280 // pause/break, = 19
281 // caps lock, = 20
282 // hangul, = 21
283 // hanja, = 25
284 // escape, = 27
285 // conversion, = 28
286 // non-conversion, = 29
287 // spacebar, = 32
288 // page up, = 33
289 // page down, = 34
290 // end, = 35
291 // home, = 36
292 // left arrow, = 37
293 // up arrow, = 38
294 // right arrow, = 39
295 // down arrow, = 40
296 // select, = 41
297 // print, = 42
298 // execute, = 43
299 // Print Screen, = 44
300 // insert, = 45
301 // delete, = 46
302 // help, = 47
303 // 0, = 48
304 // 1, = 49
305 // 2, = 50
306 // 3, = 51
307 // 4, = 52
308 // 5, = 53
309 // 6, = 54
310 // 7, = 55
311 // 8, = 56
312 // 9, = 57
313 // :, = 58
314 // semicolon (firefox), equals, = 59
315 // <, = 60
316 // equals (firefox), = 61
317 // ß, = 63
318 // @ (firefox), = 64
319 // a, = 65
320 // b, = 66
321 // c, = 67
322 // d, = 68
323 // e, = 69
324 // f, = 70
325 // g, = 71
326 // h, = 72
327 // i, = 73
328 // j, = 74
329 // k, = 75
330 // l, = 76
331 // m, = 77
332 // n, = 78
333 // o, = 79
334 // p, = 80
335 // q, = 81
336 // r, = 82
337 // s, = 83
338 // t, = 84
339 // u, = 85
340 // v, = 86
341 // w, = 87
342 // x, = 88
343 // y, = 89
344 // z, = 90
345 // Windows Key / Left ⌘ / Chromebook Search key, = 91
346 // right window key, = 92
347 // Windows Menu / Right ⌘, = 93
348 // sleep, = 95
349 // numpad 0, = 96
350 // numpad 1, = 97
351 // numpad 2, = 98
352 // numpad 3, = 99
353 // numpad 4, = 100
354 // numpad 5, = 101
355 // numpad 6, = 102
356 // numpad 7, = 103
357 // numpad 8, = 104
358 // numpad 9, = 105
359 // multiply, = 106
360 // add, = 107
361 // numpad period (firefox), = 108
362 // subtract, = 109
363 // decimal point, = 110
364 // divide, = 111
365 // f1, = 112
366 // f2, = 113
367 // f3, = 114
368 // f4, = 115
369 // f5, = 116
370 // f6, = 117
371 // f7, = 118
372 // f8, = 119
373 // f9, = 120
374 // f10, = 121
375 // f11, = 122
376 // f12, = 123
377 // f13, = 124
378 // f14, = 125
379 // f15, = 126
380 // f16, = 127
381 // f17, = 128
382 // f18, = 129
383 // f19, = 130
384 // f20, = 131
385 // f21, = 132
386 // f22, = 133
387 // f23, = 134
388 // f24, = 135
389 // f25, = 136
390 // f26, = 137
391 // f27, = 138
392 // f28, = 139
393 // f29, = 140
394 // f30, = 141
395 // f31, = 142
396 // f32, = 143
397 // num lock, = 144
398 // scroll lock, = 145
399 // airplane mode, = 151
400 // ^, = 160
401 // !, = 161
402 // ؛ (arabic semicolon), = 162
403 // #, = 163
404 // $, = 164
405 // ù, = 165
406 // page backward, = 166
407 // page forward, = 167
408 // refresh, = 168
409 // closing paren (AZERTY), = 169
410 // *, = 170
411 // ~ + * key, = 171
412 // home key, = 172
413 // minus (firefox), mute/unmute, = 173
414 // decrease volume level, = 174
415 // increase volume level, = 175
416 // next, = 176
417 // previous, = 177
418 // stop, = 178
419 // play/pause, = 179
420 // e-mail, = 180
421 // mute/unmute (firefox), = 181
422 // decrease volume level (firefox), = 182
423 // increase volume level (firefox), = 183
424 // semi-colon / ñ, = 186
425 // equal sign, = 187
426 // comma, = 188
427 // dash, = 189
428 // period, = 190
429 // forward slash / ç, = 191
430 // grave accent / ñ / æ / ö, = 192
431 // ?, / or °, = 193
432 // numpad period (chrome), = 194
433 // open bracket, = 219
434 // back slash, = 220
435 // close bracket / å, = 221
436 // single quote / ø / ä, = 222
437 // `, = 223
438 // left or right ⌘ key (firefox), = 224
439 // altgr, = 225
440 // < /git >, left back slash, = 226
441 // GNOME Compose Key, = 230
442 // ç, = 231
443 // XF86Forward, = 233
444 // XF86Back, = 234
445 // non-conversion, = 235
446 // alphanumeric, = 240
447 // hiragana/katakana, = 242
448 // half-width/full-width, = 243
449 // kanji, = 244
450 // unlock trackpad (Chrome/Edge), = 251
451 // toggle touchpad, = 255
452 NA = 0,
453 Break = 3,
454 Backspace = 8,
455 Tab = 9,
456 Clear = 12,
457 Enter = 13,
458 Shift = 16,
459 Ctrl = 17,
460 Alt = 18,
461 Pause = 19,
462 CapsLock = 20,
463 // hangul, = 21
464 // hanja, = 25
465 Escape = 27,
466 // conversion, = 28
467 // non-conversion, = 29
468 Space = 32,
469 PageUp = 33,
470 PageDown = 34,
471 End = 35,
472 Home = 36,
473 LeftArrow = 37,
474 UpArrow = 38,
475 RightArrow = 39,
476 DownArrow = 40,
477 // select, = 41
478 // print, = 42
479 // execute, = 43
480 // Print Screen, = 44
481 Insert = 45,
482 Delete = 46,
483 // help, = 47
484 Num0 = 48,
485 Num1 = 49,
486 Num2 = 50,
487 Num3 = 51,
488 Num4 = 52,
489 Num5 = 53,
490 Num6 = 54,
491 Num7 = 55,
492 Num8 = 56,
493 Num9 = 57,
494 // :, = 58
495 // semicolon (firefox), equals, = 59
496 // <, = 60
497 // equals (firefox), = 61
498 // ß, = 63
499 // @ (firefox), = 64
500 A = 65,
501 B = 66,
502 C = 67,
503 D = 68,
504 E = 69,
505 F = 70,
506 G = 71,
507 H = 72,
508 I = 73,
509 J = 74,
510 K = 75,
511 L = 76,
512 M = 77,
513 N = 78,
514 O = 79,
515 P = 80,
516 Q = 81,
517 R = 82,
518 S = 83,
519 T = 84,
520 U = 85,
521 V = 86,
522 W = 87,
523 X = 88,
524 Y = 89,
525 Z = 90,
526 LeftWindow = 91,
527 RightWindow = 92,
528 SelectKey = 93,
529 Numpad0 = 96,
530 Numpad1 = 97,
531 Numpad2 = 98,
532 Numpad3 = 99,
533 Numpad4 = 100,
534 Numpad5 = 101,
535 Numpad6 = 102,
536 Numpad7 = 103,
537 Numpad8 = 104,
538 Numpad9 = 105,
539 Multiply = 106,
540 Add = 107,
541 Subtract = 109,
542 DecimalPoint = 110,
543 Divide = 111,
544 F1 = 112,
545 F2 = 113,
546 F3 = 114,
547 F4 = 115,
548 F5 = 116,
549 F6 = 117,
550 F7 = 118,
551 F8 = 119,
552 F9 = 120,
553 F10 = 121,
554 F11 = 122,
555 F12 = 123,
556 // f13, = 124
557 // f14, = 125
558 // f15, = 126
559 // f16, = 127
560 // f17, = 128
561 // f18, = 129
562 // f19, = 130
563 // f20, = 131
564 // f21, = 132
565 // f22, = 133
566 // f23, = 134
567 // f24, = 135
568 // f25, = 136
569 // f26, = 137
570 // f27, = 138
571 // f28, = 139
572 // f29, = 140
573 // f30, = 141
574 // f31, = 142
575 // f32, = 143
576 NumLock = 144,
577 ScrollLock = 145,
578 // airplane mode, = 151
579 // ^, = 160
580 // !, = 161
581 // ؛ (arabic semicolon), = 162
582 // #, = 163
583 // $, = 164
584 // ù, = 165
585 // page backward, = 166
586 // page forward, = 167
587 // refresh, = 168
588 // closing paren (AZERTY), = 169
589 // *, = 170
590 // ~ + * key, = 171
591 // home key, = 172
592 // minus (firefox), mute/unmute, = 173
593 // decrease volume level, = 174
594 // increase volume level, = 175
595 // next, = 176
596 // previous, = 177
597 // stop, = 178
598 // play/pause, = 179
599 // e-mail, = 180
600 // mute/unmute (firefox), = 181
601 // decrease volume level (firefox), = 182
602 // increase volume level (firefox), = 183
603 Semicolon = 186,
604 EqualSign = 187,
605 Comma = 188,
606 Dash = 189,
607 Period = 190,
608 ForwardSlash = 191,
609 GraveAccent = 192,
610 // ?, / or °, = 193
611 // numpad period (chrome), = 194
612 OpenBracket = 219,
613 BackSlash = 220,
614 CloseBracket = 221,
615 SingleQuote = 222,
616 // `, = 223
617 // left or right ⌘ key (firefox), = 224
618 // altgr, = 225
619 // < /git >, left back slash, = 226
620 // GNOME Compose Key, = 230
621 // ç, = 231
622 // XF86Forward, = 233
623 // XF86Back, = 234
624 // non-conversion, = 235
625 // alphanumeric, = 240
626 // hiragana/katakana, = 242
627 // half-width/full-width, = 243
628 // kanji, = 244
629 // unlock trackpad (Chrome/Edge), = 251
630 // toggle touchpad, = 255
631 Unknown,
632}
633
634impl KeyCode {
635 pub fn from_raw_code(i: u8) -> Self {
636 use KeyCode::*;
637 match i {
638 8 => Backspace,
639 9 => Tab,
640 13 => Enter,
641 16 => Shift,
642 17 => Ctrl,
643 18 => Alt,
644 19 => Pause,
645 20 => CapsLock,
646 27 => Escape,
647 33 => PageUp,
648 34 => PageDown,
649 35 => End,
650 36 => Home,
651 37 => LeftArrow,
652 38 => UpArrow,
653 39 => RightArrow,
654 40 => DownArrow,
655 45 => Insert,
656 46 => Delete,
657 48 => Num0,
658 49 => Num1,
659 50 => Num2,
660 51 => Num3,
661 52 => Num4,
662 53 => Num5,
663 54 => Num6,
664 55 => Num7,
665 56 => Num8,
666 57 => Num9,
667 65 => A,
668 66 => B,
669 67 => C,
670 68 => D,
671 69 => E,
672 70 => F,
673 71 => G,
674 72 => H,
675 73 => I,
676 74 => J,
677 75 => K,
678 76 => L,
679 77 => M,
680 78 => N,
681 79 => O,
682 80 => P,
683 81 => Q,
684 82 => R,
685 83 => S,
686 84 => T,
687 85 => U,
688 86 => V,
689 87 => W,
690 88 => X,
691 89 => Y,
692 90 => Z,
693 91 => LeftWindow,
694 92 => RightWindow,
695 93 => SelectKey,
696 96 => Numpad0,
697 97 => Numpad1,
698 98 => Numpad2,
699 99 => Numpad3,
700 100 => Numpad4,
701 101 => Numpad5,
702 102 => Numpad6,
703 103 => Numpad7,
704 104 => Numpad8,
705 105 => Numpad9,
706 106 => Multiply,
707 107 => Add,
708 109 => Subtract,
709 110 => DecimalPoint,
710 111 => Divide,
711 112 => F1,
712 113 => F2,
713 114 => F3,
714 115 => F4,
715 116 => F5,
716 117 => F6,
717 118 => F7,
718 119 => F8,
719 120 => F9,
720 121 => F10,
721 122 => F11,
722 123 => F12,
723 144 => NumLock,
724 145 => ScrollLock,
725 186 => Semicolon,
726 187 => EqualSign,
727 188 => Comma,
728 189 => Dash,
729 190 => Period,
730 191 => ForwardSlash,
731 192 => GraveAccent,
732 219 => OpenBracket,
733 220 => BackSlash,
734 221 => CloseBracket,
735 222 => SingleQuote,
736 _ => Unknown,
737 }
738 }
739
740 // get the raw code
741 pub fn raw_code(&self) -> u32 {
742 *self as u32
743 }
744}