From 8c7288f64006b3c44b5c3c7dd1bc12d339d7c75f Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Sun, 18 Feb 2024 12:44:22 +0100 Subject: [PATCH] fix: Perform click action when necessary (#240) --- lib/commands/gestures.js | 16 +++++--- lib/commands/winapi/user32.js | 74 ++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/lib/commands/gestures.js b/lib/commands/gestures.js index a210642..769a254 100644 --- a/lib/commands/gestures.js +++ b/lib/commands/gestures.js @@ -300,11 +300,13 @@ commands.windowsClick = async function windowsClick (opts) { const [absoluteX, absoluteY] = await toAbsoluteCoordinates.bind(this)(elementId, x, y); let clickDownInput; let clickUpInput; + let clickInput; let moveInput; try { - [clickDownInput, clickUpInput, moveInput] = await B.all([ + [clickDownInput, clickUpInput, clickInput, moveInput] = await B.all([ toMouseButtonInput({button, action: MOUSE_BUTTON_ACTION.DOWN}), toMouseButtonInput({button, action: MOUSE_BUTTON_ACTION.UP}), + toMouseButtonInput({button, action: MOUSE_BUTTON_ACTION.CLICK}), toMouseMoveInput({x: absoluteX, y: absoluteY}), ]); } catch (e) { @@ -316,13 +318,17 @@ commands.windowsClick = async function windowsClick (opts) { await handleInputs(modifierKeyDownInputs); } await handleInputs(moveInput); + const hasDuration = _.isInteger(durationMs) && durationMs > 0; + const hasInterClickDelay = _.isInteger(interClickDelayMs) && interClickDelayMs > 0; for (let i = 0; i < times; ++i) { - await handleInputs(clickDownInput); - if (_.isInteger(durationMs) && durationMs > 0) { + if (hasDuration) { + await handleInputs(clickDownInput); await B.delay(durationMs); + await handleInputs(clickUpInput); + } else { + await handleInputs(clickInput); } - await handleInputs(clickUpInput); - if (_.isInteger(interClickDelayMs) && interClickDelayMs > 0) { + if (hasInterClickDelay) { await B.delay(interClickDelayMs); } } diff --git a/lib/commands/winapi/user32.js b/lib/commands/winapi/user32.js index 2a73a42..2f9a2ca 100644 --- a/lib/commands/winapi/user32.js +++ b/lib/commands/winapi/user32.js @@ -140,6 +140,8 @@ export const MOUSE_BUTTON = Object.freeze({ export const MOUSE_BUTTON_ACTION = Object.freeze({ UP: 'up', DOWN: 'down', + // This action is an intenal one + CLICK: 'click', }); const MOUSEEVENTF_MOVE = 0x0001; const MOUSEEVENTF_LEFTDOWN = 0x0002; @@ -230,8 +232,8 @@ function createMouseInput (params = {}) { /** * @typedef {Object} MouseButtonOptions - * @property {'left' | 'middle' | 'right' | 'back' | 'forward'} button The desired button name to click - * @property {'up' | 'down'} action The desired button action + * @property {typeof MOUSE_BUTTON[keyof typeof MOUSE_BUTTON]} button The desired button name to click + * @property {typeof MOUSE_BUTTON_ACTION[keyof typeof MOUSE_BUTTON_ACTION]} action The desired button action */ /** @@ -243,18 +245,6 @@ function createMouseInput (params = {}) { * @throws {Error} If the input data is invalid */ export async function toMouseButtonInput({button, action}) { - let down = true; - switch (_.toLower(action)) { - case MOUSE_BUTTON_ACTION.UP: - down = false; - break; - case MOUSE_BUTTON_ACTION.DOWN: - break; - default: - throw createInvalidArgumentError(`Mouse button action '${action}' is unknown. ` + - `Only ${_.values(MOUSE_BUTTON_ACTION)} actions are supported`); - } - // If the host is configured to swap left & right buttons, inject swapped // events to un-do that re-mapping. if (await isLeftMouseButtonSwapped()) { @@ -264,34 +254,56 @@ export async function toMouseButtonInput({button, action}) { button = MOUSE_BUTTON.LEFT; } } + + let evtDown; + let evtUp; + let mouseData; switch (_.toLower(button)) { case MOUSE_BUTTON.LEFT: - return createMouseInput({ - dwFlags: down ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP, - }); + [evtDown, evtUp] = [MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP]; + break; case MOUSE_BUTTON.RIGHT: - return createMouseInput({ - dwFlags: down ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP, - }); + [evtDown, evtUp] = [MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP]; + break; case MOUSE_BUTTON.MIDDLE: - return createMouseInput({ - dwFlags: down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP, - }); + [evtDown, evtUp] = [MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP]; + break; case MOUSE_BUTTON.BACK: - return createMouseInput({ - dwFlags: down ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP, - mouseData: XBUTTON1, - }); + [evtDown, evtUp] = [MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP]; + mouseData = XBUTTON1; + break; case MOUSE_BUTTON.FORWARD: - return createMouseInput({ - dwFlags: down ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP, - mouseData: XBUTTON2, - }); + [evtDown, evtUp] = [MOUSEEVENTF_XDOWN, MOUSEEVENTF_XUP]; + mouseData = XBUTTON2; + break; default: throw createInvalidArgumentError( `Mouse button '${button}' is unknown. Only ${_.values(MOUSE_BUTTON)} buttons are supported` ); } + + let dwFlags; + switch (_.toLower(action)) { + case MOUSE_BUTTON_ACTION.UP: + dwFlags = evtUp; + break; + case MOUSE_BUTTON_ACTION.DOWN: + dwFlags = evtDown; + break; + case MOUSE_BUTTON_ACTION.CLICK: + dwFlags = evtDown | evtUp; + break; + default: + throw createInvalidArgumentError( + `Mouse button action '${action}' is unknown. ` + + `Only ${[MOUSE_BUTTON_ACTION.UP, MOUSE_BUTTON_ACTION.DOWN]} actions are supported` + ); + } + + return createMouseInput({ + dwFlags, + ...(_.isNil(mouseData) ? {} : {mouseData}), + }); } function clamp (num, min, max) {