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
150 }
151
152 pub(crate) fn key(&self) -> Key {
153 self.typed_key.borrow().clone()
154 }
155
156 pub(crate) fn modifiers(&self) -> Modifiers {
157 self.modifiers.get()
158 }
159}
160
161impl KeyboardEventMethods<crate::DomTypeHolder> for KeyboardEvent {
162 fn Constructor(
164 window: &Window,
165 proto: Option<HandleObject>,
166 can_gc: CanGc,
167 type_: DOMString,
168 init: &KeyboardEventBinding::KeyboardEventInit,
169 ) -> Fallible<DomRoot<KeyboardEvent>> {
170 let mut modifiers = Modifiers::empty();
171 modifiers.set(Modifiers::CONTROL, init.parent.ctrlKey);
172 modifiers.set(Modifiers::ALT, init.parent.altKey);
173 modifiers.set(Modifiers::SHIFT, init.parent.shiftKey);
174 modifiers.set(Modifiers::META, init.parent.metaKey);
175 let event = KeyboardEvent::new_with_proto(
176 window,
177 proto,
178 type_,
179 init.parent.parent.parent.bubbles,
180 init.parent.parent.parent.cancelable,
181 init.parent.parent.view.as_deref(),
182 init.parent.parent.detail,
183 Key::Named(NamedKey::Unidentified),
184 init.code.clone(),
185 init.location,
186 init.repeat,
187 init.isComposing,
188 modifiers,
189 0,
190 0,
191 can_gc,
192 );
193 *event.key.borrow_mut() = init.key.clone();
194 Ok(event)
195 }
196
197 fn InitKeyboardEvent(
199 &self,
200 type_arg: DOMString,
201 can_bubble_arg: bool,
202 cancelable_arg: bool,
203 view_arg: Option<&Window>,
204 key_arg: DOMString,
205 location_arg: u32,
206 _modifiers_list_arg: DOMString,
207 repeat: bool,
208 _locale: DOMString,
209 ) {
210 if self.upcast::<Event>().dispatching() {
211 return;
212 }
213
214 self.upcast::<UIEvent>()
215 .InitUIEvent(type_arg, can_bubble_arg, cancelable_arg, view_arg, 0);
216 *self.key.borrow_mut() = key_arg;
217 self.location.set(location_arg);
218 self.repeat.set(repeat);
219 }
220
221 fn Key(&self) -> DOMString {
223 self.key.borrow().clone()
224 }
225
226 fn Code(&self) -> DOMString {
228 self.code.borrow().clone()
229 }
230
231 fn Location(&self) -> u32 {
233 self.location.get()
234 }
235
236 fn CtrlKey(&self) -> bool {
238 self.modifiers.get().contains(Modifiers::CONTROL)
239 }
240
241 fn ShiftKey(&self) -> bool {
243 self.modifiers.get().contains(Modifiers::SHIFT)
244 }
245
246 fn AltKey(&self) -> bool {
248 self.modifiers.get().contains(Modifiers::ALT)
249 }
250
251 fn MetaKey(&self) -> bool {
253 self.modifiers.get().contains(Modifiers::META)
254 }
255
256 fn Repeat(&self) -> bool {
258 self.repeat.get()
259 }
260
261 fn IsComposing(&self) -> bool {
263 self.is_composing.get()
264 }
265
266 fn GetModifierState(&self, key_arg: DOMString) -> bool {
268 self.modifiers.get().contains(match &*key_arg {
269 "Alt" => Modifiers::ALT,
270 "AltGraph" => Modifiers::ALT_GRAPH,
271 "CapsLock" => Modifiers::CAPS_LOCK,
272 "Control" => Modifiers::CONTROL,
273 "Fn" => Modifiers::FN,
274 "FnLock" => Modifiers::FN_LOCK,
275 "Meta" => Modifiers::META,
276 "NumLock" => Modifiers::NUM_LOCK,
277 "ScrollLock" => Modifiers::SCROLL_LOCK,
278 "Shift" => Modifiers::SHIFT,
279 "Symbol" => Modifiers::SYMBOL,
280 "SymbolLock" => Modifiers::SYMBOL_LOCK,
281 _ => return false,
282 })
283 }
284
285 fn CharCode(&self) -> u32 {
287 self.char_code.get()
288 }
289
290 fn KeyCode(&self) -> u32 {
292 self.key_code.get()
293 }
294
295 fn Which(&self) -> u32 {
297 if self.char_code.get() != 0 {
298 self.char_code.get()
299 } else {
300 self.key_code.get()
301 }
302 }
303
304 fn IsTrusted(&self) -> bool {
306 self.uievent.IsTrusted()
307 }
308}