playwright/api/input_device.rs
1use crate::imp::{
2 core::*,
3 page::{MouseClickArgs, Page as PageImpl},
4 prelude::*,
5 utils::MouseButton
6};
7
8/// Keyboard provides an api for managing a virtual keyboard. The high level api is [`method: Keyboard.type`], which takes
9/// raw characters and generates proper keydown, keypress/input, and keyup events on your page.
10///
11/// For finer control, you can use [`method: Keyboard.down`], [`method: Keyboard.up`], and [`method: Keyboard.insertText`]
12/// to manually fire events as if they were generated from a real keyboard.
13///
14/// An example of holding down `Shift` in order to select and delete some text:
15///
16/// ```js
17/// await page.keyboard.type('Hello World!');
18/// await page.keyboard.press('ArrowLeft');
19///
20/// await page.keyboard.down('Shift');
21/// for (let i = 0; i < ' World'.length; i++)
22/// await page.keyboard.press('ArrowLeft');
23/// await page.keyboard.up('Shift');
24///
25/// await page.keyboard.press('Backspace');
26///// Result text will end up saying 'Hello!'
27/// ```
28///
29/// An example of pressing uppercase `A`
30/// ```js
31/// await page.keyboard.press('Shift+KeyA');
32///// or
33/// await page.keyboard.press('Shift+A');
34/// ```
35///
36/// An example to trigger select-all with the keyboard
37/// ```js
38///// on Windows and Linux
39/// await page.keyboard.press('Control+A');
40///// on macOS
41/// await page.keyboard.press('Meta+A');
42/// ```
43#[derive(Debug, Clone)]
44pub struct Keyboard {
45 inner: Weak<PageImpl>
46}
47
48/// The Mouse class operates in main-frame CSS pixels relative to the top-left corner of the viewport.
49///
50/// Every `page` object has its own Mouse, accessible with [`property: Page.mouse`].
51///
52/// ```js
53///// Using ‘page.mouse’ to trace a 100x100 square.
54/// await page.mouse.move(0, 0);
55/// await page.mouse.down();
56/// await page.mouse.move(0, 100);
57/// await page.mouse.move(100, 100);
58/// await page.mouse.move(100, 0);
59/// await page.mouse.move(0, 0);
60/// await page.mouse.up();
61/// ```
62#[derive(Debug, Clone)]
63pub struct Mouse {
64 inner: Weak<PageImpl>
65}
66
67/// The Touchscreen class operates in main-frame CSS pixels relative to the top-left corner of the viewport. Methods on the
68/// touchscreen can only be used in browser contexts that have been initialized with `hasTouch` set to true.
69#[derive(Debug, Clone)]
70pub struct TouchScreen {
71 inner: Weak<PageImpl>
72}
73
74impl Keyboard {
75 pub(crate) fn new(inner: Weak<PageImpl>) -> Self { Self { inner } }
76
77 /// Dispatches a `keydown` event.
78 ///
79 /// `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
80 /// value or a single character to generate the text for. A superset of the `key` values can be found
81 /// [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
82 ///
83 /// `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
84 /// `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
85 ///
86 /// Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
87 ///
88 /// Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
89 ///
90 /// If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
91 /// texts.
92 ///
93 /// If `key` is a modifier key, `Shift`, `Meta`, `Control`, or `Alt`, subsequent key presses will be sent with that modifier
94 /// active. To release the modifier key, use [`method: Keyboard.up`].
95 ///
96 /// After the key is pressed once, subsequent calls to [`method: Keyboard.down`] will have
97 /// [repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat) set to true. To release the key, use
98 /// [`method: Keyboard.up`].
99 ///
100 /// > NOTE: Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
101 pub async fn down(&self, key: &str) -> Result<(), Arc<Error>> {
102 let inner = upgrade(&self.inner)?;
103 inner.key_down(key).await
104 }
105
106 pub async fn up(&self, key: &str) -> Result<(), Arc<Error>> {
107 let inner = upgrade(&self.inner)?;
108 inner.key_up(key).await
109 }
110
111 /// Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
112 ///
113 /// ```js
114 /// page.keyboard.insertText('嗨');
115 /// ```
116 ///
117 ///
118 /// > NOTE: Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
119 pub async fn input_text(&self, text: &str) -> Result<(), Arc<Error>> {
120 let inner = upgrade(&self.inner)?;
121 inner.key_input_text(text).await
122 }
123
124 /// Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
125 ///
126 /// To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.press`].
127 ///
128 /// ```js
129 /// await page.keyboard.type('Hello'); // Types instantly
130 /// await page.keyboard.type('World', {delay: 100}); // Types slower, like a user
131 /// ```
132 ///
133 /// > NOTE: Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
134 /// > NOTE: For characters that are not on a US keyboard, only an `input` event will be sent.
135 pub async fn r#type(&self, text: &str, delay: Option<f64>) -> Result<(), Arc<Error>> {
136 let inner = upgrade(&self.inner)?;
137 inner.key_type(text, delay).await
138 }
139
140 /// Shortcut for [`method: Keyboard.down`] and [`method: Keyboard.up`].
141 pub async fn press(&self, key: &str, delay: Option<f64>) -> Result<(), Arc<Error>> {
142 let inner = upgrade(&self.inner)?;
143 inner.key_press(key, delay).await
144 }
145}
146
147impl Mouse {
148 pub(crate) fn new(inner: Weak<PageImpl>) -> Self { Self { inner } }
149
150 pub async fn r#move(&self, x: f64, y: f64, steps: Option<i32>) -> Result<(), Arc<Error>> {
151 let inner = upgrade(&self.inner)?;
152 inner.mouse_move(x, y, steps).await
153 }
154
155 pub async fn down(
156 &self,
157 button: Option<MouseButton>,
158 click_count: Option<i32>
159 ) -> Result<(), Arc<Error>> {
160 let inner = upgrade(&self.inner)?;
161 inner.mouse_down(button, click_count).await
162 }
163
164 pub async fn up(
165 &self,
166 button: Option<MouseButton>,
167 click_count: Option<i32>
168 ) -> Result<(), Arc<Error>> {
169 let inner = upgrade(&self.inner)?;
170 inner.mouse_up(button, click_count).await
171 }
172
173 /// Shortcut for [`method: Mouse.move`], [`method: Mouse.down`], [`method: Mouse.up`].
174 pub fn click_builder(&self, x: f64, y: f64) -> ClickBuilder {
175 ClickBuilder::new(self.inner.clone(), x, y)
176 }
177
178 /// Shortcut for [`method: Mouse.move`], [`method: Mouse.down`], [`method: Mouse.up`], [`method: Mouse.down`] and
179 /// [`method: Mouse.up`].
180 pub fn dblclick_builder(&self, x: f64, y: f64) -> DblClickBuilder {
181 DblClickBuilder::new(self.inner.clone(), x, y)
182 }
183}
184
185impl TouchScreen {
186 pub(crate) fn new(inner: Weak<PageImpl>) -> Self { Self { inner } }
187
188 pub async fn tap(&self, x: f64, y: f64) -> Result<(), Arc<Error>> {
189 let inner = upgrade(&self.inner)?;
190 inner.screen_tap(x, y).await
191 }
192}
193
194macro_rules! clicker {
195 ($t: ident, $f: ident, $mf: ident) => {
196 pub struct $t {
197 inner: Weak<PageImpl>,
198 args: MouseClickArgs
199 }
200
201 impl $t {
202 pub(crate) fn new(inner: Weak<PageImpl>, x: f64, y: f64) -> Self {
203 let args = MouseClickArgs::new(x, y);
204 Self { inner, args }
205 }
206
207 pub async fn $f(self) -> Result<(), Arc<Error>> {
208 let Self { inner, args } = self;
209 let _ = upgrade(&inner)?.$mf(args).await?;
210 Ok(())
211 }
212
213 setter! {
214 /// Defaults to `left`.
215 button: Option<MouseButton>,
216 /// defaults to 1. See [UIEvent.detail].
217 click_count: Option<i32>,
218 /// Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0.
219 delay: Option<f64>
220 }
221 }
222 };
223}
224
225clicker!(ClickBuilder, click, mouse_click);
226clicker!(DblClickBuilder, dblclick, mouse_dblclick);