Node

Edit on GitHubIn addition to the C++ library, Robot can also be integrated with new or existing Node projects. Although there are some key differences in syntax and coding style, the bulk of the JavaScript API remains identical to its C++ counterpart. Since most of this site focuses on the C++ API, this page is dedicated towards documenting all the differences between the two API's for the purposes of helping you get started more quickly and easily. Please review all the sections below prior to using Robot in your Node projects.

Please keep in mind that the API documentation includes examples in both C++ and JavaScript. For more in-depth examples, explore the test cases, however, this document along with the examples in the API section should be sufficient to understand the API.

Installing

The Node version of Robot is called robot-js and like most Node libraries, it can be downloaded through NPM. Since robot-js is a Node addon, it requires a binary compilation step in order to work. However, this is not always convenient as it requires setting up the appropriate development environment prior to installation. To make setup easier, we provide precompiled versions of binaries for the most common platforms where Robot is supported. These binaries will be downloaded automatically during installation. If the binaries could not be downloaded, you will have to compile them manually.

Warning: To save on bandwidth, only binaries appropriate to your immediate environment will be downloaded. Switching to a different platform or Node module version will require a reinstallation or recompilation of the robot-js binaries.

$ npm install robot-js

Versioning

Like the C++ library, robot-js has its own independent version number. This is needed because robot-js uses the C++ library but both libraries are developed independently and could have their own issues. To access the version of the C++ library, use the ROBOT_VERSION and ROBOT_VERSION_STR constants. To access the version of robot-js, which is identical to the package version, use the ADDON_VERSION and ADDON_VERSION_STR constants.

var robot = require ("robot-js");

robot.ROBOT_VERSION;     // 0x020304
robot.ROBOT_VERSION_STR; // "2.3.4"

robot.ADDON_VERSION;     // 0x010102
robot.ADDON_VERSION_STR; // "1.1.2"

Conventions

Unlike C++, JavaScript has a well established set of coding conventions which is respected by most Node libraries and robot-js is no exception. As such, this section will help outline the core differences in coding conventions between the C++ and JavaScript APIs.

Types

JavaScript is a loosely typed, dynamic language which means that you don't actually have to declare the type of the variable ahead of time like you do with C++. Instead, the type will be determined automatically while the program is being executed. That being said, JavaScript has four fundamental data types: booleans, numbers, strings and objects. The boolean type remains identical to its C++ counterpart and has no special considerations attached to it. Numbers, on the other hand, are treated as a single type in JavaScript.

While C++ has special denominations for its numbers (e.g. variable bit-length integers and floating-point numbers), JavaScript will always only have a single type to represents its numbers. Internally, numbers are represented as double-precision floating-point values, which means that JavaScript can never truly support 64-bit integers, however this is usually not a problem as large 64-bit operations are rare. In the case of optimization, most JavaScript engines will use integers until a floating-point operation is performed, at which point, it will transparently switch over to a double-precision representation. Now with regards to memory addresses, since they can never realistically exceed the maximum representable number, no special accommodations are required.

C++ has a wide range of methods for representing strings. These include character pointers, character arrays, STL strings and more. While a bit tricky to work with in C++, in JavaScript these are all represented as simple UTF-8 encoded strings. This means that whenever one of the C++ string types is used, it is safe to assume it will behave as a regular JavaScript string.

Last but not least, JavaScript has a unified method of representing objects and arrays. In C++, STL containers like vector and unordered_map are used to represent managed arrays and hash maps. In JavaScript they are substituted with arrays and objects, respectively. Now, whenever an unmanaged pointer-type is used, Node Buffers and JavaScript Typed Arrays are used instead. This allows the API to remain identical across both languages. For more details, see the class-specific changes below.

Constants

In robot-js, all constants including those found in enumerations will be represented in all caps. Furthermore, each word or camel-cased character is separated with an underscore. This means that constants like KeySpace and ButtonLeft will become KEY_SPACE and BUTTON_LEFT respectively. In addition, all constants will be defined in their original locations as specified by the documentation. This means that constants which are part of the Memory object will continue to be part of the Memory object and constants which are part of the global object will be part of the global robot object, as returned by the require statement loading the robot-js library.

Functions

