Simplify keyboard modifiers handling (#129)

This commit is contained in:
Pavel Feldman 2017-07-25 14:35:03 -07:00 committed by Andrey Lushnikov
parent 0007809305
commit eca0d7fe53
5 changed files with 100 additions and 159 deletions

View File

@ -63,7 +63,6 @@
+ [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options) + [page.waitForSelector(selector[, options])](#pagewaitforselectorselector-options)
* [class: Keyboard](#class-keyboard) * [class: Keyboard](#class-keyboard)
+ [keyboard.down(key[, options])](#keyboarddownkey-options) + [keyboard.down(key[, options])](#keyboarddownkey-options)
+ [keyboard.modifiers()](#keyboardmodifiers)
+ [keyboard.sendCharacter(char)](#keyboardsendcharacterchar) + [keyboard.sendCharacter(char)](#keyboardsendcharacterchar)
+ [keyboard.up(key)](#keyboardupkey) + [keyboard.up(key)](#keyboardupkey)
* [class: Mouse](#class-mouse) * [class: Mouse](#class-mouse)
@ -662,15 +661,6 @@ This will not send input events unless `text` is specified.
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 [`keyboard.up`](#keyboardupkey). 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 [`keyboard.up`](#keyboardupkey).
#### keyboard.modifiers()
- returns: <[Object]>
- `Shift` <[boolean]>
- `Meta` <[boolean]>
- `Control` <[boolean]>
- `Alt` <[boolean]>
Returns which modifier keys are currently active. Use [`keyboard.down`](#keyboarddownkey) to activate a modifier key.
#### keyboard.sendCharacter(char) #### keyboard.sendCharacter(char)
- `char` <[string]> Character to send into the page. - `char` <[string]> Character to send into the page.
- returns: <[Promise]> - returns: <[Promise]>

View File

@ -22,8 +22,7 @@ class Keyboard {
*/ */
constructor(client) { constructor(client) {
this._client = client; this._client = client;
/** @type {!Set<string>} */ this._modifiers = 0;
this._keys = new Set();
} }
/** /**
@ -33,10 +32,10 @@ class Keyboard {
*/ */
async down(key, options) { async down(key, options) {
let {text} = options || {}; let {text} = options || {};
this._keys.add(key); this._modifiers |= this._modifierBit(key);
await this._client.send('Input.dispatchKeyEvent', { await this._client.send('Input.dispatchKeyEvent', {
type: text ? 'keyDown' : 'rawKeyDown', type: text ? 'keyDown' : 'rawKeyDown',
modifiers: this._modifiersMask(), modifiers: this._modifiers,
windowsVirtualKeyCode: codeForKey(key), windowsVirtualKeyCode: codeForKey(key),
key: key, key: key,
text: text, text: text,
@ -45,15 +44,19 @@ class Keyboard {
} }
/** /**
* @param {{Shift: boolean, Alt: boolean, Meta: boolean, Control: boolean}} * @param {string} key
* @return {number}
*/ */
modifiers() { _modifierBit(key) {
return { if (key === 'Alt')
Shift: this._keys.has('Shift'), return 1;
Alt: this._keys.has('Alt'), if (key === 'Control')
Meta: this._keys.has('Meta'), return 2;
Control: this._keys.has('Control') if (key === 'Meta')
}; return 4;
if (key === 'Shift')
return 8;
return 0;
} }
/** /**
@ -61,10 +64,10 @@ class Keyboard {
* @return {!Promise} * @return {!Promise}
*/ */
async up(key) { async up(key) {
this._keys.delete(key); this._modifiers &= ~this._modifierBit(key);
await this._client.send('Input.dispatchKeyEvent', { await this._client.send('Input.dispatchKeyEvent', {
type: 'keyUp', type: 'keyUp',
modifiers: this._modifiersMask(), modifiers: this._modifiers,
key, key,
windowsVirtualKeyCode: codeForKey(key), windowsVirtualKeyCode: codeForKey(key),
}); });
@ -77,27 +80,83 @@ class Keyboard {
async sendCharacter(char) { async sendCharacter(char) {
await this._client.send('Input.dispatchKeyEvent', { await this._client.send('Input.dispatchKeyEvent', {
type: 'char', type: 'char',
modifiers: this._modifiersMask(), modifiers: this._modifiers,
text: char, text: char,
key: char, key: char,
unmodifiedText: 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';
}
/** /**
* @return {number} * @param {number} x
* @param {number} y
* @return {!Promise}
*/ */
_modifiersMask() { async move(x, y) {
let modifiers = 0; this._x = x;
if (this._keys.has('Alt')) this._y = y;
modifiers += 1; await this._client.send('Input.dispatchMouseEvent', {
if (this._keys.has('Control')) type: 'mouseMoved',
modifiers += 2; button: this._button,
if (this._keys.has('Meta')) x, y,
modifiers += 4; modifiers: this._keyboard._modifiers
if (this._keys.has('Shift')) });
modifiers += 8; }
return modifiers;
/**
* @param {!Object=} options
*/
async press(options) {
await this.down(options);
await this.up(options);
}
/**
* @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)
});
}
/**
* @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)
});
} }
} }
@ -216,5 +275,6 @@ function codeForKey(key) {
return 0; return 0;
} }
module.exports = Keyboard; module.exports = {Keyboard, Mouse};
helper.tracePublicAPI(Keyboard); helper.tracePublicAPI(Keyboard);
helper.tracePublicAPI(Mouse);

View File

@ -1,106 +0,0 @@
/**
* 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.
*/
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._modifiersMask()
});
}
/**
* @param {!Object=} options
*/
async press(options) {
await this.down(options);
await this.up(options);
}
/**
* @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._modifiersMask(),
clickCount: (options.clickCount || 1)
});
}
/**
* @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._modifiersMask(),
clickCount: (options.clickCount || 1)
});
}
/**
* @return {number}
*/
_modifiersMask() {
let modifiers = this._keyboard.modifiers();
let mask = 0;
if (modifiers.Alt)
mask += 1;
if (modifiers.Control)
mask += 2;
if (modifiers.Meta)
mask += 4;
if (modifiers.Shift)
mask += 8;
return mask;
}
}
module.exports = Mouse;

View File

@ -22,8 +22,7 @@ let NavigatorWatcher = require('./NavigatorWatcher');
let Dialog = require('./Dialog'); let Dialog = require('./Dialog');
let EmulationManager = require('./EmulationManager'); let EmulationManager = require('./EmulationManager');
let FrameManager = require('./FrameManager'); let FrameManager = require('./FrameManager');
let Keyboard = require('./Keyboard'); let {Keyboard, Mouse} = require('./Input');
let Mouse = require('./Mouse');
let helper = require('./helper'); let helper = require('./helper');
class Page extends EventEmitter { class Page extends EventEmitter {
@ -39,11 +38,11 @@ class Page extends EventEmitter {
client.send('Runtime.enable', {}), client.send('Runtime.enable', {}),
client.send('Security.enable', {}), client.send('Security.enable', {}),
]); ]);
let keyboard = new Keyboard(client); const keyboard = new Keyboard(client);
let mouse = new Mouse(client, keyboard); const mouse = new Mouse(client, keyboard);
let frameManager = await FrameManager.create(client, mouse); const frameManager = await FrameManager.create(client, mouse);
let networkManager = new NetworkManager(client); const networkManager = new NetworkManager(client);
let page = new Page(client, frameManager, networkManager, screenshotTaskQueue, mouse, keyboard); const page = new Page(client, frameManager, networkManager, screenshotTaskQueue, mouse, keyboard);
// Initialize default page size. // Initialize default page size.
await page.setViewport({width: 400, height: 300}); await page.setViewport({width: 400, height: 300});
return page; return page;

View File

@ -888,16 +888,14 @@ describe('Puppeteer', function() {
})); }));
it('keyboard.modifiers()', SX(async function(){ it('keyboard.modifiers()', SX(async function(){
let keyboard = page.keyboard; let keyboard = page.keyboard;
expect(keyboard.modifiers().Shift).toBe(false); expect(keyboard._modifiers).toBe(0);
expect(keyboard.modifiers().Meta).toBe(false);
expect(keyboard.modifiers().Alt).toBe(false);
expect(keyboard.modifiers().Control).toBe(false);
keyboard.down('Shift'); keyboard.down('Shift');
expect(keyboard.modifiers().Shift).toBe(true); expect(keyboard._modifiers).toBe(8);
expect(keyboard.modifiers().Alt).toBe(false); keyboard.down('Alt');
expect(keyboard._modifiers).toBe(9);
keyboard.up('Shift'); keyboard.up('Shift');
expect(keyboard.modifiers().Shift).toBe(false); keyboard.up('Alt');
expect(keyboard.modifiers().Alt).toBe(false); expect(keyboard._modifiers).toBe(0);
})); }));
it('should resize the textarea', SX(async function(){ it('should resize the textarea', SX(async function(){
await page.navigate(PREFIX + '/input/textarea.html'); await page.navigate(PREFIX + '/input/textarea.html');