keysender

Node.js keyboard and mouse inputs emulator, global hotkey register for Windows

Usage no npm install needed!

<script type="module">
  import keysender from 'https://cdn.skypack.dev/keysender';
</script>

README

keysender

Node.js Desktop Automation for Windows. Emulate the mouse and keyboard physical or virtual inputs, capture workwindow, register global hotkeys.

Contents

Installation

Install Windows Build Tools:

npm install --global windows-build-tools

Install node-gyp:

npm install -g node-gyp

Install keysender using npm:

npm install keysender

or yarn:

yarn add keysender

Example

const { Hardware, GlobalHotkey } = require("keysender");
const obj = new Hardware(null, "Notepad"); // find Notepad handle by className and set it as workwindow
new GlobalHotkey({
  // register hotkey
  key: "num-",
  isEnabled() {
    return (
      (obj.workwindow.isOpen() || obj.workwindow.refresh()) &&
      obj.workwindow.isForeground()
    ); // if "Notepad" is open and foreground - do {action}
  },
  getProps(state, prevState, prevProps) {
    console.log(state, prevState, prevProps);
    if (
      !prevProps ||
      state.height !== prevState.height ||
      state.width !== prevState.width
    )
      return [state.width / 2, state.height / 2];
    return prevProps;
  },
  updateState(state) {
    const { height, width } = obj.workwindow.getView();
    return { height, width };
  },
  async action(props) {
    obj.workwindow.setView({ x: 0, y: 0 }); // move workwindow to top left corner of the screen
    await obj.mouse.moveCurveToAsync(...props); // makes human similar mouse movement from current cursor position to middle of"Notepad" window
    await obj.keyboard.printTextAsync("hello"); // instantly types "hello"
    await obj.keyboard.sendKeyAsync("space", 50); // press key "space", await for 50 milliseconds, release key "space"
    await obj.keyboard.sendKeysAsync("world".split(""), [25, 50], 50); // press key "w", await for random from range [25, 50]milliseconds, release key "w", await for 50 milliseconds, press key "o", await for random from range [25, 50] milliseconds,release key "o", await for 50 milliseconds, ..., release key "d"
    await obj.keyboard.sendKeyAsync(["ctrl", "s"], 50); // press key combination "ctrl+s", await for 50 milliseconds, releasekey combination
    // obj.workwindow.close(); // close "Notepad" window
  },
});

Syntax

KeyboardButton

toggleKey, sendKey, sendKeys, GlobalHotkey supports for following keys or numbers(virtual key codes)

type KeyboardRegularButton =
  | "backspace"
  | "tab"
  | "enter"
  | "pause"
  | "capslock"
  | "escape"
  | "space"
  | "pageup"
  | "pagedown"
  | "end"
  | "home"
  | "left"
  | "up"
  | "right"
  | "down"
  | "prntscrn"
  | "insert"
  | "delete"
  | "0"
  | "1"
  | "2"
  | "3"
  | "4"
  | "5"
  | "6"
  | "7"
  | "8"
  | "9"
  | "a"
  | "b"
  | "c"
  | "d"
  | "e"
  | "f"
  | "g"
  | "h"
  | "i"
  | "j"
  | "k"
  | "l"
  | "m"
  | "n"
  | "o"
  | "p"
  | "q"
  | "r"
  | "s"
  | "t"
  | "u"
  | "v"
  | "w"
  | "x"
  | "y"
  | "z"
  | "num0"
  | "num0"
  | "num1"
  | "num2"
  | "num3"
  | "num4"
  | "num5"
  | "num6"
  | "num7"
  | "num8"
  | "num9"
  | "num*"
  | "num+"
  | "num,"
  | "num-"
  | "num."
  | "num/"
  | "f1"
  | "f2"
  | "f3"
  | "f4"
  | "f5"
  | "f6"
  | "f7"
  | "f8"
  | "f9"
  | "f10"
  | "f11"
  | "f12"
  | "f13"
  | "f14"
  | "f15"
  | "f16"
  | "f17"
  | "f18"
  | "f19"
  | "f20"
  | "f21"
  | "f22"
  | "f23"
  | "f24"
  | "numlock"
  | "scrolllock"
  | ";"
  | "="
  | ","
  | "-"
  | "."
  | "/"
  | "~"
  | "["
  | "|"
  | "]"
  | "'";
type KeyboardSpecButton =
  | "alt"
  | "ctrl"
  | "shift"
  | "lshift"
  | "rshift"
  | "lctrl"
  | "rctrl"
  | "lalt"
  | "ralt"
  | "lwin"
  | "rwin";
type KeyboardButton = KeyboardRegularButton | KeyboardSpecButton;

Hardware and Virtual

