robot | mouse click | mouse control cocoa | Search

The keySend function is designed to simulate typing a string on the keyboard with optional special key presses, using the robotjs library to interact with the mouse and keyboard. The function takes a string to be typed and an array of special keys to be pressed, and uses a loop to simulate typing the string with realistic timing and modifier key presses.

Run example

npm run import -- "send keys"

send keys

// Type "Hello World" then press enter.
var robot = require("robotjs");

const TAP_SPECIAL = [
  'enter',
  'escape',
  'backspace',
  'delete',
]

async function keySend(text, special) {

  // Type "Hello World".
  //robot.typeString(text)

  let modifiers = special.filter(s => !TAP_SPECIAL.includes(s))

  for(let i = 0; i < text.length; i++) {
    let localModifiers = [].concat(modifiers)
    if(text[i].toUpperCase() == text[i] && !localModifiers.includes('shift')) {
      localModifiers.push('shift')
    }
    robot.keyToggle(text[i].toLowerCase(), 'down', modifiers)
    await new Promise(resolve => setTimeout(resolve, 150))
    robot.keyToggle(text[i].toLowerCase(), 'up', modifiers)
  }

  let tap = special.filter(s => TAP_SPECIAL.includes(s))
  if(tap.length > 0) {
    // Press enter.
    robot.keyTap(tap[0], modifiers)
  }

}

module.exports = keySend

What the code could have been:

/**
 * Import the robotjs module for simulating keyboard input.
 */
const robot = require("robotjs");

/**
 * Enum for special keys that can't be typed like normal keys.
 */
const TAP_SPECIAL = [
  'enter',
  'escape',
  'backspace',
  'delete',
];

/**
 * Send a key sequence to the keyboard, handling normal and special keys.
 * @param {string} text The text to type.
 * @param {string[]} special Special keys to tap after typing.
 * @returns {Promise<void>}
 */
async function keySend(text, special) {
  // Type the text, handling shift keys and timing for a smooth typing experience.
  for (let i = 0; i < text.length; i++) {
    let modifiers = getModifiers(text[i]);
    await sendKey(text[i].toLowerCase(), modifiers);
    await new Promise(resolve => setTimeout(resolve, 150));
  }

  // If there are special keys to tap, handle them here.
  if (special.length > 0) {
    await tapSpecialKeys(special);
  }
}

/**
 * Get the modifiers for a given character, including shift if it's uppercase.
 * @param {string} char The character to check.
 * @returns {string[]} The modifiers for the character.
 */
function getModifiers(char) {
  const modifiers = [];
  if (char.toUpperCase() === char &&!modifiers.includes('shift')) {
    modifiers.push('shift');
  }
  return modifiers;
}

/**
 * Send a key to the keyboard with the given modifiers.
 * @param {string} key The key to send.
 * @param {string[]} modifiers The modifiers to apply.
 * @returns {Promise<void>}
 */
async function sendKey(key, modifiers) {
  await robot.keyToggle(key, 'down', modifiers);
  await new Promise(resolve => setTimeout(resolve, 150));
  await robot.keyToggle(key, 'up', modifiers);
}

/**
 * Tap special keys on the keyboard.
 * @param {string[]} special The special keys to tap.
 * @returns {Promise<void>}
 */
async function tapSpecialKeys(special) {
  for (const key of special) {
    await robot.keyTap(key);
    await new Promise(resolve => setTimeout(resolve, 150));
  }
}

module.exports = keySend;

Code Breakdown

Importing the robotjs library

var robot = require("robotjs");

The robotjs library is imported, which allows the script to interact with the mouse and keyboard.

Defining a list of special keys

const TAP_SPECIAL = [
  'enter',
  'escape',
  'backspace',
  'delete',
]

The TAP_SPECIAL array contains a list of special keys that should be tapped instead of toggled.

KeySend function

async function keySend(text, special) {
  //...
}

The keySend function takes two parameters:

Function implementation

let modifiers = special.filter(s =>!TAP_SPECIAL.includes(s))

The modifiers array is created by filtering the special array to exclude special keys.

for(let i = 0; i < text.length; i++) {
  let localModifiers = [].concat(modifiers)
  if(text[i].toUpperCase() == text[i] &&!localModifiers.includes('shift')) {
    localModifiers.push('shift')
  }
  robot.keyToggle(text[i].toLowerCase(), 'down', modifiers)
  await new Promise(resolve => setTimeout(resolve, 150))
  robot.keyToggle(text[i].toLowerCase(), 'up', modifiers)
}

The script loops through each character in the text string. For each character:

let tap = special.filter(s => TAP_SPECIAL.includes(s))
if(tap.length > 0) {
  robot.keyTap(tap[0], modifiers)
}

After typing the string, the script checks if there are any special keys to be tapped in the special array. If there are, the keyTap function is called to tap the special key with the specified modifiers.

Exporting the function

module.exports = keySend

The keySend function is exported as a module, making it available for use in other scripts.