script/dom/
keyboardevent.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use js::rust::HandleObject;
9use keyboard_types::{Key, Modifiers, NamedKey};
10
11use crate::dom::bindings::cell::DomRefCell;
12use crate::dom::bindings::codegen::Bindings::KeyboardEventBinding;
13use crate::dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
14use crate::dom::bindings::codegen::Bindings::UIEventBinding::UIEventMethods;
15use crate::dom::bindings::error::Fallible;
16use crate::dom::bindings::inheritance::Castable;
17use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::bindings::str::DOMString;
20use crate::dom::event::Event;
21use crate::dom::uievent::UIEvent;
22use crate::dom::window::Window;
23use crate::script_runtime::CanGc;
24
25#[dom_struct]
26pub(crate) struct KeyboardEvent {
27    uievent: UIEvent,
28    key: DomRefCell<DOMString>,
29    #[no_trace]
30    typed_key: DomRefCell<Key>,
31    code: DomRefCell<DOMString>,
32    location: Cell<u32>,
33    #[no_trace]
34    modifiers: Cell<Modifiers>,
35    repeat: Cell<bool>,
36    is_composing: Cell<bool>,
37    char_code: Cell<u32>,
38    key_code: Cell<u32>,
39}
40
41impl KeyboardEvent {
42    fn new_inherited() -> KeyboardEvent {
43        KeyboardEvent {
44            uievent: UIEvent::new_inherited(),
45            key: DomRefCell::new(DOMString::new()),
46            typed_key: DomRefCell::new(Key::Named(NamedKey::Unidentified)),
47            code: DomRefCell::new(DOMString::new()),
48            location: Cell::new(0),
49            modifiers: Cell::new(Modifiers::empty()),
50            repeat: Cell::new(false),
51            is_composing: Cell::new(false),
52            char_code: Cell::new(0),
53            key_code: Cell::new(0),
54        }
55    }
56
57    pub(crate) fn new_uninitialized(window: &Window, can_gc: CanGc) -> DomRoot<KeyboardEvent> {
58        Self::new_uninitialized_with_proto(window, None, can_gc)
59    }
60
61    fn new_uninitialized_with_proto(
62        window: &Window,
63        proto: Option<HandleObject>,
64        can_gc: CanGc,
65    ) -> DomRoot<KeyboardEvent> {
66        reflect_dom_object_with_proto(
67            Box::new(KeyboardEvent::new_inherited()),
68            window,
69            proto,
70            can_gc,
71        )
72    }
73
74    #[allow(clippy::too_many_arguments)]
75    pub(crate) fn new(
76        window: &Window,
77        type_: DOMString,
78        can_bubble: bool,
79        cancelable: bool,
80        view: Option<&Window>,
81        detail: i32,
82        key: Key,
83        code: DOMString,
84        location: u32,
85        repeat: bool,
86        is_composing: bool,
87        modifiers: Modifiers,
88        char_code: u32,
89        key_code: u32,
90        can_gc: CanGc,
91    ) -> DomRoot<KeyboardEvent> {
92        Self::new_with_proto(
93            window,
94            None,
95            type_,
96            can_bubble,
97            cancelable,
98            view,
99            detail,
100            key,
101            code,
102            location,
103            repeat,
104            is_composing,
105            modifiers,
106            char_code,
107            key_code,
108            can_gc,
109        )
110    }
111
112    #[allow(clippy::too_many_arguments)]
113    fn new_with_proto(
114        window: &Window,
115        proto: Option<HandleObject>,
116        type_: DOMString,
117        can_bubble: bool,
118        cancelable: bool,
119        view: Option<&Window>,
120        _detail: i32,
121        key: Key,
122        code: DOMString,
123        location: u32,
124        repeat: bool,
125        is_composing: bool,
126        modifiers: Modifiers,
127        char_code: u32,
128        key_code: u32,
129        can_gc: CanGc,
130    ) -> DomRoot<KeyboardEvent> {
131        let ev = KeyboardEvent::new_uninitialized_with_proto(window, proto, can_gc);
132        ev.InitKeyboardEvent(
133            type_,
134            can_bubble,
135            cancelable,
136            view,
137            DOMString::from(key.to_string()),
138            location,
139            DOMString::new(),
140            repeat,
141            DOMString::new(),
142        );
143        *ev.typed_key.borrow_mut() = key;
144        *ev.code.borrow_mut() = code;
145        ev.modifiers.set(modifiers);
146        ev.is_composing.set(is_composing);
147        ev.char_code.set(char_code);
148        ev.key_code.set(key_code);
149        ev.uievent.set_which(key_code);
150        ev
151    }
152
153    pub(crate) fn key(&self) -> Key {
154        self.typed_key.borrow().clone()
155    }
156
157    pub(crate) fn modifiers(&self) -> Modifiers {
158        self.modifiers.get()
159    }
160}
161
162impl KeyboardEventMethods<crate::DomTypeHolder> for KeyboardEvent {
163    /// <https://w3c.github.io/uievents/#dom-keyboardevent-keyboardevent>
164    fn Constructor(
165        window: &Window,
166        proto: Option<HandleObject>,
167        can_gc: CanGc,
168        type_: DOMString,
169        init: &KeyboardEventBinding::KeyboardEventInit,
170    ) -> Fallible<DomRoot<KeyboardEvent>> {
171        let mut modifiers = Modifiers::empty();
172        modifiers.set(Modifiers::CONTROL, init.parent.ctrlKey);
173        modifiers.set(Modifiers::ALT, init.parent.altKey);
174        modifiers.set(Modifiers::SHIFT, init.parent.shiftKey);
175        modifiers.set(Modifiers::META, init.parent.metaKey);
176        let event = KeyboardEvent::new_with_proto(
177            window,
178            proto,
179            type_,
180            init.parent.parent.parent.bubbles,
181            init.parent.parent.parent.cancelable,
182            init.parent.parent.view.as_deref(),
183            init.parent.parent.detail,
184            Key::Named(NamedKey::Unidentified),
185            init.code.clone(),
186            init.location,
187            init.repeat,
188            init.isComposing,
189            modifiers,
190            init.charCode,
191            init.keyCode,
192            can_gc,
193        );
194        *event.key.borrow_mut() = init.key.clone();
195        Ok(event)
196    }
197
198    /// <https://w3c.github.io/uievents/#widl-KeyboardEvent-initKeyboardEvent>
199    fn InitKeyboardEvent(
200        &self,
201        type_arg: DOMString,
202        can_bubble_arg: bool,
203        cancelable_arg: bool,
204        view_arg: Option<&Window>,
205        key_arg: DOMString,
206        location_arg: u32,
207        _modifiers_list_arg: DOMString,
208        repeat: bool,
209        _locale: DOMString,
210    ) {
211        if self.upcast::<Event>().dispatching() {
212            return;
213        }
214
215        self.upcast::<UIEvent>()
216            .InitUIEvent(type_arg, can_bubble_arg, cancelable_arg, view_arg, 0);
217        *self.key.borrow_mut() = key_arg;
218        self.location.set(location_arg);
219        self.repeat.set(repeat);
220    }
221
222    /// <https://w3c.github.io/uievents/#dom-keyboardevent-initkeyboardevent>
223    fn Key(&self) -> DOMString {
224        self.key.borrow().clone()
225    }
226
227    /// <https://w3c.github.io/uievents/#dom-keyboardevent-code>
228    fn Code(&self) -> DOMString {
229        self.code.borrow().clone()
230    }
231
232    /// <https://w3c.github.io/uievents/#dom-keyboardevent-location>
233    fn Location(&self) -> u32 {
234        self.location.get()
235    }
236
237    /// <https://w3c.github.io/uievents/#dom-keyboardevent-ctrlkey>
238    fn CtrlKey(&self) -> bool {
239        self.modifiers.get().contains(Modifiers::CONTROL)
240    }
241
242    /// <https://w3c.github.io/uievents/#dom-keyboardevent-shiftkey>
243    fn ShiftKey(&self) -> bool {
244        self.modifiers.get().contains(Modifiers::SHIFT)
245    }
246
247    /// <https://w3c.github.io/uievents/#dom-keyboardevent-altkey>
248    fn AltKey(&self) -> bool {
249        self.modifiers.get().contains(Modifiers::ALT)
250    }
251
252    /// <https://w3c.github.io/uievents/#dom-keyboardevent-metakey>
253    fn MetaKey(&self) -> bool {
254        self.modifiers.get().contains(Modifiers::META)
255    }
256
257    /// <https://w3c.github.io/uievents/#dom-keyboardevent-repeat>
258    fn Repeat(&self) -> bool {
259        self.repeat.get()
260    }
261
262    /// <https://w3c.github.io/uievents/#dom-keyboardevent-iscomposing>
263    fn IsComposing(&self) -> bool {
264        self.is_composing.get()
265    }
266
267    /// <https://w3c.github.io/uievents/#dom-keyboardevent-getmodifierstate>
268    fn GetModifierState(&self, key_arg: DOMString) -> bool {
269        self.modifiers.get().contains(match &*key_arg.str() {
270            "Alt" => Modifiers::ALT,
271            "AltGraph" => Modifiers::ALT_GRAPH,
272            "CapsLock" => Modifiers::CAPS_LOCK,
273            "Control" => Modifiers::CONTROL,
274            "Fn" => Modifiers::FN,
275            "FnLock" => Modifiers::FN_LOCK,
276            "Meta" => Modifiers::META,
277            "NumLock" => Modifiers::NUM_LOCK,
278            "ScrollLock" => Modifiers::SCROLL_LOCK,
279            "Shift" => Modifiers::SHIFT,
280            "Symbol" => Modifiers::SYMBOL,
281            "SymbolLock" => Modifiers::SYMBOL_LOCK,
282            _ => return false,
283        })
284    }
285
286    /// <https://w3c.github.io/uievents/#dom-keyboardevent-charcode>
287    fn CharCode(&self) -> u32 {
288        self.char_code.get()
289    }
290
291    /// <https://w3c.github.io/uievents/#dom-keyboardevent-keycode>
292    fn KeyCode(&self) -> u32 {
293        self.key_code.get()
294    }
295
296    /// <https://dom.spec.whatwg.org/#dom-event-istrusted>
297    fn IsTrusted(&self) -> bool {
298        self.uievent.IsTrusted()
299    }
300}