Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sendkeys-macos

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sendkeys-macos - npm Package Compare versions

Comparing version 1.1.2 to 1.2.0

src/mouse.m

7

CHANGELOG.md
# Changelog
## [1.2.0](https://www.github.com/socsieng/sendkeys-macos/compare/v1.1.2...v1.2.0) (2020-12-24)
### Features
* add experimental support for mouse movements ([7f5b93f](https://www.github.com/socsieng/sendkeys-macos/commit/7f5b93fe3cea210d587fe7b700064583b94aad2b))
### [1.1.2](https://www.github.com/socsieng/sendkeys-macos/compare/v1.1.1...v1.1.2) (2020-09-22)

@@ -4,0 +11,0 @@

12

package.json
{
"name": "sendkeys-macos",
"version": "1.1.2",
"version": "1.2.0",
"description": "Sends keystrokes to a given application with customizable delays to simulate typing",

@@ -13,3 +13,5 @@ "repository": {

"test": "mocha ./**/*.spec.js",
"tag": "git tag -f \"v$(bin/version)\""
"tag": "git tag -f \"v$(bin/version)\"",
"build": "scripts/build.sh",
"install": "scripts/build.sh"
},

@@ -21,3 +23,7 @@ "keywords": [

"macos",
"automator"
"automator",
"mouse",
"move",
"drag",
"click"
],

@@ -24,0 +30,0 @@ "author": "socsieng",

@@ -8,2 +8,4 @@ # SendKeys for macOS

_Includes experimental support for mouse operations._
# Installation

@@ -87,2 +89,13 @@

### Mouse commands
Experimental support for mouse commands, including:
- Mouse move: `<m:x1,y1,x2,y2:duration_in_seconds>`
- Mouse click: `<m:button:number_of_clicks>`
- `button` supported values `left`, `center`, `right`.
- `number_of_clicks` defaults to `1`
- Mouse drag: `<d:x1,y1,x2,y2:duration_in_seconds:button>`
- `button` supported values `left`, `center`, `right`. Defaults to `left`.
### Continuation

@@ -89,0 +102,0 @@

const { execFileSync } = require('child_process');
const generator = require('./generator');
const { splitIncluding } = require('./splitter');
const path = require('path');
const { existsSync } = require('fs');

@@ -10,3 +13,12 @@ const defaultOptions = {

function sendKeys(appName, keystrokes, options = {}) {
// matches <m:1,2,3,4:0.5> or <m:1,2,3,4>
const mouseMoveExpression = /\<m:((\d+),(\d+),)?(\d+),(\d+)(:([\d.]+))?\>/;
// matches <m:left:1> or <m:right>
const mouseClickExpression = /\<m:([a-z]+)(:(\d+))?\>/;
// matches <d:1,2,3,4:0.5:left> or <d:1,2:0.5:left> or <d:1,2,3,4:0.5>
const mouseDragExpression = /\<d:((\d+),(\d+),)?(\d+),(\d+)(:([\d.]+))?(:([a-z]+))?\>/;
const mouseExpressions = [mouseMoveExpression, mouseClickExpression, mouseDragExpression];
function sendKeys(appName, /** @type {string} */ keystrokes, options = {}) {
const mergedOptions = {

@@ -16,7 +28,59 @@ ...defaultOptions,

};
const output = generator.generate(keystrokes, appName, mergedOptions.delay, mergedOptions.initialDelay);
if (mergedOptions.generateScript) {
const output = generator.generate(keystrokes, appName, mergedOptions.delay, mergedOptions.initialDelay);
process.stdout.write(output);
return;
}
const usingMouse = hasMouseCommands(keystrokes);
const hasMouse = existsSync(path.resolve(__dirname, '../build/mouse'));
if (usingMouse && hasMouse) {
// mouse support
const fragments = splitIncluding(
keystrokes,
mouseExpressions.map(exp => new RegExp(exp, 'g')),
);
let isFirstActivation = true;
for (const fragment of fragments) {
let result;
let match;
if ((match = mouseMoveExpression.exec(fragment))) {
const [, , x1, y1, x2, y2, , duration] = match;
result = sendMouseMove(x1, y1, x2, y2, duration);
} else if ((match = mouseClickExpression.exec(fragment))) {
const [, button, , count] = match;
result = sendMouseClick(button, count);
} else if ((match = mouseDragExpression.exec(fragment))) {
const [, , x1, y1, x2, y2, , duration, , button] = match;
result = sendMouseDrag(x1, y1, x2, y2, duration, button);
} else {
const output = generator.generate(
fragment,
isFirstActivation ? appName : undefined,
mergedOptions.delay,
isFirstActivation ? mergedOptions.initialDelay : 0,
);
result = execFileSync('osascript', ['-l', 'JavaScript', '-e', output], {
encoding: 'utf8',
stdio: 'pipe',
});
isFirstActivation = false;
}
if (result && result.trim()) {
console.log(result);
}
}
} else {
if (usingMouse && !hasMouse) {
console.warn(
'Script appears to making use of mouse commands without supported binary. Mouse commands will appear as keystrokes.',
);
}
const output = generator.generate(keystrokes, appName, mergedOptions.delay, mergedOptions.initialDelay);
const result = execFileSync('osascript', ['-l', 'JavaScript', '-e', output], {

@@ -33,2 +97,35 @@ encoding: 'utf8',

function hasMouseCommands(keystrokes) {
return mouseExpressions.map(exp => new RegExp(exp, 'g')).some(exp => exp.test(keystrokes));
}
function sendMouseMove(x1, y1, x2, y2, duration) {
return sendMouseCommands({ x1, y1, x2, y2, duration });
}
function sendMouseClick(button, count) {
return sendMouseCommands({ click: button, clicks: count });
}
function sendMouseDrag(x1, y1, x2, y2, duration, button) {
return sendMouseCommands({ x1, y1, x2, y2, duration, drag: button || 'left' });
}
function sendMouseCommands(options) {
const args = [];
const fixedOptions = {
...options,
duration: options.duration ? Number(options.duration) * 1000 : undefined,
};
Object.keys(fixedOptions)
.filter(key => fixedOptions[key] != null)
.forEach(key => args.push(`-${key}`, `${fixedOptions[key]}`));
return execFileSync(path.resolve(__dirname, '../build/mouse'), args, {
encoding: 'utf8',
stdio: 'pipe',
});
}
module.exports = sendKeys;
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc