2017-07-18 01:49:52 +00:00
/ * *
* Copyright 2017 Google Inc . All rights reserved .
*
* Licensed under the Apache License , Version 2.0 ( the 'License' ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an 'AS IS' BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2022-08-17 12:39:41 +00:00
import { assert } from '../util/assert.js' ;
2022-06-22 13:25:44 +00:00
import { CDPSession } from './Connection.js' ;
import { _keyDefinitions , KeyDefinition , KeyInput } from './USKeyboardLayout.js' ;
import { Protocol } from 'devtools-protocol' ;
import { Point } from './JSHandle.js' ;
2017-10-23 19:43:45 +00:00
2020-05-07 10:54:55 +00:00
type KeyDescription = Required <
Pick < KeyDefinition , ' keyCode ' | ' key ' | ' text ' | ' code ' | ' location ' >
> ;
2017-07-19 03:53:00 +00:00
2020-06-25 09:56:55 +00:00
/ * *
* Keyboard provides an api for managing a virtual keyboard .
* The high level api is { @link Keyboard . "type" } ,
* which takes raw characters and generates proper keydown , keypress / input ,
* and keyup events on your page .
*
* @remarks
* For finer control , you can use { @link Keyboard . down } ,
* { @link Keyboard . up } , and { @link Keyboard . sendCharacter }
* to manually fire events as if they were generated from a real keyboard .
*
2022-10-13 16:55:11 +00:00
* On macOS , keyboard shortcuts like ` ⌘ A ` - \ > Select All do not work .
2020-06-25 09:56:55 +00:00
* See { @link https : //github.com/puppeteer/puppeteer/issues/1313 | #1313}.
*
* @example
* An example of holding down ` Shift ` in order to select and delete some text :
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-25 09:56:55 +00:00
* await page . keyboard . type ( 'Hello World!' ) ;
* await page . keyboard . press ( 'ArrowLeft' ) ;
*
* await page . keyboard . down ( 'Shift' ) ;
* for ( let i = 0 ; i < ' World' . length ; i ++ )
* await page . keyboard . press ( 'ArrowLeft' ) ;
* await page . keyboard . up ( 'Shift' ) ;
*
* await page . keyboard . press ( 'Backspace' ) ;
* // Result text will end up saying 'Hello!'
* ` ` `
*
* @example
* An example of pressing ` A `
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-25 09:56:55 +00:00
* await page . keyboard . down ( 'Shift' ) ;
* await page . keyboard . press ( 'KeyA' ) ;
* await page . keyboard . up ( 'Shift' ) ;
* ` ` `
*
* @public
* /
2020-04-22 14:44:04 +00:00
export class Keyboard {
2022-06-13 09:16:25 +00:00
# client : CDPSession ;
# pressedKeys = new Set < string > ( ) ;
/ * *
* @internal
* /
2020-04-22 14:44:04 +00:00
_modifiers = 0 ;
2022-06-13 09:16:25 +00:00
/ * *
* @internal
* /
2020-04-22 14:44:04 +00:00
constructor ( client : CDPSession ) {
2022-06-13 09:16:25 +00:00
this . # client = client ;
2017-07-18 01:49:52 +00:00
}
2020-06-25 09:56:55 +00:00
/ * *
* Dispatches a ` keydown ` event .
*
* @remarks
* If ` key ` is a single character and no modifier keys besides ` Shift `
* are being held down , a ` keypress ` / ` input ` event will also generated .
* The ` text ` option can be specified to force an input event to be generated .
* If ` key ` is a modifier key , ` Shift ` , ` Meta ` , ` Control ` , or ` Alt ` ,
* subsequent key presses will be sent with that modifier active .
* To release the modifier key , use { @link Keyboard . up } .
*
* After the key is pressed once , subsequent calls to
* { @link Keyboard . down } will have
* { @link https : //developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat | repeat}
* set to true . To release the key , use { @link Keyboard . up } .
*
* Modifier keys DO influence { @link Keyboard . down } .
* Holding down ` Shift ` will type the text in upper case .
*
* @param key - Name of key to press , such as ` ArrowLeft ` .
* See { @link KeyInput } for a list of all key names .
*
* @param options - An object of options . Accepts text which , if specified ,
2022-12-03 10:23:47 +00:00
* generates an input event with this text . Accepts commands which , if specified ,
* is the commands of keyboard shortcuts ,
* see { @link https : //source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h | Chromium Source Code} for valid command names.
2020-06-25 09:56:55 +00:00
* /
2020-05-07 10:54:55 +00:00
async down (
key : KeyInput ,
2022-12-03 10:23:47 +00:00
options : { text? : string ; commands? : string [ ] } = {
text : undefined ,
commands : [ ] ,
}
2020-05-07 10:54:55 +00:00
) : Promise < void > {
2022-06-13 09:16:25 +00:00
const description = this . # keyDescriptionForString ( key ) ;
2017-10-23 19:43:45 +00:00
2022-06-13 09:16:25 +00:00
const autoRepeat = this . # pressedKeys . has ( description . code ) ;
this . # pressedKeys . add ( description . code ) ;
this . _modifiers |= this . # modifierBit ( description . key ) ;
2017-10-23 19:43:45 +00:00
const text = options . text === undefined ? description.text : options.text ;
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchKeyEvent' , {
2017-07-18 01:49:52 +00:00
type : text ? 'keyDown' : 'rawKeyDown' ,
2017-07-25 21:35:03 +00:00
modifiers : this._modifiers ,
2017-10-23 19:43:45 +00:00
windowsVirtualKeyCode : description.keyCode ,
code : description.code ,
key : description.key ,
text : text ,
2017-07-31 19:05:46 +00:00
unmodifiedText : text ,
2017-10-23 19:43:45 +00:00
autoRepeat ,
location : description.location ,
2020-05-07 10:54:55 +00:00
isKeypad : description.location === 3 ,
2022-12-03 10:23:47 +00:00
commands : options.commands ,
2017-07-18 01:49:52 +00:00
} ) ;
}
2022-06-13 09:16:25 +00:00
# modifierBit ( key : string ) : number {
2022-06-14 11:55:35 +00:00
if ( key === 'Alt' ) {
return 1 ;
}
if ( key === 'Control' ) {
return 2 ;
}
if ( key === 'Meta' ) {
return 4 ;
}
if ( key === 'Shift' ) {
return 8 ;
}
2017-07-25 21:35:03 +00:00
return 0 ;
2017-07-18 01:49:52 +00:00
}
2022-06-13 09:16:25 +00:00
# keyDescriptionForString ( keyString : KeyInput ) : KeyDescription {
2017-10-23 19:43:45 +00:00
const shift = this . _modifiers & 8 ;
const description = {
key : '' ,
keyCode : 0 ,
code : '' ,
text : '' ,
2020-05-07 10:54:55 +00:00
location : 0 ,
2017-10-23 19:43:45 +00:00
} ;
2022-06-13 09:16:25 +00:00
const definition = _keyDefinitions [ keyString ] ;
2018-05-31 23:53:51 +00:00
assert ( definition , ` Unknown key: " ${ keyString } " ` ) ;
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( definition . key ) {
description . key = definition . key ;
}
if ( shift && definition . shiftKey ) {
description . key = definition . shiftKey ;
}
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( definition . keyCode ) {
description . keyCode = definition . keyCode ;
}
if ( shift && definition . shiftKeyCode ) {
2017-10-23 19:43:45 +00:00
description . keyCode = definition . shiftKeyCode ;
2022-06-14 11:55:35 +00:00
}
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( definition . code ) {
description . code = definition . code ;
}
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( definition . location ) {
description . location = definition . location ;
}
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( description . key . length === 1 ) {
description . text = description . key ;
}
2017-10-23 19:43:45 +00:00
2022-06-14 11:55:35 +00:00
if ( definition . text ) {
description . text = definition . text ;
}
if ( shift && definition . shiftText ) {
description . text = definition . shiftText ;
}
2017-10-23 19:43:45 +00:00
// if any modifiers besides shift are pressed, no text should be sent
2022-06-14 11:55:35 +00:00
if ( this . _modifiers & ~ 8 ) {
description . text = '' ;
}
2017-10-23 19:43:45 +00:00
return description ;
}
2020-06-25 09:56:55 +00:00
/ * *
* Dispatches a ` keyup ` event .
*
* @param key - Name of key to release , such as ` ArrowLeft ` .
* See { @link KeyInput | KeyInput }
* for a list of all key names .
* /
2020-04-22 14:44:04 +00:00
async up ( key : KeyInput ) : Promise < void > {
2022-06-13 09:16:25 +00:00
const description = this . # keyDescriptionForString ( key ) ;
2017-10-23 19:43:45 +00:00
2022-06-13 09:16:25 +00:00
this . _modifiers &= ~ this . # modifierBit ( description . key ) ;
this . # pressedKeys . delete ( description . code ) ;
await this . # client . send ( 'Input.dispatchKeyEvent' , {
2017-07-18 01:49:52 +00:00
type : 'keyUp' ,
2017-07-25 21:35:03 +00:00
modifiers : this._modifiers ,
2017-10-23 19:43:45 +00:00
key : description.key ,
windowsVirtualKeyCode : description.keyCode ,
code : description.code ,
2020-05-07 10:54:55 +00:00
location : description.location ,
2017-07-18 01:49:52 +00:00
} ) ;
}
2020-06-25 09:56:55 +00:00
/ * *
* Dispatches a ` keypress ` and ` input ` event .
* This does not send a ` keydown ` or ` keyup ` event .
*
* @remarks
* Modifier keys DO NOT effect { @link Keyboard . sendCharacter | Keyboard . sendCharacter } .
* Holding down ` Shift ` will not type the text in upper case .
*
* @example
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-25 09:56:55 +00:00
* page . keyboard . sendCharacter ( '嗨' ) ;
* ` ` `
*
* @param char - Character to send into the page .
* /
2020-04-22 14:44:04 +00:00
async sendCharacter ( char : string ) : Promise < void > {
2022-06-22 13:25:44 +00:00
await this . # client . send ( 'Input.insertText' , { text : char } ) ;
2017-07-18 01:49:52 +00:00
}
2017-10-07 07:28:24 +00:00
2020-04-22 14:44:04 +00:00
private charIsKey ( char : string ) : char is KeyInput {
2022-06-13 09:16:25 +00:00
return ! ! _keyDefinitions [ char as KeyInput ] ;
2020-04-22 14:44:04 +00:00
}
2020-06-25 09:56:55 +00:00
/ * *
* Sends a ` keydown ` , ` keypress ` / ` input ` ,
* and ` keyup ` event for each character in the text .
*
* @remarks
* To press a special key , like ` Control ` or ` ArrowDown ` ,
* use { @link Keyboard . press } .
*
* Modifier keys DO NOT effect ` keyboard.type ` .
* Holding down ` Shift ` will not type the text in upper case .
*
* @example
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-25 09:56:55 +00:00
* await page . keyboard . type ( 'Hello' ) ; // Types instantly
* await page . keyboard . type ( 'World' , { delay : 100 } ) ; // Types slower, like a user
* ` ` `
*
* @param text - A text to type into a focused element .
* @param options - An object of options . Accepts delay which ,
* if specified , is the time to wait between ` keydown ` and ` keyup ` in milliseconds .
* Defaults to 0 .
* /
2022-06-22 13:25:44 +00:00
async type ( text : string , options : { delay? : number } = { } ) : Promise < void > {
2022-05-24 14:28:36 +00:00
const delay = options . delay || undefined ;
2017-10-07 07:28:24 +00:00
for ( const char of text ) {
2020-04-22 14:44:04 +00:00
if ( this . charIsKey ( char ) ) {
2022-06-22 13:25:44 +00:00
await this . press ( char , { delay } ) ;
2019-10-21 06:29:56 +00:00
} else {
2022-06-14 11:55:35 +00:00
if ( delay ) {
2022-06-22 13:25:44 +00:00
await new Promise ( f = > {
2022-06-15 10:42:21 +00:00
return setTimeout ( f , delay ) ;
} ) ;
2022-06-14 11:55:35 +00:00
}
2017-10-23 19:43:45 +00:00
await this . sendCharacter ( char ) ;
2019-10-21 06:29:56 +00:00
}
2017-10-07 07:28:24 +00:00
}
}
2020-06-25 09:56:55 +00:00
/ * *
* Shortcut for { @link Keyboard . down }
* and { @link Keyboard . up } .
*
* @remarks
* If ` key ` is a single character and no modifier keys besides ` Shift `
* are being held down , a ` keypress ` / ` input ` event will also generated .
* The ` text ` option can be specified to force an input event to be generated .
*
* Modifier keys DO effect { @link Keyboard . press } .
* Holding down ` Shift ` will type the text in upper case .
*
* @param key - Name of key to press , such as ` ArrowLeft ` .
* See { @link KeyInput } for a list of all key names .
*
* @param options - An object of options . Accepts text which , if specified ,
* generates an input event with this text . Accepts delay which ,
* if specified , is the time to wait between ` keydown ` and ` keyup ` in milliseconds .
2022-12-03 10:23:47 +00:00
* Defaults to 0 . Accepts commands which , if specified ,
* is the commands of keyboard shortcuts ,
* see { @link https : //source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/editing/commands/editor_command_names.h | Chromium Source Code} for valid command names.
2020-06-25 09:56:55 +00:00
* /
2020-05-07 10:54:55 +00:00
async press (
key : KeyInput ,
2022-12-03 10:23:47 +00:00
options : { delay? : number ; text? : string ; commands? : string [ ] } = { }
2020-05-07 10:54:55 +00:00
) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { delay = null } = options ;
2017-10-07 07:28:24 +00:00
await this . down ( key , options ) ;
2022-06-14 11:55:35 +00:00
if ( delay ) {
2022-06-22 13:25:44 +00:00
await new Promise ( f = > {
2022-06-15 10:42:21 +00:00
return setTimeout ( f , options . delay ) ;
} ) ;
2022-06-14 11:55:35 +00:00
}
2017-10-07 07:28:24 +00:00
await this . up ( key ) ;
}
2017-07-25 21:35:03 +00:00
}
2017-07-18 01:49:52 +00:00
2020-07-02 11:15:39 +00:00
/ * *
* @public
* /
2022-04-27 21:00:07 +00:00
export type MouseButton = 'left' | 'right' | 'middle' | 'back' | 'forward' ;
2020-04-22 14:44:04 +00:00
2020-07-02 11:15:39 +00:00
/ * *
* @public
* /
export interface MouseOptions {
button? : MouseButton ;
2020-04-22 14:44:04 +00:00
clickCount? : number ;
}
2020-07-06 07:27:17 +00:00
/ * *
* @public
* /
export interface MouseWheelOptions {
deltaX? : number ;
deltaY? : number ;
}
2020-06-24 09:00:13 +00:00
/ * *
* The Mouse class operates in main - frame CSS pixels
* relative to the top - left corner of the viewport .
* @remarks
* Every ` page ` object has its own Mouse , accessible with [ ` page.mouse ` ] ( # pagemouse ) .
*
* @example
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-24 09:00:13 +00:00
* // Using ‘ page.mouse’ to trace a 100x100 square.
* await page . mouse . move ( 0 , 0 ) ;
* await page . mouse . down ( ) ;
* await page . mouse . move ( 0 , 100 ) ;
* await page . mouse . move ( 100 , 100 ) ;
* await page . mouse . move ( 100 , 0 ) ;
* await page . mouse . move ( 0 , 0 ) ;
* await page . mouse . up ( ) ;
* ` ` `
*
* * * Note * * : The mouse events trigger synthetic ` MouseEvent ` s .
* This means that it does not fully replicate the functionality of what a normal user
* would be able to do with their mouse .
*
* For example , dragging and selecting text is not possible using ` page.mouse ` .
* Instead , you can use the { @link https : //developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/getSelection | `DocumentOrShadowRoot.getSelection()`} functionality implemented in the platform.
*
* @example
* For example , if you want to select all content between nodes :
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2022-08-12 12:15:26 +00:00
* await page . evaluate (
* ( from , to ) = > {
* const selection = from . getRootNode ( ) . getSelection ( ) ;
* const range = document . createRange ( ) ;
* range . setStartBefore ( from ) ;
* range . setEndAfter ( to ) ;
* selection . removeAllRanges ( ) ;
* selection . addRange ( range ) ;
* } ,
* fromJSHandle ,
* toJSHandle
* ) ;
2020-06-24 09:00:13 +00:00
* ` ` `
2022-08-12 12:15:26 +00:00
*
2020-06-24 09:00:13 +00:00
* If you then would want to copy - paste your selection , you can use the clipboard api :
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2020-06-24 09:00:13 +00:00
* // The clipboard api does not allow you to copy, unless the tab is focused.
* await page . bringToFront ( ) ;
* await page . evaluate ( ( ) = > {
* // Copy the selected content to the clipboard
* document . execCommand ( 'copy' ) ;
* // Obtain the content of the clipboard as a string
* return navigator . clipboard . readText ( ) ;
* } ) ;
* ` ` `
2022-08-12 12:15:26 +00:00
*
2020-06-24 09:00:13 +00:00
* * * Note * * : If you want access to the clipboard API ,
* you have to give it permission to do so :
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2022-08-12 12:15:26 +00:00
* await browser
* . defaultBrowserContext ( )
* . overridePermissions ( '<your origin>' , [
* 'clipboard-read' ,
* 'clipboard-write' ,
* ] ) ;
2020-06-24 09:00:13 +00:00
* ` ` `
2022-08-12 12:15:26 +00:00
*
2020-06-24 09:00:13 +00:00
* @public
* /
2020-04-22 14:44:04 +00:00
export class Mouse {
2022-06-13 09:16:25 +00:00
# client : CDPSession ;
# keyboard : Keyboard ;
# x = 0 ;
# y = 0 ;
# button : MouseButton | 'none' = 'none' ;
2020-07-02 11:15:39 +00:00
2017-07-18 01:49:52 +00:00
/ * *
2020-06-24 09:00:13 +00:00
* @internal
2017-07-25 21:35:03 +00:00
* /
2020-04-22 14:44:04 +00:00
constructor ( client : CDPSession , keyboard : Keyboard ) {
2022-06-13 09:16:25 +00:00
this . # client = client ;
this . # keyboard = keyboard ;
2017-07-25 21:35:03 +00:00
}
2020-06-24 09:00:13 +00:00
/ * *
* Dispatches a ` mousemove ` event .
* @param x - Horizontal position of the mouse .
* @param y - Vertical position of the mouse .
* @param options - Optional object . If specified , the ` steps ` property
* sends intermediate ` mousemove ` events when set to ` 1 ` ( default ) .
* /
2020-05-07 10:54:55 +00:00
async move (
x : number ,
y : number ,
2022-06-22 13:25:44 +00:00
options : { steps? : number } = { }
2020-05-07 10:54:55 +00:00
) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { steps = 1 } = options ;
2022-06-13 09:16:25 +00:00
const fromX = this . # x ,
fromY = this . # y ;
this . # x = x ;
this . # y = y ;
2017-08-29 21:13:38 +00:00
for ( let i = 1 ; i <= steps ; i ++ ) {
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchMouseEvent' , {
2017-08-29 21:13:38 +00:00
type : 'mouseMoved' ,
2022-06-13 09:16:25 +00:00
button : this. # button ,
x : fromX + ( this . # x - fromX ) * ( i / steps ) ,
y : fromY + ( this . # y - fromY ) * ( i / steps ) ,
modifiers : this. # keyboard . _modifiers ,
2017-08-29 21:13:38 +00:00
} ) ;
}
2017-07-25 21:35:03 +00:00
}
2020-06-24 09:00:13 +00:00
/ * *
* Shortcut for ` mouse.move ` , ` mouse.down ` and ` mouse.up ` .
* @param x - Horizontal position of the mouse .
* @param y - Vertical position of the mouse .
* @param options - Optional ` MouseOptions ` .
* /
2020-05-07 10:54:55 +00:00
async click (
x : number ,
y : number ,
2022-06-22 13:25:44 +00:00
options : MouseOptions & { delay? : number } = { }
2020-05-07 10:54:55 +00:00
) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { delay = null } = options ;
2019-06-10 08:42:19 +00:00
if ( delay !== null ) {
2021-04-19 07:04:37 +00:00
await this . move ( x , y ) ;
await this . down ( options ) ;
2022-06-22 13:25:44 +00:00
await new Promise ( f = > {
2022-06-15 10:42:21 +00:00
return setTimeout ( f , delay ) ;
} ) ;
2019-06-10 08:42:19 +00:00
await this . up ( options ) ;
} else {
2021-04-19 07:04:37 +00:00
await this . move ( x , y ) ;
await this . down ( options ) ;
await this . up ( options ) ;
2019-06-10 08:42:19 +00:00
}
2017-07-26 00:03:13 +00:00
}
2020-06-24 09:00:13 +00:00
/ * *
* Dispatches a ` mousedown ` event .
* @param options - Optional ` MouseOptions ` .
* /
2020-04-22 14:44:04 +00:00
async down ( options : MouseOptions = { } ) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { button = 'left' , clickCount = 1 } = options ;
2022-06-13 09:16:25 +00:00
this . # button = button ;
await this . # client . send ( 'Input.dispatchMouseEvent' , {
2017-07-25 21:35:03 +00:00
type : 'mousePressed' ,
2018-11-12 20:59:21 +00:00
button ,
2022-06-13 09:16:25 +00:00
x : this. # x ,
y : this. # y ,
modifiers : this. # keyboard . _modifiers ,
2020-05-07 10:54:55 +00:00
clickCount ,
2017-07-25 21:35:03 +00:00
} ) ;
}
/ * *
2020-06-24 09:00:13 +00:00
* Dispatches a ` mouseup ` event .
* @param options - Optional ` MouseOptions ` .
2017-07-25 21:35:03 +00:00
* /
2020-04-22 14:44:04 +00:00
async up ( options : MouseOptions = { } ) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { button = 'left' , clickCount = 1 } = options ;
2022-06-13 09:16:25 +00:00
this . # button = 'none' ;
await this . # client . send ( 'Input.dispatchMouseEvent' , {
2017-07-25 21:35:03 +00:00
type : 'mouseReleased' ,
2018-11-12 20:59:21 +00:00
button ,
2022-06-13 09:16:25 +00:00
x : this. # x ,
y : this. # y ,
modifiers : this. # keyboard . _modifiers ,
2020-05-07 10:54:55 +00:00
clickCount ,
2017-07-25 21:35:03 +00:00
} ) ;
2017-07-18 01:49:52 +00:00
}
2020-07-06 07:27:17 +00:00
/ * *
* Dispatches a ` mousewheel ` event .
* @param options - Optional : ` MouseWheelOptions ` .
*
* @example
* An example of zooming into an element :
2022-08-12 12:15:26 +00:00
*
2022-07-01 11:52:39 +00:00
* ` ` ` ts
2022-08-12 12:15:26 +00:00
* await page . goto (
* 'https://mdn.mozillademos.org/en-US/docs/Web/API/Element/wheel_event$samples/Scaling_an_element_via_the_wheel?revision=1587366'
* ) ;
2020-07-06 07:27:17 +00:00
*
* const elem = await page . $ ( 'div' ) ;
* const boundingBox = await elem . boundingBox ( ) ;
* await page . mouse . move (
* boundingBox . x + boundingBox . width / 2 ,
* boundingBox . y + boundingBox . height / 2
* ) ;
*
2022-08-12 12:15:26 +00:00
* await page . mouse . wheel ( { deltaY : - 100 } ) ;
2020-07-06 07:27:17 +00:00
* ` ` `
* /
async wheel ( options : MouseWheelOptions = { } ) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { deltaX = 0 , deltaY = 0 } = options ;
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchMouseEvent' , {
2020-07-06 07:27:17 +00:00
type : 'mouseWheel' ,
2022-06-13 09:16:25 +00:00
x : this. # x ,
y : this. # y ,
2020-07-06 07:27:17 +00:00
deltaX ,
deltaY ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2020-07-06 07:27:17 +00:00
pointerType : 'mouse' ,
} ) ;
}
2021-06-04 10:25:36 +00:00
/ * *
* Dispatches a ` drag ` event .
* @param start - starting point for drag
* @param target - point to drag to
* /
async drag ( start : Point , target : Point ) : Promise < Protocol.Input.DragData > {
2022-06-22 13:25:44 +00:00
const promise = new Promise < Protocol.Input.DragData > ( resolve = > {
this . # client . once ( 'Input.dragIntercepted' , event = > {
2022-06-15 10:42:21 +00:00
return resolve ( event . data ) ;
} ) ;
2021-06-04 10:25:36 +00:00
} ) ;
await this . move ( start . x , start . y ) ;
await this . down ( ) ;
await this . move ( target . x , target . y ) ;
return promise ;
}
/ * *
* Dispatches a ` dragenter ` event .
* @param target - point for emitting ` dragenter ` event
2021-10-02 09:01:44 +00:00
* @param data - drag data containing items and operations mask
2021-06-04 10:25:36 +00:00
* /
async dragEnter ( target : Point , data : Protocol.Input.DragData ) : Promise < void > {
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchDragEvent' , {
2021-06-04 10:25:36 +00:00
type : 'dragEnter' ,
x : target.x ,
y : target.y ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2021-06-04 10:25:36 +00:00
data ,
} ) ;
}
/ * *
* Dispatches a ` dragover ` event .
* @param target - point for emitting ` dragover ` event
2021-10-02 09:01:44 +00:00
* @param data - drag data containing items and operations mask
2021-06-04 10:25:36 +00:00
* /
async dragOver ( target : Point , data : Protocol.Input.DragData ) : Promise < void > {
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchDragEvent' , {
2021-06-04 10:25:36 +00:00
type : 'dragOver' ,
x : target.x ,
y : target.y ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2021-06-04 10:25:36 +00:00
data ,
} ) ;
}
/ * *
* Performs a dragenter , dragover , and drop in sequence .
* @param target - point to drop on
* @param data - drag data containing items and operations mask
* /
async drop ( target : Point , data : Protocol.Input.DragData ) : Promise < void > {
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchDragEvent' , {
2021-06-04 10:25:36 +00:00
type : 'drop' ,
x : target.x ,
y : target.y ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2021-06-04 10:25:36 +00:00
data ,
} ) ;
}
/ * *
* Performs a drag , dragenter , dragover , and drop in sequence .
2022-10-05 12:17:03 +00:00
* @param start - point to drag from
2021-06-04 10:25:36 +00:00
* @param target - point to drop on
* @param options - An object of options . Accepts delay which ,
* if specified , is the time to wait between ` dragover ` and ` drop ` in milliseconds .
* Defaults to 0 .
* /
async dragAndDrop (
start : Point ,
target : Point ,
2022-06-22 13:25:44 +00:00
options : { delay? : number } = { }
2021-06-04 10:25:36 +00:00
) : Promise < void > {
2022-06-22 13:25:44 +00:00
const { delay = null } = options ;
2021-06-04 10:25:36 +00:00
const data = await this . drag ( start , target ) ;
await this . dragEnter ( target , data ) ;
await this . dragOver ( target , data ) ;
if ( delay ) {
2022-06-22 13:25:44 +00:00
await new Promise ( resolve = > {
2022-06-15 10:42:21 +00:00
return setTimeout ( resolve , delay ) ;
} ) ;
2021-06-04 10:25:36 +00:00
}
await this . drop ( target , data ) ;
await this . up ( ) ;
}
2017-07-18 01:49:52 +00:00
}
2020-06-24 08:34:37 +00:00
/ * *
* The Touchscreen class exposes touchscreen events .
2020-07-02 11:15:39 +00:00
* @public
2020-06-24 08:34:37 +00:00
* /
2020-04-22 14:44:04 +00:00
export class Touchscreen {
2022-06-13 09:16:25 +00:00
# client : CDPSession ;
# keyboard : Keyboard ;
2020-04-22 14:44:04 +00:00
2020-06-24 08:34:37 +00:00
/ * *
* @internal
* /
2020-04-22 14:44:04 +00:00
constructor ( client : CDPSession , keyboard : Keyboard ) {
2022-06-13 09:16:25 +00:00
this . # client = client ;
this . # keyboard = keyboard ;
2017-09-02 02:03:51 +00:00
}
/ * *
2020-06-24 08:34:37 +00:00
* Dispatches a ` touchstart ` and ` touchend ` event .
* @param x - Horizontal position of the tap .
* @param y - Vertical position of the tap .
2017-09-02 02:03:51 +00:00
* /
2020-04-22 14:44:04 +00:00
async tap ( x : number , y : number ) : Promise < void > {
2022-06-22 13:25:44 +00:00
const touchPoints = [ { x : Math.round ( x ) , y : Math.round ( y ) } ] ;
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchTouchEvent' , {
2017-09-02 02:03:51 +00:00
type : 'touchStart' ,
touchPoints ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2017-09-02 02:03:51 +00:00
} ) ;
2022-06-13 09:16:25 +00:00
await this . # client . send ( 'Input.dispatchTouchEvent' , {
2017-09-02 02:03:51 +00:00
type : 'touchEnd' ,
touchPoints : [ ] ,
2022-06-13 09:16:25 +00:00
modifiers : this. # keyboard . _modifiers ,
2017-09-02 02:03:51 +00:00
} ) ;
}
}