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