Skip to main content

thirtyfour/cdp/domains/
input.rs

1//! `Input` domain — synthetic keyboard, mouse, and text input events.
2
3use serde::Serialize;
4
5use crate::cdp::Cdp;
6use crate::cdp::command::{CdpCommand, Empty};
7use crate::common::protocol::string_enum;
8use crate::error::WebDriverResult;
9
10string_enum! {
11    /// Type of synthetic keyboard event for [`DispatchKeyEvent`].
12    pub enum KeyEventType {
13        /// Key pressed down.
14        KeyDown = "keyDown",
15        /// Key released.
16        KeyUp = "keyUp",
17        /// Raw key down (skips the OS-level translation step).
18        RawKeyDown = "rawKeyDown",
19        /// Inserts a character (e.g. for IME).
20        Char = "char",
21    }
22}
23
24string_enum! {
25    /// Type of synthetic mouse event for [`DispatchMouseEvent`].
26    pub enum MouseEventType {
27        /// Mouse button pressed.
28        MousePressed = "mousePressed",
29        /// Mouse button released.
30        MouseReleased = "mouseReleased",
31        /// Mouse moved.
32        MouseMoved = "mouseMoved",
33        /// Mouse wheel scrolled.
34        MouseWheel = "mouseWheel",
35    }
36}
37
38string_enum! {
39    /// Mouse button identifier for [`DispatchMouseEvent`].
40    pub enum MouseButton {
41        /// No button.
42        None = "none",
43        /// Left button.
44        Left = "left",
45        /// Middle button.
46        Middle = "middle",
47        /// Right button.
48        Right = "right",
49        /// Back button.
50        Back = "back",
51        /// Forward button.
52        Forward = "forward",
53    }
54}
55
56/// `Input.dispatchKeyEvent`.
57#[derive(Debug, Clone, Serialize)]
58#[serde(rename_all = "camelCase")]
59pub struct DispatchKeyEvent {
60    /// Event phase.
61    pub r#type: KeyEventType,
62    /// Bit mask of [Modifiers](https://chromedevtools.github.io/devtools-protocol/tot/Input/#method-dispatchKeyEvent).
63    /// 1=Alt, 2=Ctrl, 4=Meta, 8=Shift.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub modifiers: Option<u32>,
66    /// Text the key represents (for `"char"`).
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub text: Option<String>,
69    /// Unmodified text (e.g. `"a"` instead of `"A"` if shift is pressed).
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub unmodified_text: Option<String>,
72    /// Key identifier (e.g. `"Enter"`, `"a"`).
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub key: Option<String>,
75    /// `code` value per <https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values> (e.g. `"KeyA"`).
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub code: Option<String>,
78    /// Native virtual key code.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub native_virtual_key_code: Option<i32>,
81    /// Windows virtual key code.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub windows_virtual_key_code: Option<i32>,
84    /// Whether this is an auto-repeat.
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub auto_repeat: Option<bool>,
87    /// Whether this is a keypad event.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub is_keypad: Option<bool>,
90    /// Whether the event is a system key (Alt/Meta).
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub is_system_key: Option<bool>,
93}
94impl CdpCommand for DispatchKeyEvent {
95    const METHOD: &'static str = "Input.dispatchKeyEvent";
96    type Returns = Empty;
97}
98
99/// `Input.dispatchMouseEvent`.
100#[derive(Debug, Clone, Serialize)]
101#[serde(rename_all = "camelCase")]
102pub struct DispatchMouseEvent {
103    /// Event phase.
104    pub r#type: MouseEventType,
105    /// X coordinate of the event relative to the main frame's viewport in CSS pixels.
106    pub x: f64,
107    /// Y coordinate of the event relative to the main frame's viewport in CSS pixels.
108    pub y: f64,
109    /// Bit mask of modifiers (see [`DispatchKeyEvent::modifiers`]).
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub modifiers: Option<u32>,
112    /// Mouse button identifier.
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub button: Option<MouseButton>,
115    /// Number of times the mouse button was clicked. Defaults to 0.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub click_count: Option<u32>,
118    /// X-axis delta for `"mouseWheel"`.
119    #[serde(skip_serializing_if = "Option::is_none")]
120    pub delta_x: Option<f64>,
121    /// Y-axis delta for `"mouseWheel"`.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub delta_y: Option<f64>,
124}
125impl CdpCommand for DispatchMouseEvent {
126    const METHOD: &'static str = "Input.dispatchMouseEvent";
127    type Returns = Empty;
128}
129
130/// `Input.insertText` — types text into the focused element via IME.
131#[derive(Debug, Clone, Serialize)]
132pub struct InsertText {
133    /// Text to insert.
134    pub text: String,
135}
136impl CdpCommand for InsertText {
137    const METHOD: &'static str = "Input.insertText";
138    type Returns = Empty;
139}
140
141/// Domain facade returned by [`Cdp::input`].
142#[derive(Debug)]
143pub struct InputDomain<'a> {
144    cdp: &'a Cdp,
145}
146
147impl<'a> InputDomain<'a> {
148    pub(crate) fn new(cdp: &'a Cdp) -> Self {
149        Self {
150            cdp,
151        }
152    }
153
154    /// `Input.insertText` — types text into the focused element.
155    pub async fn insert_text(&self, text: impl Into<String>) -> WebDriverResult<()> {
156        self.cdp
157            .send(InsertText {
158                text: text.into(),
159            })
160            .await?;
161        Ok(())
162    }
163}