diff options
Diffstat (limited to '')
-rw-r--r-- | remote/cdp/domains/parent/Input.sys.mjs | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/remote/cdp/domains/parent/Input.sys.mjs b/remote/cdp/domains/parent/Input.sys.mjs new file mode 100644 index 0000000000..4121298d50 --- /dev/null +++ b/remote/cdp/domains/parent/Input.sys.mjs @@ -0,0 +1,168 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { Domain } from "chrome://remote/content/cdp/domains/Domain.sys.mjs"; + +export class Input extends Domain { + // commands + + /** + * Simulate key events. + * + * @param {object} options + * - autoRepeat (not supported) + * - code (not supported) + * - key + * - isKeypad (not supported) + * - location (not supported) + * - modifiers + * - text (not supported) + * - type + * - unmodifiedText (not supported) + * - windowsVirtualKeyCode + * - nativeVirtualKeyCode (not supported) + * - keyIdentifier (not supported) + * - isSystemKey (not supported) + */ + async dispatchKeyEvent(options = {}) { + // missing code, text, unmodifiedText, autorepeat, location, iskeypad + const { key, modifiers, type, windowsVirtualKeyCode } = options; + const { alt, ctrl, meta, shift } = Input.Modifier; + + let domType; + if (type == "keyDown" || type == "rawKeyDown") { + // 'rawKeyDown' is passed as type by puppeteer for all non-text keydown events: + // See https://github.com/GoogleChrome/puppeteer/blob/2d99d85976dcb28cc6e3bad4b6a00cd61a67a2cf/lib/Input.js#L52 + // For now we simply map rawKeyDown to keydown. + domType = "keydown"; + } else if (type == "keyUp" || type == "char") { + // 'char' is fired as a single key event. Behind the scenes it will trigger keydown, + // keypress and keyup. `domType` will only be used as the event to wait for. + domType = "keyup"; + } else { + throw new Error(`Unknown key event type ${type}`); + } + + const { browser } = this.session.target; + const browserWindow = browser.ownerGlobal; + + const EventUtils = this._getEventUtils(browserWindow); + const eventId = await this.executeInChild( + "_addContentEventListener", + domType + ); + + if (type == "char") { + // type == "char" is used when doing `await page.keyboard.type( 'I’m a list' );` + // the ’ character will be calling dispatchKeyEvent only once with type=char. + EventUtils.synthesizeKey(key, {}, browserWindow); + } else { + // Non printable keys should be prefixed with `KEY_` + const eventUtilsKey = key.length == 1 ? key : "KEY_" + key; + const eventInfo = { + keyCode: windowsVirtualKeyCode, + type: domType, + altKey: !!(modifiers & alt), + ctrlKey: !!(modifiers & ctrl), + metaKey: !!(modifiers & meta), + shiftKey: !!(modifiers & shift), + }; + EventUtils.synthesizeKey(eventUtilsKey, eventInfo, browserWindow); + } + + await this.executeInChild("_waitForContentEvent", eventId); + } + + /** + * Simulate mouse events. + * + * @param {object} options + * @param {string} options.type + * @param {number} options.x + * @param {number} options.y + * @param {number} options.modifiers + * @param {number} options.timestamp [Not Supported] + * @param {string} options.button + * @param {number} options.buttons [Not Supported] + * @param {string} options.clickCount + * @param {number} options.deltaX [Not Supported] + * @param {number} options.deltaY [Not Supported] + * @param {string} options.pointerType [Not Supported] + */ + async dispatchMouseEvent(options = {}) { + const { button, clickCount, modifiers, type, x, y } = options; + const { alt, ctrl, meta, shift } = Input.Modifier; + + let domType; + if (type === "mousePressed") { + domType = "mousedown"; + } else if (type === "mouseReleased") { + domType = "mouseup"; + } else if (type === "mouseMoved") { + domType = "mousemove"; + } else { + throw new Error(`Mouse type is not supported: ${type}`); + } + + if (domType === "mousedown" && button === "right") { + domType = "contextmenu"; + } + + const buttonID = Input.Button[button] || Input.Button.left; + const { browser } = this.session.target; + const currentWindow = browser.ownerGlobal; + + const EventUtils = this._getEventUtils(currentWindow); + const eventId = await this.executeInChild( + "_addContentEventListener", + domType + ); + + EventUtils.synthesizeMouse(browser, x, y, { + type: domType, + button: buttonID, + clickCount: clickCount || 1, + altKey: !!(modifiers & alt), + ctrlKey: !!(modifiers & ctrl), + metaKey: !!(modifiers & meta), + shiftKey: !!(modifiers & shift), + }); + + await this.executeInChild("_waitForContentEvent", eventId); + } + + /** + * Memoized EventUtils getter. + */ + _getEventUtils(win) { + if (!this._eventUtils) { + this._eventUtils = { + window: win, + parent: win, + _EU_Ci: Ci, + _EU_Cc: Cc, + }; + Services.scriptloader.loadSubScript( + "chrome://remote/content/external/EventUtils.js", + this._eventUtils + ); + } + return this._eventUtils; + } +} + +Input.Button = { + left: 0, + middle: 1, + right: 2, + back: 3, + forward: 4, +}; + +Input.Modifier = { + alt: 1, + ctrl: 2, + meta: 4, + shift: 8, +}; |