puppeteer/lib/Input.js

307 lines
6.1 KiB
JavaScript
Raw Normal View History

/**
* 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.
*/
const helper = require('./helper');
class Keyboard {
/**
* @param {!Connection} client
*/
constructor(client) {
this._client = client;
this._modifiers = 0;
this._pressedKeys = new Set();
}
/**
* @param {string} key
* @param {{text: (string|undefined)}} options
* @return {!Promise}
*/
async down(key, options) {
let {text} = options || {};
let autoRepeat = this._pressedKeys.has(key);
this._pressedKeys.add(key);
this._modifiers |= this._modifierBit(key);
await this._client.send('Input.dispatchKeyEvent', {
type: text ? 'keyDown' : 'rawKeyDown',
modifiers: this._modifiers,
windowsVirtualKeyCode: codeForKey(key),
key: key,
text: text,
unmodifiedText: text,
autoRepeat
});
}
/**
* @param {string} key
* @return {number}
*/
_modifierBit(key) {
if (key === 'Alt')
return 1;
if (key === 'Control')
return 2;
if (key === 'Meta')
return 4;
if (key === 'Shift')
return 8;
return 0;
}
/**
* @param {string} key
* @return {!Promise}
*/
async up(key) {
this._modifiers &= ~this._modifierBit(key);
this._pressedKeys.delete(key);
await this._client.send('Input.dispatchKeyEvent', {
type: 'keyUp',
modifiers: this._modifiers,
key,
windowsVirtualKeyCode: codeForKey(key),
});
}
/**
* @param {string} char
* @return {!Promise}
*/
async sendCharacter(char) {
await this._client.send('Input.dispatchKeyEvent', {
type: 'char',
modifiers: this._modifiers,
text: char,
key: char,
unmodifiedText: char
});
}
}
class Mouse {
/**
* @param {!Connection} client
* @param {!Keyboard} keyboard
*/
constructor(client, keyboard) {
this._client = client;
this._keyboard = keyboard;
this._x = 0;
this._y = 0;
this._button = 'none';
}
/**
* @param {number} x
* @param {number} y
* @return {!Promise}
*/
async move(x, y) {
this._x = x;
this._y = y;
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseMoved',
button: this._button,
x, y,
modifiers: this._keyboard._modifiers
});
await this._doubleRaf();
}
/**
* @param {number} x
* @param {number} y
* @param {!Object=} options
*/
async click(x, y, options) {
this.move(x, y);
this.down(options);
if (options && options.delay)
await new Promise(f => setTimeout(f, options.delay));
await this.up(options);
}
async _doubleRaf() {
// This is a hack for now, to make clicking less race-prone. See crbug.com/747647
await this._client.send('Runtime.evaluate', {
expression: 'new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))',
awaitPromise: true,
returnByValue: true
});
}
/**
* @param {!Object=} options
*/
async down(options) {
if (!options)
options = {};
this._button = (options.button || 'left');
await this._client.send('Input.dispatchMouseEvent', {
type: 'mousePressed',
button: this._button,
x: this._x,
y: this._y,
modifiers: this._keyboard._modifiers,
clickCount: (options.clickCount || 1)
});
await this._doubleRaf();
}
/**
* @param {!Object=} options
*/
async up(options) {
if (!options)
options = {};
this._button = 'none';
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseReleased',
button: (options.button || 'left'),
x: this._x,
y: this._y,
modifiers: this._keyboard._modifiers,
clickCount: (options.clickCount || 1)
});
await this._doubleRaf();
}
}
let keys = {
'Cancel': 3,
'Help': 6,
'Backspace': 8,
'Tab': 9,
'Clear': 12,
'Enter': 13,
'Shift': 16,
'Control': 17,
'Alt': 18,
'Pause': 19,
'CapsLock': 20,
'Escape': 27,
'Convert': 28,
'NonConvert': 29,
'Accept': 30,
'ModeChange': 31,
'PageUp': 33,
'PageDown': 34,
'End': 35,
'Home': 36,
'ArrowLeft': 37,
'ArrowUp': 38,
'ArrowRight': 39,
'ArrowDown': 40,
'Select': 41,
'Print': 42,
'Execute': 43,
'PrintScreen': 44,
'Insert': 45,
'Delete': 46,
')': 48,
'!': 49,
'@': 50,
'#': 51,
'$': 52,
'%': 53,
'^': 54,
'&': 55,
'*': 56,
'(': 57,
'Meta': 91,
'ContextMenu': 93,
'F1': 112,
'F2': 113,
'F3': 114,
'F4': 115,
'F5': 116,
'F6': 117,
'F7': 118,
'F8': 119,
'F9': 120,
'F10': 121,
'F11': 122,
'F12': 123,
'F13': 124,
'F14': 125,
'F15': 126,
'F16': 127,
'F17': 128,
'F18': 129,
'F19': 130,
'F20': 131,
'F21': 132,
'F22': 133,
'F23': 134,
'F24': 135,
'NumLock': 144,
'ScrollLock': 145,
'AudioVolumeMute': 173,
'AudioVolumeDown': 174,
'AudioVolumeUp': 175,
'MediaTrackNext': 176,
'MediaTrackPrevious': 177,
'MediaStop': 178,
'MediaPlayPause': 179,
';': 186,
':': 186,
'=': 187,
'+': 187,
',': 188,
'<': 188,
'-': 189,
'_': 189,
'.': 190,
'>': 190,
'/': 191,
'?': 191,
'`': 192,
'~': 192,
'[': 219,
'{': 219,
'\\': 220,
'|': 220,
']': 221,
'}': 221,
'\'': 222,
'"': 222,
'AltGraph': 225,
'Attn': 246,
'CrSel': 247,
'ExSel': 248,
'EraseEof': 249,
'Play': 250,
'ZoomOut': 251
};
/**
* @param {string} key
* @return {number}
*/
function codeForKey(key) {
if (keys[key])
return keys[key];
if (key.length === 1)
return key.toUpperCase().charCodeAt(0);
return 0;
}
module.exports = { Keyboard, Mouse };
helper.tracePublicAPI(Keyboard);
helper.tracePublicAPI(Mouse);