Rewild Your Web
web
browser
dweb
1--- original
2+++ modified
3@@ -0,0 +1,174 @@
4+/* SPDX Id: AGPL-3.0-or-later */
5+
6+//! The `Keyboard` interface provides virtual keyboard input injection.
7+//! This is a Servo-specific, non-standard API for privileged pages.
8+
9+use constellation_traits::ScriptToConstellationMessage;
10+use dom_struct::dom_struct;
11+use embedder_traits::{
12+ ImeEvent, InputEvent, InputEventAndId, KeyboardEvent as EmbedderKeyboardEvent,
13+};
14+use keyboard_types::{
15+ Code, CompositionEvent, CompositionState, Key, KeyState, Location, Modifiers,
16+};
17+
18+use crate::dom::bindings::codegen::Bindings::KeyboardBinding::{
19+ KeyboardMethods, ServoCompositionEventInit, ServoKeyboardEventInit,
20+};
21+use crate::dom::bindings::error::{Error, Fallible};
22+use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
23+use crate::dom::bindings::root::DomRoot;
24+use crate::dom::bindings::str::DOMString;
25+use crate::dom::globalscope::GlobalScope;
26+use crate::script_runtime::CanGc;
27+
28+#[dom_struct]
29+pub(crate) struct Keyboard {
30+ reflector_: Reflector,
31+}
32+
33+impl Keyboard {
34+ fn new_inherited() -> Keyboard {
35+ Keyboard {
36+ reflector_: Reflector::new(),
37+ }
38+ }
39+
40+ pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<Keyboard> {
41+ reflect_dom_object(Box::new(Keyboard::new_inherited()), global, can_gc)
42+ }
43+
44+ fn send_to_active_ime(&self, event: InputEvent) {
45+ let global = self.global();
46+ let event_and_id = InputEventAndId::from(event);
47+ let _ = global.script_to_constellation_chan().send(
48+ ScriptToConstellationMessage::InjectInputToActiveIme(event_and_id),
49+ );
50+ }
51+
52+ fn parse_key_state(state: &DOMString) -> Fallible<KeyState> {
53+ match &*state.str() {
54+ "down" => Ok(KeyState::Down),
55+ "up" => Ok(KeyState::Up),
56+ _ => Err(Error::Type(format!(
57+ "Invalid key state '{}': expected 'down' or 'up'",
58+ state
59+ ))),
60+ }
61+ }
62+
63+ fn parse_key(key: &DOMString) -> Key {
64+ let key_str = key.str();
65+ // Try to parse as a named key first
66+ if key_str.len() > 1 {
67+ // This could be a named key like "Backspace", "Enter", etc.
68+ match &*key_str {
69+ "Backspace" => Key::Named(keyboard_types::NamedKey::Backspace),
70+ "Tab" => Key::Named(keyboard_types::NamedKey::Tab),
71+ "Enter" => Key::Named(keyboard_types::NamedKey::Enter),
72+ "Escape" => Key::Named(keyboard_types::NamedKey::Escape),
73+ "Delete" => Key::Named(keyboard_types::NamedKey::Delete),
74+ "ArrowUp" => Key::Named(keyboard_types::NamedKey::ArrowUp),
75+ "ArrowDown" => Key::Named(keyboard_types::NamedKey::ArrowDown),
76+ "ArrowLeft" => Key::Named(keyboard_types::NamedKey::ArrowLeft),
77+ "ArrowRight" => Key::Named(keyboard_types::NamedKey::ArrowRight),
78+ "Home" => Key::Named(keyboard_types::NamedKey::Home),
79+ "End" => Key::Named(keyboard_types::NamedKey::End),
80+ "PageUp" => Key::Named(keyboard_types::NamedKey::PageUp),
81+ "PageDown" => Key::Named(keyboard_types::NamedKey::PageDown),
82+ "Space" => Key::Character(" ".to_string()),
83+ _ => Key::Character(key_str.to_string()),
84+ }
85+ } else {
86+ Key::Character(key_str.to_string())
87+ }
88+ }
89+
90+ fn parse_code(code: &DOMString) -> Code {
91+ let code_str = code.str();
92+ if code_str.is_empty() {
93+ Code::Unidentified
94+ } else {
95+ // Try to parse the code string
96+ code_str.to_string().parse().unwrap_or(Code::Unidentified)
97+ }
98+ }
99+
100+ fn parse_location(location: u32) -> Location {
101+ match location {
102+ 0 => Location::Standard,
103+ 1 => Location::Left,
104+ 2 => Location::Right,
105+ 3 => Location::Numpad,
106+ _ => Location::Standard,
107+ }
108+ }
109+
110+ fn build_modifiers(init: &ServoKeyboardEventInit) -> Modifiers {
111+ let mut modifiers = Modifiers::empty();
112+ if init.shift {
113+ modifiers.insert(Modifiers::SHIFT);
114+ }
115+ if init.ctrl {
116+ modifiers.insert(Modifiers::CONTROL);
117+ }
118+ if init.alt {
119+ modifiers.insert(Modifiers::ALT);
120+ }
121+ if init.meta {
122+ modifiers.insert(Modifiers::META);
123+ }
124+ modifiers
125+ }
126+
127+ fn parse_composition_state(state: &DOMString) -> Fallible<CompositionState> {
128+ match &*state.str() {
129+ "start" => Ok(CompositionState::Start),
130+ "update" => Ok(CompositionState::Update),
131+ "end" => Ok(CompositionState::End),
132+ _ => Err(Error::Type(format!(
133+ "Invalid composition state '{}': expected 'start', 'update', or 'end'",
134+ state
135+ ))),
136+ }
137+ }
138+}
139+
140+impl KeyboardMethods<crate::DomTypeHolder> for Keyboard {
141+ /// Send a keyboard event (keydown/keyup) to the active IME input.
142+ fn SendKeyboardEvent(&self, init: &ServoKeyboardEventInit) -> Fallible<()> {
143+ let state = Self::parse_key_state(&init.state)?;
144+ let key = Self::parse_key(&init.key);
145+ let code = Self::parse_code(&init.code);
146+ let location = Self::parse_location(init.location);
147+ let modifiers = Self::build_modifiers(init);
148+
149+ let keyboard_event = EmbedderKeyboardEvent::new_without_event(
150+ state,
151+ key,
152+ code,
153+ location,
154+ modifiers,
155+ init.repeat,
156+ init.isComposing,
157+ );
158+
159+ let event = InputEvent::Keyboard(keyboard_event);
160+ self.send_to_active_ime(event);
161+ Ok(())
162+ }
163+
164+ /// Send a composition event to the active IME input.
165+ fn SendCompositionEvent(&self, init: &ServoCompositionEventInit) -> Fallible<()> {
166+ let state = Self::parse_composition_state(&init.state)?;
167+
168+ let composition_event = CompositionEvent {
169+ state,
170+ data: init.data.to_string(),
171+ };
172+
173+ let event = InputEvent::Ime(ImeEvent::Composition(composition_event));
174+ self.send_to_active_ime(event);
175+ Ok(())
176+ }
177+}