///|
/// CDP Input Domain
///
/// Implements Chrome DevTools Protocol Input domain.
/// Handles mouse and keyboard input.
///|
/// Input Domain handler
pub struct InputDomain {
tree : @dom.DomTree
/// Current mouse position
mut mouse_x : Double
mut mouse_y : Double
/// Mouse button state
mut button_pressed : Bool
}
///|
/// Create new Input domain
pub fn InputDomain::new(tree : @dom.DomTree) -> InputDomain {
{ tree, mouse_x: 0.0, mouse_y: 0.0, button_pressed: false }
}
///|
fn rect_contains_point(rect : @dom.Rect, x : Double, y : Double) -> Bool {
x >= rect.x &&
x <= rect.x + rect.width &&
y >= rect.y &&
y <= rect.y + rect.height
}
///|
fn InputDomain::find_hit_node(
self : InputDomain,
node : @dom.NodeId,
x : Double,
y : Double,
) -> @dom.NodeId? {
match self.tree.get_children(node) {
Ok(children) => {
let mut idx = children.length() - 1
while idx >= 0 {
match self.find_hit_node(children[idx], x, y) {
Some(hit) => return Some(hit)
None => ()
}
idx -= 1
}
}
Err(_) => ()
}
match self.tree.get_node_info(node) {
Ok(info) =>
match info.node_type {
@dom.Element =>
match self.tree.get_cached_rect(node) {
Some(rect) if rect_contains_point(rect, x, y) => Some(node)
_ => None
}
_ => None
}
Err(_) => None
}
}
// =============================================================================
// Mouse Events
// =============================================================================
///|
/// Input.dispatchMouseEvent
pub fn InputDomain::dispatch_mouse_event(
self : InputDomain,
type_ : String,
x : Double,
y : Double,
button : String,
click_count : Int,
) -> Result[Unit, CdpError] {
// Suppress unused warnings for now
let _ = button
let _ = click_count
// Update mouse position
self.mouse_x = x
self.mouse_y = y
// Handle event type
match type_ {
"mousePressed" => {
self.button_pressed = true
Ok(())
}
"mouseReleased" => {
self.button_pressed = false
// On release, trigger click on element at position
self.click_at(x, y)
}
"mouseMoved" => Ok(())
_ =>
Err(
CdpError::from_code(InvalidParams, "Unknown mouse event type: " + type_),
)
}
}
///|
/// Find element at position and trigger click
fn InputDomain::click_at(
self : InputDomain,
x : Double,
y : Double,
) -> Result[Unit, CdpError] {
let doc = self.tree.get_document()
match self.find_hit_node(doc, x, y) {
Some(node) => self.tree.set_focus(Some(node))
None => self.tree.set_focus(None)
}
Ok(())
}
// =============================================================================
// Keyboard Events
// =============================================================================
///|
/// Input.dispatchKeyEvent
pub fn InputDomain::dispatch_key_event(
self : InputDomain,
type_ : String,
key : String,
code : String,
text : String?,
) -> Result[Unit, CdpError] {
// Suppress unused warnings
let _ = self
let _ = code
match type_ {
"keyDown" =>
// Handle special keys
match key {
"Enter" | "Return" =>
// Submit form or activate focused element
Ok(())
"Tab" =>
// Move focus to next element
Ok(())
"Escape" =>
// Cancel current action
Ok(())
_ => Ok(())
}
"keyUp" => Ok(())
"char" =>
// Handle text input
match text {
Some(t) => {
// Input text to focused element
let _ = t
Ok(())
}
None => Ok(())
}
_ =>
Err(
CdpError::from_code(InvalidParams, "Unknown key event type: " + type_),
)
}
}
///|
/// Input.insertText - Insert text at current cursor position
pub fn InputDomain::insert_text(
self : InputDomain,
text : String,
) -> Result[Unit, CdpError] {
// Get focused element and insert text
match self.tree.get_focus() {
Some(focused) =>
// Append text to focused element's value
match self.tree.get_attribute(focused, "value") {
Ok(Some(current)) =>
match self.tree.set_attribute(focused, "value", current + text) {
Ok(_) => Ok(())
Err(e) => Err(core_to_cdp_error(e))
}
Ok(None) =>
match self.tree.set_attribute(focused, "value", text) {
Ok(_) => Ok(())
Err(e) => Err(core_to_cdp_error(e))
}
Err(e) => Err(core_to_cdp_error(e))
}
None => Err(CdpError::from_code(NoSuchElement, "No element is focused"))
}
}