use chromiumoxide::cdp::browser_protocol::input::{DispatchKeyEventParams, DispatchKeyEventType};
use chromiumoxide::keys::get_key_definition;
use chromiumoxide::Page;
use crate::error::{AuditError, Result};
pub async fn press(page: &Page, key: &str) -> Result<()> {
press_with_modifiers(page, key, 0).await
}
pub async fn press_with_modifiers(page: &Page, key: &str, modifiers: i64) -> Result<()> {
let def = get_key_definition(key).ok_or_else(|| AuditError::InteractionFailed {
reason: format!("Unknown key: {key}"),
})?;
let mut cmd = DispatchKeyEventParams::builder();
let key_down_event_type = if let Some(txt) = def.text {
cmd = cmd.text(txt);
DispatchKeyEventType::KeyDown
} else if def.key.len() == 1 {
cmd = cmd.text(def.key);
DispatchKeyEventType::KeyDown
} else {
DispatchKeyEventType::RawKeyDown
};
cmd = cmd
.key(def.key)
.code(def.code)
.windows_virtual_key_code(def.key_code)
.native_virtual_key_code(def.key_code)
.modifiers(modifiers);
let key_down = cmd
.clone()
.r#type(key_down_event_type)
.build()
.map_err(|e| AuditError::InteractionFailed {
reason: format!("KeyDown build failed: {e}"),
})?;
page.execute(key_down)
.await
.map_err(|e| AuditError::InteractionFailed {
reason: format!("KeyDown dispatch failed: {e}"),
})?;
let key_up = cmd
.r#type(DispatchKeyEventType::KeyUp)
.build()
.map_err(|e| AuditError::InteractionFailed {
reason: format!("KeyUp build failed: {e}"),
})?;
page.execute(key_up)
.await
.map_err(|e| AuditError::InteractionFailed {
reason: format!("KeyUp dispatch failed: {e}"),
})?;
Ok(())
}
pub async fn press_tab(page: &Page) -> Result<()> {
press(page, "Tab").await
}
pub async fn press_shift_tab(page: &Page) -> Result<()> {
press_with_modifiers(page, "Tab", 8).await
}
pub async fn press_enter(page: &Page) -> Result<()> {
press(page, "Enter").await
}
pub async fn press_escape(page: &Page) -> Result<()> {
press(page, "Escape").await
}
pub async fn press_arrow(page: &Page, direction: &str) -> Result<()> {
let key = match direction {
"Up" => "ArrowUp",
"Down" => "ArrowDown",
"Left" => "ArrowLeft",
"Right" => "ArrowRight",
other => {
return Err(AuditError::InteractionFailed {
reason: format!("Invalid arrow direction: {other}"),
});
}
};
press(page, key).await
}
pub async fn type_text(page: &Page, text: &str) -> Result<()> {
for ch in text.chars() {
let s = ch.to_string();
press(page, &s).await?;
}
Ok(())
}