In JavaScript, all function names begin with lowercase characters. This is different from the C++ version of the library in which all the function names begin with uppercase characters. This is important to keep in mind when reading the documentation as all function names will begin with uppercase characters.

With regards to function overloading and function consistency, the robot-js API remains identical to C++ except for a few minor cases described below. Utility classes like Point and Bounds are especially precise when it comes to function overloading and even provide greater flexibility consistent with traditional JavaScript design patterns. For more information about function overloading and overloading robot-specific data types, see the section below.

Warning: Calling functions with incorrect parameters will result in runtime exceptions or other undefined behavior. As a result, special care must be taken to ensure that all functions are called with their correct parameters.

Operators

JavaScript does not currently support operator overloading. As such, all operator functions have been assigned a name or in some cases, even removed. The naming conventions, however, are consistent across the entire API except for a few minor cases where a more descriptive name is used instead, see below for more details. The naming conventions are as follows:

Operator Becomes
== eq
!= ne
+ add
- sub
- neg
< lt
> gt
<= le
>= ge

Properties

Like functions, public properties also begin with lowercase characters. However, getters and setters are not used for the retrieval and manipulation of said properties, instead, they are accessed and modified directly. As a result, special care must be taken to ensure the properties are set correctly as any error will lead to undefined behavior.

Warning: Setting properties to incorrect data types will result in runtime exceptions or other undefined behavior. As a result, special care must be taken to ensure that all properties are set to their correct data types.

Internals

Functions and variables beginning with an underscore are considered private and should not be directly accessed by any application. These utilities are used solely by the robot-js library for various undocumented tasks. While some of these utilities may be accessible, they can and will change without notice.

Changes

This section describes all the changes between the C++ and robot-js API. While this may not be an extensive list, understanding these changes will greatly improve your development time and reduce your code complexity. This section is split up into three parts, the first describes additions exclusive to robot-js, the second describes omissions from robot-js and the third describes any class specific changes and clarifications.

Additions

To make developing with robot-js easier, some additional functionality is included. Most of this functionality is implemented to get around the limitations of the language, others are implemented to stay consistent with JavaScript design patterns. However, the most important reason some of this functionality is implemented is to help reduce code complexity and to address specific performance issues. All additions to robot-js are described in sections below.

ToString functions

Occasionally, it might be helpful to convert certain classes into their string representations. For this, the toString instance function is used. By implementing this function, every supported class will be automatically converted into a string whenever it's referred to in a manner in which a string is expected. In robot-js, the following classes implement the toString function: Hash, Color, Image, Range, Point, Size and Bounds.

var p = robot.Point (2, 4);
console.log (p.toString());
    // Will output: [2, 4]

Clone functions

In C++, all objects are by default passed by value. This functionality can be changed on a case by case basis by using a pointer or explicitly passing the value by reference. This if different from JavaScript in which all objects are passed by reference. Since passing by value is not really an option in JavaScript, an alternative needs to be implemented to maintain consistency with the C++ library. For this all non-static classes implement a clone instance function which returns an identical copy of the object it's used on.

var t = robot.Timer();
var copy  = t.clone();

t.start();
t.eq (copy); // False
t.ne (copy); // True

Normalize functions

JavaScript does not support function overloading in the same way that C++ does. In C++, multiple functions can have the same name as long as their parameters are different and the compiler will take care of differentiating between them. In JavaScript, however, this is not the case as variable data types are not known ahead of time. In order to support function overloading in JavaScript, a series of runtime comparisons must be performed on the parameters to determine which function to use. Furthermore, since C++ supports implicit conversions, there needs to be some reusable method of accepting overloaded parameters.

In robot-js, a normalize function is available on certain classes which are typically used in overloading scenarios. This function accepts a number of parameters and normalizes them into an object which could be used to process the data. If the parameters could not be normalized, a runtime exception is thrown. The following classes implement the normalize class function: Color, Range, Point, Size and Bounds.

robot.Point .normalize (    );       // { x: 0, y: 0 }
robot.Point .normalize (2   );       // { x: 2, y: 2 }
robot.Point .normalize (2, 4);       // { x: 2, y: 4 }

