1use 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 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 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 fn Key(&self) -> DOMString {
224 self.key.borrow().clone()
225 }
226
227 fn Code(&self) -> DOMString {
229 self.code.borrow().clone()
230 }
231
232 fn Location(&self) -> u32 {
234 self.location.get()
235 }
236
237 fn CtrlKey(&self) -> bool {
239 self.modifiers.get().contains(Modifiers::CONTROL)
240 }
241
242 fn ShiftKey(&self) -> bool {
244 self.modifiers.get().contains(Modifiers::SHIFT)
245 }
246
247 fn AltKey(&self) -> bool {
249 self.modifiers.get().contains(Modifiers::ALT)
250 }
251
252 fn MetaKey(&self) -> bool {
254 self.modifiers.get().contains(Modifiers::META)
255 }
256
257 fn Repeat(&self) -> bool {
259 self.repeat.get()
260 }
261
262 fn IsComposing(&self) -> bool {
264 self.is_composing.get()
265 }
266
267 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 fn CharCode(&self) -> u32 {
288 self.char_code.get()
289 }
290
291 fn KeyCode(&self) -> u32 {
293 self.key_code.get()
294 }
295
296 fn IsTrusted(&self) -> bool {
298 self.uievent.IsTrusted()
299 }
300}