Skip to content

Commit

Permalink
chore: Optimize screen size calculation for mouse gestures emulation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mykola-mokhnach authored Jul 13, 2023
1 parent 487a05c commit 14dad04
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
9 changes: 6 additions & 3 deletions lib/commands/gestures.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
toMouseButtonInput,
toMouseMoveInput,
toMouseWheelInput,
getVirtualScreenSize,
} from './winapi/user32';
import { errors } from 'appium/driver';
import B from 'bluebird';
Expand Down Expand Up @@ -437,6 +438,7 @@ commands.windowsClickAndDrag = async function windowsClickAndDrag (opts = {}) {
durationMs = 500,
} = opts;

const screenSize = await getVirtualScreenSize();
const [modifierKeyDownInputs, modifierKeyUpInputs] = modifierKeysToInputs.bind(this)(modifierKeys);
const [[startAbsoluteX, startAbsoluteY], [endAbsoluteX, endAbsoluteY]] = await B.all([
toAbsoluteCoordinates.bind(this)(startElementId, startX, startY, 'Starting drag point'),
Expand All @@ -448,9 +450,9 @@ commands.windowsClickAndDrag = async function windowsClickAndDrag (opts = {}) {
let moveEndInput;
try {
[moveStartInput, clickDownInput, moveEndInput, clickUpInput] = await B.all([
toMouseMoveInput({x: startAbsoluteX, y: startAbsoluteY}),
toMouseMoveInput({x: startAbsoluteX, y: startAbsoluteY}, screenSize),
toMouseButtonInput({button: MOUSE_BUTTON.LEFT, action: MOUSE_BUTTON_ACTION.DOWN}),
toMouseMoveInput({x: endAbsoluteX, y: endAbsoluteY}),
toMouseMoveInput({x: endAbsoluteX, y: endAbsoluteY}, screenSize),
toMouseButtonInput({button: MOUSE_BUTTON.LEFT, action: MOUSE_BUTTON_ACTION.UP}),
]);
} catch (e) {
Expand Down Expand Up @@ -520,6 +522,7 @@ commands.windowsHover = async function windowsHover (opts = {}) {
durationMs = 500,
} = opts;

const screenSize = await getVirtualScreenSize();
const [modifierKeyDownInputs, modifierKeyUpInputs] = modifierKeysToInputs.bind(this)(modifierKeys);
const [[startAbsoluteX, startAbsoluteY], [endAbsoluteX, endAbsoluteY]] = await B.all([
toAbsoluteCoordinates.bind(this)(startElementId, startX, startY, 'Starting hover point'),
Expand All @@ -533,7 +536,7 @@ commands.windowsHover = async function windowsHover (opts = {}) {
const promise = B.resolve(toMouseMoveInput({
x: startAbsoluteX + Math.trunc((endAbsoluteX - startAbsoluteX) * step / stepsCount),
y: startAbsoluteY + Math.trunc((endAbsoluteY - startAbsoluteY) * step / stepsCount),
}));
}, screenSize));
inputPromises.push(promise);
// This is needed to avoid 'Error: Too many asynchronous calls are running'
inputPromisesChunk.push(promise);
Expand Down
27 changes: 24 additions & 3 deletions lib/commands/winapi/user32.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ async function getSystemMetrics(nIndex) {
return await getUser32().GetSystemMetrics(nIndex);
}

const isLeftMouseButtonSwapped = _.memoize(async function isLeftMouseButtonSwapped () {
return Boolean(await getSystemMetrics(SM_SWAPBUTTON));
});

function createMouseInput (params = {}) {
return {
type: INPUT_MOUSE,
Expand Down Expand Up @@ -247,7 +251,7 @@ export async function toMouseButtonInput({button, action}) {

// If the host is configured to swap left & right buttons, inject swapped
// events to un-do that re-mapping.
if (await getSystemMetrics(SM_SWAPBUTTON)) {
if (await isLeftMouseButtonSwapped()) {
if (button === MOUSE_BUTTON.LEFT) {
button = MOUSE_BUTTON.RIGHT;
} else if (button === MOUSE_BUTTON.RIGHT) {
Expand Down Expand Up @@ -305,18 +309,19 @@ function clamp (num, min, max) {
* input structure
*
* @param {MouseMoveOptions} opts
* @param {Size?} screenSize
* @returns {Promise<INPUT>} The resulting input structure
* @throws {Error} If the input data is invalid
*/
export async function toMouseMoveInput({dx, dy, x, y}) {
export async function toMouseMoveInput({dx, dy, x, y}, screenSize = null) {
const isAbsolute = _.isInteger(x) && _.isInteger(y);
const isRelative = _.isInteger(dx) && _.isInteger(dy);
if (!isAbsolute && !isRelative) {
throw createInvalidArgumentError('Either relative or absolute move coordinates must be provided');
}

if (isAbsolute) {
const [width, height] = await B.all([SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN].map(getSystemMetrics));
const {width, height} = screenSize ?? await getVirtualScreenSize();
if (width <= 1 || height <= 1) {
throw new Error('Cannot retrieve virtual screen dimensions via GetSystemMetrics WinAPI');
}
Expand Down Expand Up @@ -408,3 +413,19 @@ export function toUnicodeKeyInputs(text) {
}
return result;
}

/**
* @typedef {Object} Size
* @property {number} width
* @property {number} height
*/

/**
* Fetches the size of the virtual screen
*
* @returns {Promise[Size]}
*/
export async function getVirtualScreenSize () {
const [width, height] = await B.all([SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN].map(getSystemMetrics));
return {width, height};
}

0 comments on commit 14dad04

Please sign in to comment.