robot.Color .normalize (a, b, c, d); // { r, g, b, a }
robot.Range .normalize (a, b);       // { min, max   }
robot.Point .normalize (a, b);       // { x, y       }
robot.Size  .normalize (a, b);       // { w, h       }
robot.Bounds.normalize (a, b, c, d); // { x, y, w, h }

Compare functions

From time to time, a sorting operation needs to be performed on an array of values. Luckily, JavaScript makes this easy for us thanks to the built-in sort function. While this function works great on standard data types such as strings and numbers, a comparator is required whenever a custom data type is used. This function specifies the order in which to sort the array of values.

In robot-js, a compare function is available on certain classes which are typically stored in a list and sorted. This function can be passed directly into the sort function and will correctly sort the items in the array. Keep in mind, however, that the array must be made up of only a single type, specifying a mix of data types will usually result in a runtime exception. The following classes implement the compare class function: Timer, Module, Segment and Region.

var process = robot.Process();
var modules =
[
    robot.Module (process, "", "", 4, 0),
    robot.Module (process, "", "", 2, 0),
    robot.Module (process, "", "", 1, 0),
    robot.Module (process, "", "", 3, 0),
];

modules.sort (robot.Module.compare);
    // Modules become [ 1, 2, 3, 4 ]

Memory Helpers

SReturnNameParameters
int8 readInt8 (uintptr address, uint32 count = 1, uint32 stride = 0)
int16 readInt16 (uintptr address, uint32 count = 1, uint32 stride = 0)
int32 readInt32 (uintptr address, uint32 count = 1, uint32 stride = 0)
int64 readInt64 (uintptr address, uint32 count = 1, uint32 stride = 0)
real32 readReal32 (uintptr address, uint32 count = 1, uint32 stride = 0)
real64 readReal64 (uintptr address, uint32 count = 1, uint32 stride = 0)
auto readPtr (uintptr address, uint32 count = 1, uint32 stride = 0)
bool readBool (uintptr address, uint32 count = 1, uint32 stride = 0)
string readString (uintptr address, uint32 length, uint32 count = 1, uint32 stride = 0)
bool writeInt8 (uintptr address, int8 data)
bool writeInt16 (uintptr address, int16 data)
bool writeInt32 (uintptr address, int32 data)
bool writeInt64 (uintptr address, int64 data)
bool writeReal32 (uintptr address, real32 data)
bool writeReal64 (uintptr address, real64 data)
bool writePtr (uintptr address, auto data)
bool writeBool (uintptr address, bool data)
bool writeString (uintptr address, string data, length = data.length)

Because JavaScript is a loosely typed, dynamic language, performing memory manipulation routines through ReadData and WriteData will result in a lot of code. More importantly, these functions can have some serious performance implications since the data has to pass through multiple transformation steps to become usable. To solve this, an additional eighteen functions are introduced to minimize the amount of data transformation steps needed and to yield data in the correct type directly.

Read Helpers

The read functions read the memory of the selected process and return the resulting value. address specifies the base address in the selected process from which the data is read while the number of bytes read depends on the function itself. For example, reading an int8 will read a single byte while reading an int32 will read four. The string variant of the function requires a length parameter which specifies the length of the string(s) to read. This value must be a number and cannot be an array. On success, these functions return the data in memory of a type consistent with the function used. On failure, these functions return null. See the ReadData function for more information.

As an aside, these functions can also accept a count and Stride parameter. count specifies the number of items to read while stride specifies the byte offset between each item. If stride is zero, it will be set to the size of a single item, meaning the items read are next to each other. Only a single read will be performed to extract the data with no additional data being read past the final item. The result will be returned as an array of elements. As an example, calling readInt16 with count set to three and stride set to six will cause the function to read 14 bytes of data in a single call and extract three 16-bit integers, each four bytes away from each other.

Note: For improved performance, consider using a memory cache.

Write Helpers

The write functions copy data into the memory of the selected process and return whether or not they were successful. address specifies the base address in the selected process to which the data is written while the number of bytes written depends on the function itself. For example, writing an int8 will write a single byte while writing an int32 will write four. The string variant of the function accepts a length parameter which specifies the length of the string to write. By default, the length of the string is used. On success, these functions return true. On failure, these functions return false. See the WriteData function for more information.

Omissions

