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).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}