v1.3.0.0
Event Handling

A number of classes and object types described in this documentation can emit asynchronous event notifications which may be "subscribed" or "listened" to by attaching an event handler callback function.

In general, events are a fairly standard JS feature/technique, and this scripting environment follows some familiar conventions as well as introducing some unique ones. All events in DSE are actually a type of Function object belonging to the class instance which emits the event. They can be referred-to either by name (eg. emitter.on("eventName", ...)) or with an actual instance reference (eg. emitter.eventName.connect(...)).

For some of the examples here we'll use the Touch Portal API's TP.broadcastEvent event, which get emitted whenever the current page on a TP device changes.

First we need some handler function to connect to the event. This could be declared inline when connecting to the event, or any identifier (name) pointing to a valid function. Both examples are shown here, but for the latter version let's use this one:

/**
@param event Name of the event type (currently TP only sends 'pageChange' events).
@param data Contains any further information about the event.
For 'pageChange' events this contains `pageName`, `previousPageName`, `deviceIp`, `deviceName`, & `deviceId` properties.
*/
function onBroadcastEvent(event, data) {
console.log(`${event}: Navigated to new page ${data.pageName} from ${data.previousPageName} on device ${data.deviceName}`;
}
ArrayBuffer data(int mode=Mode.Clipboard)
Returns the current system clipboard value as raw bytes. When reading the value:

Note that each type of event may have their own argument(s) they pass to event handlers (or no arguments). The one shown above is specific to the TP.broadcastEvent event.

With that out of the way, let's connect the handler to the event. There are several ways to do this, and which one(s) you use may vary depending on the application or your personal preference, but they'll all accomplish the same goal. There are also ways to disconnect an event handler when you no longer wish to receive notifications, of course.

Using connect() / disconnect()

One way is with the connect()/disconnect() event prototype methods. This is known as a "subscriber" or "observer" event model and is actually the "native" way for the underlying JavaScript runtime engine used by this plugin. It is generally recommended over the other methods since it is the most direct/efficient.

// Connect the handler
TP.broadcastEvent.connect(myHandler);
// ... later, to disconnect:
TP.broadcastEvent.disconnect(myHandler);
// Inline handlers can be used but there is no way to disconnect it later.
TP.broadcastEvent.connect( (event, data) => { .... } );
TP.broadcastEvent.connect( function (event, data) { .... } );
The global TP namespace is used as a container for all Touch Portal API methods, which are invoked wi...
Definition: touchportal.dox:6
void broadcastEvent(string event, Object data)
This event is emitted when Touch Portal sends a broadcast message to all plugins.

Using on() / off() / once()

Another way is by using the "common" on()/once()/off() function syntax. Each JS object type that emits events will have these methods available. For example:

TP.on("broadcastEvent", onBroadcastEvent);
// ... later, to disconnect:
TP.off("broadcastEvent", onBroadcastEvent);
// A handler function can also be defined inline, as either an arrow or regular function.
// `on()` returns a function which can be called later to disconnect the event handler.
// This is the only way to disconnect an inline handler since it will always be unique.
const disconnect_be = TP.on("broadcastEvent", (event, data) => { .... } );
// ... later, to disconnect:
disconnect_be();
// Alternatively, only invoke the handler once and then automatically disconnect:
TP.once("broadcastEvent", onBroadcastEvent);
// Also works with inline handlers and also returns a disconnect function
const disconnect_be = TP.once("broadcastEvent", (event, data) => { .... } );

Specifying the "this" scope used in handler

Both of the above forms have a version which allows a context object to be given, which then becomes the "this" object when the event handler callback is executed.

class MyClass {
onBroadcastEvent() { console.log(this instanceof MyClass); /* should be `true` */ }
}
const myClass = new MyClass();
// `on()` and `once()` accept it as the 3rd argument
TP.on("broadcastEvent", myClass.onBroadcastEvent, myClass);
// OR `connect()` accepts is as the first argument (note the switched parameter order)
TP.broadcastEvent.connect(myClass, myClass.onBroadcastEvent);
// To disconnect, the same signature must be used:
TP.off("broadcastEvent", myClass.onBroadcastEvent, myClass);
// OR
TP.broadcastEvent.disconnect(myClass, myClass.onBroadcastEvent);

Alternate addEventListener() / removeEventListener() methods

The addEventListener()/removeEventListener() event prototype methods are alternatives for the on()/off() syntax that take an optional options object as the 3rd argument. They are included for users whore are more familiar with, or prefer, the WebAPI style events interface. Note that this is a very simplified version of the full standard Event API.

The options object may specify 2 optional properties (any others are ignored):

// Just like `on()` but 3rd argument may contain an 'options' object.
TP.addEventListener("broadcastEvent", onBroadcastEvent);
// ... or ....
TP.addEventListener("broadcastEvent", onBroadcastEvent, { once: true });
// ... or ....
TP.addEventListener("broadcastEvent", myClass.onBroadcastEvent, { once: true, context: myClass });
// To disconnect:
TP.removeEventListener("broadcastEvent", onBroadcastEvent);
// ... or ....
TP.removeEventListener("broadcastEvent", myClass.onBroadcastEvent, { context myClass });

Global connectEvent() / connectOnce() / disconnectEvent() functions

Three functions are provided in the global scope to connect and disconnect handlers by object reference. These functions are similar to the on()/once()/off() methods, but instead of an event name as the first argument, the actual event method instance is specified.

Essentially this invokes ths corresponding event's connect() prototype method for you, with the given handler (and optional this context object). connectEvent() and connectOnce() also return a function to use for disconnecting later (like on() and once() do).

// `connectEvent(sender, handler [, thisObject ])`
connectEvent(TP.broadcastEvent, onBroadcastEvent);
// ... or
connectEvent(TP.broadcastEvent, myClass.onBroadcastEvent, myClass);
// Same as `on()`, `connectEvent()` returns a function that can be used to disconnect:
const disconnect_be = connectEvent(TP.broadcastEvent, (event, data) => { .... } );
// ... later, to disconnect:
disconnect_be();
// Same as `once()`, automatically disconnect after first time event is triggered:
connectOnce(TP.broadcastEvent, onBroadcastEvent);
// `disconnectEvent()` is similar:
disconnectEvent(TP.broadcastEvent, onBroadcastEvent);
// ... or
disconnectEvent(TP.broadcastEvent, myClass.onBroadcastEvent, myClass);

Other notes

The disconnect([thisObj,] callback) event method, or disconnectEvent() global function, can be used regardless of the original connection method (on(), once() or connect()), as long as the handler wasn't an inline function.

Any number of event listeners can be attached with all above methods. All will throw a TypeError if the event being requested doesn't exist.

Unlike WebAPI Events, there is nothing preventing you from adding the same event handler to the same event multiple times, so you will likely want to avoid doing that yourself.

Also note that there is no standard Event type like with WebAPI. Each event is delivered to the callback handler with a specific set of arguments, if any.

Event handler properties

Some scripting object types will also have on* properties that correspond to each event they emit, to which a single event handler can be assigned.

For example Process has a Process.finished event which can be monitored for when an externally launched program exits. There is also a corresponding Process.onfinished property. Assigning a function to this property will add it as an event handler. Assigning undefined or null to this property will remove any attached handler.

const proc = new Process();
proc.onfinished = myHandler;
// Inline functions, arrow or regular, can also be used
proc.onfinished = function(exitCode, exitStatus) { .... };
// To remove any attached handler:
proc.onfinished = null;
The Process class allows interaction with external processes, such as launching a system command or r...
Definition: RunProcess.h:63

Unlike connecting with the other methods, only one handler can be assigned to a property of an object instance. This could be either convenient or a drawback, depending on application. For the global static objects, like TP or DSE, this means a script may replace a handler assigned in another script, for example. (For this reason, to avoid possible confusion, most of the global singleton types provided by DSE do not have such properties.)

These properties can also be read, meaning, for example, if you wanted to temporarily replace a handler and then put it back, you could:

const oldHandler = proc.onfinished;
proc.onfinished = myHandler;
// ... later
proc.onfinished = oldHandler;