/** Sets current workwindow by {handle}. */
constructor(handle?: number);
/** Finds the first window with {title} and/or {className} and sets it as current workwindow. */
constructor(title: string | null, className?: string | null);
/** Finds the first child window with {childClassName} and/or {childTitle} of window with {parentHandle} and sets it as current workwindow. */
constructor(parentHandle: number, childClassName: string | null, childTitle?: string | null);
/** Finds the first child window with {childClassName} and/or {childTitle} of the first found window with {parentTitle} and/or {parentClassName} and sets it as current workwindow. */
constructor(parentTitle: string | null, parentClassName: string | null, childClassName: string | null, childTitle?: string | null);

Classes Hardware and Virtual provide the same keyboard, mouse and workwindow methods and have the same constructors, but:

  • Class Hardware provides keyboard and mouse methods implementations on hardware level by inserts the events serially into the keyboard or mouse input stream. These events are not interspersed with other keyboard or mouse input events inserted either by the user (with the keyboard or mouse).
  • Class Virtual provides keyboard and mouse methods implementations on virtual level by sending messages to workwindow, so it could work with background window.

    Note: Virtual keyboard and mouse methods do not work for all windows, for example, input line in certain window may accept message from printText method, but sendKey method makes no effect outside input line, or the window may accept a keystroke message from sendKey method but not accept mouse movement message from moveTo method.

const { Hardware, Virtual } = require("keysender");
const foo = new Hardware("Some title");
const bar = new Virtual(null, "SomeClassName");
const foobar = new Hardware(
  "Some parent title",
  "SomeParentClassName",
  "SomeChildClassName"
);

keyboard

Provides methods to synthesize keystrokes.

keyTogglerDelay

keyTogglerDelay: number | randomFromRange = 35;
const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.keyTogglerDelay = 25;
obj.keyboard.keyTogglerDelay = [25, 50];

keySenderDelay

keySenderDelay: number | randomFromRange = 35;
const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.keySenderDelay = 25;
obj.keyboard.keySenderDelay = [25, 50];

toggleKey

toggleKey(key: KeyboardButton | number | KeyboardButton[] | number[], state?: boolean, delay?: number | randomFromRange): void;
toggleKeyAsync(key: KeyboardButton | number | KeyboardButton[] | number[], state?: boolean, delay?: number | randomFromRange): Promise<void>;

