Skip to main content

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}