diff --git a/src/chromium/Input.ts b/src/chromium/Input.ts index eb471725d5..4e3ba3fe21 100644 --- a/src/chromium/Input.ts +++ b/src/chromium/Input.ts @@ -16,7 +16,7 @@ */ import { assert } from '../helper'; -import { Modifier, Button } from '../input'; +import * as input from '../input'; import { keyDefinitions } from '../USKeyboardLayout'; import { CDPSession } from './Connection'; @@ -28,7 +28,7 @@ type KeyDescription = { location: number, }; -const kModifiers: Modifier[] = ['Alt', 'Control', 'Meta', 'Shift']; +const kModifiers: input.Modifier[] = ['Alt', 'Control', 'Meta', 'Shift']; export class Keyboard { private _client: CDPSession; @@ -157,12 +157,12 @@ export class Keyboard { await this.up(key); } - async _ensureModifiers(modifiers: Modifier[]): Promise { + async _ensureModifiers(modifiers: input.Modifier[]): Promise { for (const modifier of modifiers) { if (!kModifiers.includes(modifier)) throw new Error('Uknown modifier ' + modifier); } - const restore: Modifier[] = []; + const restore: input.Modifier[] = []; const promises: Promise[] = []; for (const key of kModifiers) { const needDown = modifiers.includes(key); @@ -179,12 +179,12 @@ export class Keyboard { } } -export class Mouse { +export class Mouse implements input.MouseOperations { private _client: CDPSession; private _keyboard: Keyboard; private _x = 0; private _y = 0; - private _button: 'none' | Button = 'none'; + private _button: 'none' | input.Button = 'none'; constructor(client: CDPSession, keyboard: Keyboard) { this._client = client; @@ -207,75 +207,7 @@ export class Mouse { } } - async click(x: number, y: number, options: { delay?: number; button?: Button; clickCount?: number; } = {}) { - const {delay = null} = options; - if (delay !== null) { - await Promise.all([ - this.move(x, y), - this.down(options), - ]); - await new Promise(f => setTimeout(f, delay)); - await this.up(options); - } else { - await Promise.all([ - this.move(x, y), - this.down(options), - this.up(options), - ]); - } - } - - async dblclick(x: number, y: number, options: { delay?: number; button?: Button; } = {}) { - const { delay = null } = options; - if (delay !== null) { - await this.move(x, y); - await this.down({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 2 }); - } else { - await Promise.all([ - this.move(x, y), - this.down({ ...options, clickCount: 1 }), - this.up({ ...options, clickCount: 1 }), - this.down({ ...options, clickCount: 2 }), - this.up({ ...options, clickCount: 2 }), - ]); - } - } - - async tripleclick(x: number, y: number, options: { delay?: number; button?: Button; } = {}) { - const { delay = null } = options; - if (delay !== null) { - await this.move(x, y); - await this.down({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 3 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 3 }); - } else { - await Promise.all([ - this.move(x, y), - this.down({ ...options, clickCount: 1 }), - this.up({ ...options, clickCount: 1 }), - this.down({ ...options, clickCount: 2 }), - this.up({ ...options, clickCount: 2 }), - this.down({ ...options, clickCount: 3 }), - this.up({ ...options, clickCount: 3 }), - ]); - } - } - - async down(options: { button?: Button; clickCount?: number; } = {}) { + async down(options: { button?: input.Button; clickCount?: number; } = {}) { const {button = 'left', clickCount = 1} = options; this._button = button; await this._client.send('Input.dispatchMouseEvent', { @@ -288,7 +220,7 @@ export class Mouse { }); } - async up(options: { button?: Button; clickCount?: number; } = {}) { + async up(options: { button?: input.Button; clickCount?: number; } = {}) { const {button = 'left', clickCount = 1} = options; this._button = 'none'; await this._client.send('Input.dispatchMouseEvent', { @@ -300,4 +232,16 @@ export class Mouse { clickCount }); } + + async click(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).click(x, y, options); + } + + async dblclick(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).dblclick(x, y, options); + } + + async tripleclick(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).tripleclick(x, y, options); + } } diff --git a/src/firefox/Input.ts b/src/firefox/Input.ts index 238a710624..029e70e27d 100644 --- a/src/firefox/Input.ts +++ b/src/firefox/Input.ts @@ -17,7 +17,7 @@ import { keyDefinitions } from '../USKeyboardLayout'; import { JugglerSession } from './Connection'; -import { Button, ClickOptions, MultiClickOptions } from '../input'; +import * as input from '../input'; interface KeyDescription { keyCode: number; @@ -156,12 +156,13 @@ export class Keyboard { } } -export class Mouse { +export class Mouse implements input.MouseOperations { _client: any; _keyboard: Keyboard; _x: number; _y: number; _buttons: number; + constructor(client, keyboard: Keyboard) { this._client = client; this._keyboard = keyboard; @@ -187,73 +188,6 @@ export class Mouse { } } - async click(x: number, y: number, options: ClickOptions = {}) { - const {delay = null} = options; - if (delay !== null) { - await Promise.all([ - this.move(x, y), - this.down(options), - ]); - await new Promise(f => setTimeout(f, delay)); - await this.up(options); - } else { - await Promise.all([ - this.move(x, y), - this.down(options), - this.up(options), - ]); - } - } - - async dblclick(x: number, y: number, options: MultiClickOptions = {}) { - const { delay = null } = options; - if (delay !== null) { - await this.move(x, y); - await this.down({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 2 }); - } else { - await Promise.all([ - this.move(x, y), - this.down({ ...options, clickCount: 1 }), - this.up({ ...options, clickCount: 1 }), - this.down({ ...options, clickCount: 2 }), - this.up({ ...options, clickCount: 2 }), - ]); - } - } - - async tripleclick(x: number, y: number, options: MultiClickOptions = {}) { - const { delay = null } = options; - if (delay !== null) { - await this.move(x, y); - await this.down({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 1 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 2 }); - await new Promise(f => setTimeout(f, delay)); - await this.down({ ...options, clickCount: 3 }); - await new Promise(f => setTimeout(f, delay)); - await this.up({ ...options, clickCount: 3 }); - } else { - await Promise.all([ - this.move(x, y), - this.down({ ...options, clickCount: 1 }), - this.up({ ...options, clickCount: 1 }), - this.down({ ...options, clickCount: 2 }), - this.up({ ...options, clickCount: 2 }), - this.down({ ...options, clickCount: 3 }), - this.up({ ...options, clickCount: 3 }), - ]); - } - } async down(options: { button?: string; clickCount?: number; } | undefined = {}) { const { button = 'left', @@ -306,4 +240,16 @@ export class Mouse { buttons: this._buttons, }); } + + async click(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).click(x, y, options); + } + + async dblclick(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).dblclick(x, y, options); + } + + async tripleclick(x: number, y: number, options?: input.ClickOptions) { + await new input.MouseClicker(this).tripleclick(x, y, options); + } } diff --git a/src/input.ts b/src/input.ts index 55689a78cc..e8a4a208f2 100644 --- a/src/input.ts +++ b/src/input.ts @@ -1,6 +1,3 @@ -import { assert } from "console"; -import { helper } from "./helper"; - // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. @@ -34,6 +31,88 @@ export type SelectOption = { index?: number; }; +export interface MouseOperations { + move(x: number, y: number, options?: { steps?: number; }): Promise; + down(options?: { button?: Button; clickCount?: number; }): Promise; + up(options?: { button?: Button; clickCount?: number; }): Promise; +} + +export class MouseClicker { + private _operations: MouseOperations; + + constructor(operations: MouseOperations) { + this._operations = operations; + } + + async click(x: number, y: number, options: ClickOptions = {}) { + const {delay = null} = options; + if (delay !== null) { + await Promise.all([ + this._operations.move(x, y), + this._operations.down(options), + ]); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up(options); + } else { + await Promise.all([ + this._operations.move(x, y), + this._operations.down(options), + this._operations.up(options), + ]); + } + } + + async dblclick(x: number, y: number, options: MultiClickOptions = {}) { + const { delay = null } = options; + if (delay !== null) { + await this._operations.move(x, y); + await this._operations.down({ ...options, clickCount: 1 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up({ ...options, clickCount: 1 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.down({ ...options, clickCount: 2 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up({ ...options, clickCount: 2 }); + } else { + await Promise.all([ + this._operations.move(x, y), + this._operations.down({ ...options, clickCount: 1 }), + this._operations.up({ ...options, clickCount: 1 }), + this._operations.down({ ...options, clickCount: 2 }), + this._operations.up({ ...options, clickCount: 2 }), + ]); + } + } + + async tripleclick(x: number, y: number, options: MultiClickOptions = {}) { + const { delay = null } = options; + if (delay !== null) { + await this._operations.move(x, y); + await this._operations.down({ ...options, clickCount: 1 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up({ ...options, clickCount: 1 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.down({ ...options, clickCount: 2 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up({ ...options, clickCount: 2 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.down({ ...options, clickCount: 3 }); + await new Promise(f => setTimeout(f, delay)); + await this._operations.up({ ...options, clickCount: 3 }); + } else { + await Promise.all([ + this._operations.move(x, y), + this._operations.down({ ...options, clickCount: 1 }), + this._operations.up({ ...options, clickCount: 1 }), + this._operations.down({ ...options, clickCount: 2 }), + this._operations.up({ ...options, clickCount: 2 }), + this._operations.down({ ...options, clickCount: 3 }), + this._operations.up({ ...options, clickCount: 3 }), + ]); + } + } +} + export const selectFunction = (element: HTMLSelectElement, ...optionsToSelect: (Node | SelectOption)[]) => { if (element.nodeName.toLowerCase() !== 'select') throw new Error('Element is not a