dioxus_html/events/
keyboard.rs

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