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