Rewild Your Web
at main 178 lines 6.4 kB view raw
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+}