Not all functionality of the C++ library is available in robot-js. This is mainly due to a couple of reasons. The first is that the functionality in question solves a problem which doesn't exist in JavaScript, making its implementation irrelevant. The second is that the functionality doesn't make sense to implement from a framework perspective, because it's most likely already implemented through Node itself. And the third and final reason is that language-specific differences between C++ and JavaScript prevent the functionality from being able to be properly implemented. Either way, the following functionality is unavailable in robot-js.

  • Enum class
  • Macros
  • Copy constructors
  • Move constructors
  • Destructors
  • Assignment operators
  • += and -= operators

Class Changes

Sometimes, the differences between C++ and JavaScript require slight changes to the API in order to work. Below is a list of changes and clarifications specific to each class. These changes should be taken into account when working with robot-js.

Hash

  • File functionality is unavailable
  • Data is passed through a Buffer
    • Direct strings are supported

Image

Bounds

  • No |= and &= operators
  • operator | becomes unite
  • operator & becomes intersect
  • Contains becomes two functions
  • GetLTRB returns LTRB object
    • { l, t, r, b }
  • Functions accept LTRB object
    • Including normalize
    • Including constructor

Keyboard

  • Compile returns an array of { down, key }
  • GetState returns bool or { key, isDown }

Mouse

  • GetState returns bool or { key, isDown }

Process

Memory

Window

  • GetHandleAx is unavailable
  • Bounds version of MapToClient is unavailable
    • W and H easily attachable upon return
  • Bounds version of MapToScreen is unavailable
    • W and H easily attachable upon return

Screen

  • Screen* returns a Screen object
    • Behaves much like a pointer
  • GrabScreen behaves identically
    • But make sure Image is valid

Timer

Clipboard

Compiling

Compiling robot-js is quite similar to compiling the C++ library but with additional prerequisites and configuration steps. To get started, read the appropriate instructions for compiling the C++ library and then follow the additional instructions below. Keep in mind that robot-js is less liberal in the types of compilers it supports so be sure to read over all the instructions prior to installing any new software. If you encounter any problems and you think it might be a bug, please submit a bug report and we'll be more than happy to investigate.

Global

Prerequisites

  • Supported version of Node.js
  • Node development libraries
# Check if Node & NPM are installed
$ node -v
$  npm -v

# Download the development libraries
# Using node-gyp for easy management

$ npm install -g node-gyp
$ node-gyp install [ver]
    # Replace the above [ver] with the latest available
    # release matching the major version number of your
    # local Node installation. For example, if you are
    # using Node 0.12.7, download 0.12.X. If using Node
    # 4.2.0, download 4.X.X and so on.

Linux

Prerequisites

  • GNU g++ 4.9.2 or newer
  • GNU Make 3.81 or newer
  • X11 Toolkit Intrinsics
  • X11 Test Extensions
  • Xinerama Extensions

Compiling

# Download robot-js and cd into it
$ cd /path/to/robot-js/Native/dir/

# Display the make instructions
# Use it as a compilation guide
$ make

# nodeVersion represents the version of
# the installed development libraries &
# nodeModules represents the matching
# node "process.versions.modules" value

Mac

Prerequisites

  • XCode with Command Line Tools
  • Expecting clang++ 5.1 or newer

Compiling

# Download robot-js and cd into it
$ cd /path/to/robot-js/Native/dir/

# Display the make instructions
# Use it as a compilation guide
$ make

# nodeVersion represents the version of
# the installed development libraries &
# nodeModules represents the matching
# node "process.versions.modules" value

Windows

Prerequisites

Compiling

After downloading robot-js, browse to the Native directory and then Addon. From there, open the Robot.vcxproj file in any text editor other than Visual Studio and search for UserMacros. Just below that you will find NodeVersion and NodeModules. NodeVersion represents the version of the installed development libraries and NodeModules represents the matching Node "process.versions.modules" value. Change these to match your environment as needed. Then go back to the Native directory, open the solution file in Visual Studio and build the project. If the build succeeded, the binaries will be copied to the correct directory for robot-js to work.

Errors

In case the build fails, make sure the version of Node you're compiling for is supported. Next, you may need to need to double check that all the appropriate prerequisites are installed. Depending on the error, you may also need to manually configure the locations of the Node development libraries. This means editing the makefiles or visual studio project directly to ensure that all the dependencies are configured correctly.