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
S | Return | Name | Parameters |
---|---|---|---|
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
- GetData returns a Uint32Array object
- SetPixel must take an instance of Color
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
- Including
Keyboard
Mouse
- GetState returns bool or
{ key, isDown }
Process
- GetHandle is unavailable
Memory
- ReadData behaves identically
void*
accepts a Node Buffer
- WriteData behaves identically
void*
accepts a Node Buffer
Window
- GetHandleAx is unavailable
- Bounds version of MapToClient is unavailable
W
andH
easily attachable upon return
- Bounds version of MapToScreen is unavailable
W
andH
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
- No operator (), use GetElapsed instead
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
- Microsoft Visual Studio 2015
- Relevant Windows SDK libraries
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.