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