Toggles key or combination of keys to provided state. | Argument | Description | Default Value | | --- | --- | --- | | key | key or array with keys | | | state | key state selection: true for press, false for release | true | | delay | milliseconds to sleep/await after key toggled | keyTogglerDelay |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.toggleKey("a", true); // press key "a" and sleep for {keyTogglerDelay} milliseconds
obj.keyboard.toggleKey("a", false, 50); // release key "a" and sleep for 50 milliseconds
obj.keyboard.toggleKey(["ctrl", "shift", "a"], true, [25, 50]); // press key combination "ctrl+shift+a" and sleep for random from range [25, 50] milliseconds
console.log("You will see this message after all previous actions ends");
obj.keyboard
  .toggleKeyAsync("b", true) // press key "b" and await for {keyTogglerDelay} milliseconds
  .then(() => obj.keyboard.toggleKeyAsync("b", false, 50)) // release key "b" and await for 50 milliseconds
  .then(() => {
    // do something
    return obj.keyboard.toggleKeyAsync("d", false);
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

sendKey

sendKey(key: KeyboardButton | number | KeyboardButton[] | number[], afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): void;
sendKeyAsync(key: KeyboardButton | number | KeyboardButton[] | number[], afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): Promise<void>;

Press and release key or combination of keys. | Argument | Description | Default Value | | --- | --- | --- | | key | key or array with keys | | | afterPressDelay | milliseconds to sleep/await after key pressed | keyTogglerDelay | | afterReleaseDelay | milliseconds to sleep/await after key released | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.sendKey("a"); // press key "a", sleep for {keyTogglerDelay} milliseconds, release key "a"
obj.keyboard.sendKey("a", 50); // press key "a", sleep for 50 milliseconds, release key "a"
obj.keyboard.sendKey("a", 50, 90); // press key "a", sleep for 50 milliseconds, release key "a", sleep for 90 milliseconds
obj.keyboard.sendKey(["ctrl", "shift", "a"], [25, 50]); // press key combination "ctrl+shift+a", sleep for random from range [25, 50] milliseconds, release key combination "ctrl+shift+a"
console.log("You will see this message after all previous actions ends");
obj.keyboard
  .sendKeyAsync("b") // press key "b", await for {keyTogglerDelay} milliseconds, release key "b"
  .then(() => obj.keyboard.sendKeyAsync("a", 50, 50)) // press key "b", await for 50 milliseconds, release key "b", await for 50 milliseconds
  .then(() => {
    // do something
    return obj.keyboard.sendKeyAsync("d");
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

sendKeys

sendKeys(keys: KeyboardButton[] | number[], afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): void;
sendKeysAsync(keys: KeyboardButton[] | number[], afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): Promise<void>;

Press and release array of keys. | Argument | Description | Default Value | | --- | --- | --- | | keys | array with keys | | | afterPressDelay | milliseconds to sleep/await after key pressed | keyTogglerDelay | | afterReleaseDelay | milliseconds to sleep/await after key released excluding last | {afterPressDelay}, or keySenderDelay if {afterPressDelay} not provided |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.sendKeys(["a", "b"]); // press key "a", sleep for {keyTogglerDelay} milliseconds, release key "a", sleep for {keySenderDelay} milliseconds, press key "b", sleep for {keyTogglerDelay} milliseconds, release key "b"
obj.keyboard.sendKeys(["a", "b"], 50); // press key "a", sleep for 50 milliseconds, release key "a", sleep for 50 milliseconds, press key "b", sleep for 50 milliseconds, release key "b"
obj.keyboard.sendKeys(["a", "b"], 50, 90); // press key "a", sleep for 50 milliseconds, release key "a", sleep for 90 milliseconds, press key "b", sleep for 50 milliseconds, release key "b"
obj.keyboard.sendKeys(["a", "b"], [25, 50]); // press key "a", sleep for random from range [25, 50] milliseconds, release key "a", sleep for random from range [25, 50] milliseconds, press key "b", sleep for random from range [25, 50] milliseconds, release key "b"
console.log("You will see this message after all previous actions ends");
obj.keyboard
  .sendKeysAsync(["a", "b"]) // press key "a", await for {keyTogglerDelay} milliseconds, release key "a", await for {keySenderDelay} milliseconds, press key "b", await for {keyTogglerDelay} milliseconds, release key "b"
  .then(() => obj.keyboard.sendKeysAsync("a", 50, [25, 50])) // press key "a", await for 50 milliseconds, release key "a", await for random from range [25, 50] milliseconds, press key "b", await for 50 milliseconds, release key "b"
  .then(() => {
    // do something
    return obj.keyboard.sendKeyAsync(["h", "e"]);
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

printText

printText(text: string, afterTypeDelay?: number | randomFromRange): void;
printTextAsync(text: string, afterTypeDelay?: number | randomFromRange): Promise<void>;

Prints text. | Argument | Description | Default Value | | --- | --- | --- | | text | string to print | | | afterTypeDelay | milliseconds to sleep/await after each char typed excluding last | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.printText("hello world"); // instantly types "hello world"
obj.keyboard.printText("hello world", 50); // types "h", sleep for 50 milliseconds, types "e", sleep for 50 milliseconds, ..., types "d";
obj.keyboard.printText("hello world", [25, 50]); // types "h", sleep for random from range [25, 50] milliseconds, types "e", sleep for random from range [25, 50] milliseconds, ..., types "d";
console.log("You will see this message after all previous actions ends");
obj.keyboard
  .printText("γ Ğ ф f Ș ě š") // instantly types "γ Ğ ф f Ș ě š"
  .then(() => obj.keyboard.printText("qwerty", 50)) // types "q", sleep for 50 milliseconds, types "w", sleep for 50 milliseconds, ..., types "y"
  .then(() => {
    // do something
    return obj.keyboard.sendKeyAsync("d");
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

mouse

Provides methods to synthesize mouse motions, mouse button clicks and get mouse position.

buttonTogglerDelay

buttonTogglerDelay: number | randomFromRange = 35;
const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.buttonTogglerDelay = 25;
obj.mouse.buttonTogglerDelay = [25, 50];

enableSaveMode

enableSaveMode(bool: boolean): void;

If saveMode is enable - every mouse move method first back to last known coordinates ([0, 0] on first move), by default - disable

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.enableSaveMode(true);

toggle

toggle(state: boolean, button?: mouseButton, delay?: number | randomFromRange): void;
toggleAsync(state: boolean, button?: mouseButton, delay?: number | randomFromRange): Promise<void>;

Switch mouse button state. | Argument | Description | Default Value | | --- | --- | --- | | state | key state selection: true for press, false for release | true | | button | name of mouse button | "left" | | delay | milliseconds to sleep/await after switching mouse button state | buttonTogglerDelay |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.toggle(); // press left mouse button and sleep for {buttonTogglerDelay} milliseconds
obj.mouse.toggle(false); // release left mouse button and sleep for {buttonTogglerDelay} milliseconds
obj.mouse.toggle(true, "right", 25); // press right mouse button and sleep for 25 milliseconds
obj.mouse.toggle(false, "right", [25, 50]); // release right mouse button and sleep for random from range [25, 50] milliseconds
console.log("You will see this message after all previous actions ends");
obj.mouse
  .toggleAsync(true, "middle") // press middle mouse button (wheel) and sleep for {buttonTogglerDelay} milliseconds
  .then(() => {
    // do something
    return obj.mouse.toggleAsync(false, "middle", 0);
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

click

click(button?: mouseButton, afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): void;
clickAsync(button?: mouseButton, afterPressDelay?: number | randomFromRange, afterReleaseDelay?: number | randomFromRange): Promise<void>;

Click mouse button. | Argument | Description | Default Value | | --- | --- | --- | | button | name of mouse button | "left" | | afterPressDelay | milliseconds to sleep/await after mouse button pressed | buttonTogglerDelay | | afterReleaseDelay | milliseconds to sleep/await after mouse button released | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.click(); // press left mouse button, sleep for {buttonTogglerDelay} milliseconds, release left mouse button
obj.mouse.click("right"); // press right mouse button, sleep for {buttonTogglerDelay} milliseconds, release right mouse button
console.log("You will see this message after all previous actions ends");
obj.mouse
  .clickAsync("middle", [25, 50]) // press middle mouse button, await for random from range [25, 50] milliseconds, release middle mouse button
  .then(() => {
    // do something
    return obj.mouse.clickAsync("left", 25, 25); // press left mouse button, await for 25 milliseconds, release left mouse button, await for 25 milliseconds
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

moveTo

moveTo(x: number, y: number, delay?: number | randomFromRange): void;
moveToAsync(x: number, y: number, delay?: number | randomFromRange): Promise<void>;

Move mouse to [x, y] in current workwindow. | Argument | Description | Default Value | | --- | --- | --- | | delay | milliseconds to sleep/await after mouse movement | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.moveTo(25, 25); // move mouse cursor to [25, 25]
obj.mouse.moveTo(50, 50, 50); // move mouse cursor to [50, 50] and sleep for 50 milliseconds
console.log("You will see this message after all previous actions ends");
obj.mouse
  .moveToAsync(25, 25) // move mouse cursor to [25, 25]
  .then(() => {
    // do something
    return obj.mouse.moveToAsync(50, 50, 50); // move mouse cursor to [50, 50] and await for 50 milliseconds
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

move

move(x: number, y: number, delay?: number | randomFromRange): void;
moveAsync(x: number, y: number, delay?: number | randomFromRange): Promise<void>;

Move mouse from current position by [x, y] relatively. | Argument | Description | Default Value | | --- | --- | --- | | delay | milliseconds to sleep/await after mouse movement | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.move(25, 25); // move mouse cursor from current position by [25, 25]
obj.mouse.move(-50, 50, 50); // move mouse cursor from current position by [-50, 50] and sleep for 50 milliseconds
console.log("You will see this message after all previous actions ends");
obj.mouse
  .moveAsync(25, -25) // move mouse cursor from current position by [25, -25]
  .then(() => {
    // do something
    return obj.mouse.moveAsync(50, -50, 50); // move mouse cursor from current position by [50, -50] and await for 50 milliseconds
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

moveCurveTo

moveCurveTo(x: number, y: number, speed?: number | "max", deviation?: number): void;
moveCurveToAsync(x: number, y: number, speed?: number | "max", deviation?: number): Promise<void>;

Simulate human similar mouse movement to [x, y] in current workwindow. | Argument | Description | Default Value | | --- | --- | --- | | speed | move speed, if speed equals to "max" - immediate movement | 5 | | deviation | movement curvature | 30 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.moveCurveTo(25, 25); // makes human similar mouse movement from current cursor position to [25, 25]
console.log("You will see this message after all previous actions ends");
obj.mouse
  .moveCurveToAsync(50, 50, "max") // makes instant human similar mouse movement from [25, 25] to [50, 50]
  .then(() => {
    // do something
    return obj.mouse.moveCurveToAsync(125, 45, 0.1, 10); // makes slow human similar mouse movement from [50, 50] to [125, 45]
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

scrollWheel

scrollWheel(amount: number, wheelTogglerDelay?: number | randomFromRange): void;
scrollWheelAsync(count: number, wheelTogglerDelay?: number | randomFromRange): Promise<void>;

Scroll mouse wheel. | Argument | Description | Default Value | | --- | --- | --- | | amount | amount of wheel movement, positive value indicates that the wheel was rotated forward, away from the user, negative value indicates that the wheel was rotated backward, toward the user | | | delay | milliseconds to sleep/await after wheel scroll | 0 |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.scrollWheel(-1);
console.log("You will see this message after all previous actions ends");
obj.mouse
  .scrollWheelAsync(25, 25)
  .then(() => {
    // do something
    return obj.mouse.scrollWheelAsync(15);
  })
  .then(() => {
    console.log("I done");
  });
console.log(
  "You will see this message without waiting for all previous actions"
);

getPos

getPos(): pos;

Returns current cursor position relative to workwindow.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.mouse.moveTo(25, 50);
console.log(obj.mouse.getPos()); // object {x: 25, y: 50}

workwindow

Provides methods to work with workwindow.

set

/** Sets current workwindow by {handle}. */
set(handle?: number): void;
/** Finds the first window with {title} and/or {className} and sets it as current workwindow. */
set(title: string | null, className?: string | null): void;
/** Finds the first child window with {childClassName} and/or {childTitle} of window with {parentHandle} and sets it as current workwindow. */
set(parentHandle: number, childClassName: string | null, childTitle?: string | null): void;
/** Finds the first child window with {childClassName} and/or {childTitle} of the first found window with {parentTitle} and/or {parentClassName} and sets it as currentworkwindow. */
set(parentTitle: string | null, parentClassName: string | null, childClassName: string | null, childTitle?: string | null): void;

Same as constructor.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware("Some title"); // or Virtual
obj.workwindow.set(null, "SomeClass");

get

get(): windowInfo;

Returns object with {handle}, {title} and {className} of current workwindow.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware("Some title"); // or Virtual
console.log(obj.workwindow.get()); // object {handle, title, className}

refresh

refresh(): boolean;

Tries to find a new workwindow using already defined {handle}, {className}, {childTitle}, {childClassName}, returns "true" if new workwindow successfully find (new handle not equal to 0), "false" if it is not.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware("Some title"); // or Virtual
obj.workwindow.refresh();

setView

setView(info: Partial<pos & size>): void;

Set workwindow position and(or) size. | Object field | Description | | --- | --- | | x | window x position | | y | window y position | | width | window width | | height | window height |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.workwindow.setView({ x: 25 }); // sets x position of workwindow to 25
obj.workwindow.setView({ y: 25, width: 1200 }); // sets y position of workwindow to 25, sets workwindow width to 1200px
obj.workwindow.setView({ x: 50, y: 25, width: 1200, height: 800 });

getView

getView(): pos & size;

Returns object with workwindow position and size.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
console.log(obj.workwindow.getView()); // object {x, y, width, height}

setForeground

setForeground(): void;

Makes the current workwindow a foreground window.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.workwindow.setForeground();

isForeground

isForeground(): boolean;

Checks if the current workwindow is a foreground window.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
console.log(obj.workwindow.isForeground()); // true if current workwindow is a foreground window, false if not

isOpen

isOpen(): boolean;

Checks if the current workwindow exist.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
console.log(obj.workwindow.isOpen()); // true if current workwindow exist, false if not

kill

kill(): void;

Terminate current workwindow by killing it's thread.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.workwindow.kill();

close

close(): void;

Close current workwindow by sending close message.

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.workwindow.close();

capture

capture(part: pos & size, format?: "rgba" | "bgra" | "grey"): img;
capture(part: pos & size, format: "monochrome", threshold?: uint8): img;
capture(format?: "rgba" | "bgra" | "grey"): img;
capture(format: "monochrome", threshold?: uint8): img;

Capture screenshot of current workwindow (even if it background) or desktop. | Argument | Description | Default Value | | --- | --- | --- | | part | object {x, y, height, width} with position and size to be captured | | | format | color format of returned image, could be "rgba", "bgra", "grey" or "monochrome"
Note: the bgra format has the best performance, but the alpha channel of pixels is not always 255. | "rgba" | | threshold | color limit for "monochrome" format, if the pixel value is smaller than the threshold, it is set to 0, otherwise it is set to 255 | 127 | Returns object {data, width, height}. | field | Description | | --- | --- | | data | Buffer with pixels | | width | width of captured img | | height | height of captured img |

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
const desktop = new Hardware(0);
obj.workwindow.capture(); // returns {data: Buffer with captured image data in rgba color format, width: width of current workwindow, height: height of current workwindow}
desktop.workwindow.capture(); // returns {data: Buffer with captured image data in rgba color format, width: width of screen, height: height of screen}
obj.workwindow.capture({ x: 25, y: 25, width: 500, height: 500 }); // returns {data: Buffer with captured image data in rgba color format, width: 500, height: 500}
desktop.workwindow.capture({ x: 25, y: 25, width: 500, height: 500 }); // returns {data: Buffer with captured image data in rgba color format, width: 500, height: 500}
obj.workwindow.capture("grey"); // returns {data: Buffer with captured image data in grayscale color format, width: width of current workwindow, height: height of current workwindow}
obj.workwindow.capture(
  { x: 25, y: 25, width: 500, height: 500 },
  "monochrome",
  200
); // returns {data: Buffer with captured image data in monochrome color format, width: 500, height: 500}

colorAt

colorAt(x: number, y: number, returnType?: "string"): string;
colorAt(x: number, y: number, returnType: "array"): [red, green, blue];
colorAt(x: number, y: number, returnType: "number"): number;

Returns pixel color in [x, y] from current workwindow (or screen if {handle} is 0).

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
const desktop = new Hardware(0);
obj.workwindow.colorAt(25, 25); // returns workwindow color in [25, 25] in "rrggbb" format
obj.workwindow.colorAt(25, 25, "array"); // returns workwindow color in [25, 25] in [r,g,b] format
obj.workwindow.colorAt(25, 25, "number"); // returns workwindow color in [25, 25] in decimal format
desktop.workwindow.colorAt(25, 25); // returns screen color in [25, 25] in "rrggbb" format

EventEmitter

EventEmitter available for every sendInput method from keyboard and mouse modules and capture method from workwindow module.

type KeyboardEvent =
  | "beforePrintText"
  | "beforeToggleKey"
  | "beforeSendKey"
  | "beforeSendKeys"
  | "afterPrintText"
  | "afterToggleKey"
  | "afterSendKey"
  | "afterSendKeys";
type MouseEvent =
  | "beforeToggle"
  | "beforeClick"
  | "beforeMoveTo"
  | "beforeMoveCurveTo"
  | "beforeMove"
  | "beforeScrollWheel"
  | "afterToggle"
  | "afterClick"
  | "afterMoveTo"
  | "afterMoveCurveTo"
  | "afterMove"
  | "afterScrollWheel";
type WorkwindowEvent = "capture";

Example:

const { Virtual, Hardware } = require("keysender");
const obj = new Hardware(handle); // or Virtual
obj.keyboard.on("beforeSendKey", (key, delay) => {
  console.log(
    `get ready, now I press ${key}, wait for ${delay} ms and release it`
  ); // logs before each sendKey or sendKeyAsync method
});
obj.keyboard.on("afterSendKey", () => {
  console.log("I done"); // logs after each sendKey or sendKeyAsync method
});
obj.keyboard.sendKey("a");
obj.keyboard.sendKeyAsync("b");

For more details see EventEmitter documentation.

GlobalHotkey

type HotkeyOptions<
  Props,
  State,
  This = GlobalHotkey<Props, State>
> = {
  key: KeyboardRegularButtonType | number;
  isEnabled?(this: This): boolean | Promise<boolean>;
} & (
  | {
      mode?: "once";
      action(this: This, props: Props): void | Promise<void>;
    }
  | {
      mode: "toggle" | "hold";
      action(this: This, props: Props): boolean | Promise<boolean>;
      finalizerCallback?(this: This, props: Props): void | Promise<void>;
      delay?: number;
    }
) &
  (
    | {
        getProps(
          this: This,
          state: State,
          prevState: State,
          prevProps: Props
        ): Props;
        updateState?(this: This, currState: State): State;
        initialState?: State extends {} ? Partial<State> : State;
        initialProps?: Props;
      }
    | { getProps?: undefined }
  );
constructor(options: HotkeyOptions<Props, State>);

Registers hotkey, if some hotkey already registered for this {options.key}, unregister previous hotkey and registers new hotkey. | field | Description | Default Value | | | --- | --- | --- | --- | | key | hotkey | | required | | mode | if "once" - {options.action} will call one time for each {options.key} press,
if "hold" - {options.action} will repeat every {options.delay} milliseconds while {options.key} is pressed or {options.action} returns true,
if "toggle" - {options.action} starts repeat repeat every {options.delay} milliseconds after {options.key} first time pressed and stops after {options.key} second time pressed or {options.action} returns false | "once" | | | isEnabled | function to check if hotkey is need to be executing | | | | action | function to be call after hotkey was pressed | | required | | finalizerCallback | if {options.mode} is "hold" or "toggle" - function to be call after hotkey work is end,
first param is props, the second - reason of ending,
if {options.mode} is "hold": reason can be "ended" (if {options.action} returned false) or "released" (if {options.hotkey} was released);
if {options.mode} is "toggle": reason can be "ended" (if {options.action} returned false) or "toggled" (if {options.hotkey} was toggled) or reason from stop method | | | | delay | if {options.mode} is "hold" or "toggle" - sets delay between {options.action} calls | 0 | | | getProps | function for updating the {options.action} argument (see example below), executed once before starting {options.action}. | | | | updateState | state update function for {options.getProps}, use this for some uncontrollable things like window resizing | | | | initialProps | props for first {options.getProps} call | | | | initialState | state for first {options.getProps} and {options.updateState} call | | |

const { GlobalHotkey } = require("keysender");
const foo = new GlobalHotkey({ // logs "hi" after pressing "num+"
    key: "num+",
    action() {
        console.log("hi");
    }
});
new GlobalHotkey({ // logs "hi" every 50 milliseconds while "num*" is pressed
    key: "num*",
    action() {
        console.log("hi");
        return true;
    },
    mode: "hold",
    delay: 50
});
let i = 0;
new GlobalHotkey({ // logs "hi" every 50 milliseconds after "num/" is pressed until "num/" be pressed again or i become > 50
    key: "num/",
    action() {
        i++;
        if (i > 50) return false;
        console.log("hi")
        return true
    },
    mode: "toggle",
    delay: 50
});
new GlobalHotkey({ // after "a" is pressed if i <= 50 - logs "hi" every 50 milliseconds until "a" be pressed again
    key: "a",
    isEnabled() {
        return i <= 50;
    }
    action() {
        i++;
        console.log("hi")
        return true
    },
    mode: "toggle",
    delay: 50
});
new GlobalHotkey({ // logs "hi" every 50 milliseconds while "num-" is pressed, logs "bye" when "num-" is released
    key: "num-",
    async action() {
        console.log("hi");
        return true;
    },
    mode: "hold",
    delay: 50,
    async finalizerCallback(props, reason) {
        console.log(reason);
    }
});
const bar = new GlobalHotkey({ // unregister prev "num+" hotkey {foo} (but it still could be reassignment) and register new hotkey "num+" {bar}
    key: "num+",
    action() {
        console.log("hello");
    }
});
const obj = new Hardware(null, "Notepad");
new GlobalHotkey({
  key: "num+",
  isEnabled() { //check if window open, if it closed - stopping here.
    return obj.workwindow.isOpen();
  },
  getProps(state, prevState, prevProps) {
    if ( // check is something changing after previous hotkey pressing or is it first call
      !prevProps ||
      state.height !== prevState.height ||
      state.width !== prevState.width
    )
      return [state.width / 2, state.height / 2];
    return prevProps;
  },
  updateState(state) {
    const { height, width } = obj.workwindow.getView();
    return { height, width };
  },
  async action(props) {
    await obj.mouse.moveToAsync(...props);
    await obj.mouse.clickAsync();
  },
});

hotkeyState

readonly hotkeyState: boolean;

if {options.mode} is "hold" - state of {options.key} (true if {options.key} is pressed, false if it isn't),
if {options.mode} is "toggle" - state of toggler,
if {options.mode} is "once" - always true.

const { GlobalHotkey } = require("keysender");
const text = "hello world!";
let i = 0;
new GlobalHotkey({
  key: "num-",
  async action() {
    while (i < text.length && this.hotkeyState) {
      console.log(text[i]);
      i++;
      await new Promise((_) => setTimeout(_, 250));
    }
    return false;
  },
  finalizerCallback() {
    if (this.hotkeyState) console.log("I done");
    else console.log("I not done");
    i = 0;
  },
  mode: "toggle",
});

stop

stop(reason?: string): Promise<void>;

Stops the loop of {option.action} executing.
Note: works only if {options.mode} equals to "toggle". | Argument | Description | Default Value | | --- | --- | --- | | reason | reason to {options.finalizerCallback} | "stopped" |

const foo = new GlobalHotkey({
  key: "num-",
  mode: "toggle",
  action() {
    // some action here
    return true;
  },
  finalizerCallback(_, reason) {
    if (reason === "someReason") {
      console.log("stopped");
    }
  },
});

new GlobalHotkey({
  key: "num+",
  async action() {
    await foo.stop("someReason");
    console.log("you se this message after finalizerCallback message");
  },
});

getState

getState(): State;

Note: available only if {options.getProps} exist

const foo = new GlobalHotkey({
  key: "num+",
  getProps(state, prevState, prevProps) {
    // some code here...
  },
  async action(props) {
    // some action here
  },
});

const currState = foo.getState();

setState

setState: {
  (newState: State): void;
  (setStateFunc: (prevState: State) => State): void;
};

Note: available only if {options.getProps} exist

const foo = new GlobalHotkey({
  key: "num+",
  getProps(state, prevState, prevProps) {
    // some code here...
  },
  async action(props) {
    // some action here
  },
});

foo.setState("some data");
foo.setState((prevState) => prevState + "some data");

reassignment

reassignment(newHotkey: KeyboardRegularButton | number): void;

Reassignments hotkey.

const { GlobalHotkey } = require("keysender");
function action() {
  console.log("hi");
}
const foo = new GlobalHotkey({
  key: "num+",
  action,
});
foo.reassignment("a"); // now function {action} calling after "a" pressed

unregister

unregister(): void;

Unregister hotkey, but it still can be reassignment by reassignment method.

const { GlobalHotkey } = require("keysender");
const foo = new GlobalHotkey({
  key: "num+",
  action() {
    console.log("hi");
  },
});
foo.unregister(); // hotkey "num+" {foo} is unregister, but it still could be reassignment

delete

delete(): void;

Delete hotkey.

const { GlobalHotkey } = require("keysender");
const foo = new GlobalHotkey({
  key: "num+",
  action() {
    console.log("hi");
  },
});
foo.delete(); // hotkey "num+" {foo} is no longer exist

unregisterAll

static unregisterAll(): void;

Unregister all hotkeys, but they still can be reassignment by reassignment method.

const { GlobalHotkey } = require("keysender");
new GlobalHotkey({
  key: "num+",
  action() {
    console.log("hi");
  },
});
new GlobalHotkey({
  key: "num-",
  action() {
    console.log("hi");
  },
});
GlobalHotkey.unregisterAll();

deleteAll

static deleteAll(): void;

Delete all hotkeys, use it before close program.

const { GlobalHotkey } = require("keysender");
new GlobalHotkey({
  key: "num+",
  action() {
    console.log("hi");
  },
});
new GlobalHotkey({
  key: "num-",
  action() {
    console.log("hi");
  },
});
GlobalHotkey.deleteAll();

textToImg

textToImg(text: string, path: string, fontSize: number, options?: textToImgOptions): img;

Draws text using the specified font (supports .ttf and .otf only). | Argument | Description | Default Value | | --- | --- | --- | | text | text to draw | | | path | path to font | | | fontSize | font size in px | | | options | object with options | | Options object: | field | Description | Default Value | | --- | --- | --- | | enableActualHeight | if true - height of returned img be equal to {fontSize} (some characters may be trimmed top or bottom) | false | | enableAntiAliasing | if true - anti-aliasing enabled | true | | color | text color, could be [r, g, b] or "rrggbb" or number | 0xffffff (white) | | backgroundColor | background color, could be [r, g, b] or "rrggbb" or number | 0 (black) | | format | color format of return data, could be "rgba", "bgra", "grey"
Note: bgra format has the best performance, but alpha chanel of each pixel is 0 | "rgba" | Returns object {data, width, height}. | field | Description | | --- | --- | | data | Buffer with pixels | | width | width of drawn text | | height | height of drawn text |

const { textToImg } = require("keysender");
const img1 = textToImg("Hello World!", "./path/to/font.ttf", 12);
const img2 = textToImg("Hello World!", "./path/to/font.otf", 24, {
  enableAntiAliasing: false,
  format: "grey",
});
const img3 = textToImg("Hello World!", "./path/to/font.otf", 36, {
  enableActualHeight: true,
  color: "ff0000",
  backgroundColor: [0, 255, 0],
});

getAllWindows

getAllWindows(): windowInfo[];

Returns array with objects {handle, title, className} of all open windows.

const { getAllWindows } = require("keysender");
console.log(getAllWindows()); // array with objects {handle, title, className} of all open windows

getWindowChildren

getWindowChildren(parentHandle: number): windowInfo[];
getWindowChildren(parentTitle: string | null, parentClassName?: string | null): windowInfo[];

Returns array with objects {handle, title, className} with all children of given window.

const { getWindowChildren } = require("keysender");
console.log(getWindowChildren(parentHandle)); // array with objects {handle, title, className} of all {parentHandle} children
console.log(getWindowChildren("Some title")); // array with objects {handle, title, className} of all children window of the first found window with title "Some title"
console.log(getWindowChildren(null, "SomeClass")); // array with objects {handle, title, className} of all children window of the first found window with className "SomeClass"
console.log(getWindowChildren("Some title", "SomeClass")); // array with objects {handle, title, className} of all children window of the first found window with className "SomeClass" and title "Some title"

getScreenSize

getScreenSize(): size;

Returns object with screen size.

const { getScreenSize } = require("keysender");
console.log(getScreenSize()); // object {width, height}

vkToString

vkToString(virtualKey: number): KeyboardButton;

Returns string name of {virtualKey}.

const { vkToString } = require("keysender");
console.log(vkToString(66)); // "b"

sleep

sleep(ms: number | randomFromRange): void;

Pause current thread for {ms} milliseconds.

const { sleep } = require("keysender");
sleep(25); // pause current thread for 25 milliseconds.
sleep([25, 50]); // pause current thread for random from range [25, 50] milliseconds.