events - Events and listeners
Stability: 2 - Stable
events itself is an EventEmitter.
Note that event handling is single-threaded and runs on the original thread. If the main script or other event handlers do time-consuming work (polling, long loops, etc.), events may not be handled in time (they will queue up and wait until the main script/other handlers finish).
events.emitter()
Returns a new EventEmitter. This emitter has no built-in events.
Event: exit
Triggered when the script exits normally or abnormally. If an exception is thrown inside an exit handler, processing of the exit event stops immediately (even if there are multiple handlers) and the exception is printed in console/logs.
When a script stops, it closes all floating windows created by that script, triggers the exit event, and then releases resources. If an exit handler contains an infinite loop, subsequent resources cannot be reclaimed in time. In that case, the script may remain in the task list; closing it from the task list will force-stop exit handling and reclaim remaining resources.
log("Start running");
events.on("exit", function () {
log("Stop running");
});
log("About to stop");events.observeKey()
Enable key listening (e.g. volume keys, Home). Key listening is implemented via the accessibility service; if accessibility is not enabled, this will throw and prompt you to enable it.
Only after this function succeeds will key event listeners like onKeyDown and onKeyUp take effect.
Available on Android 4.3+.
events.onKeyDown(keyName, listener)
keyName{string} Key name to listen forlistener{Function} Listener function. Parameter is a KeyEvent.
Register a key-down listener. When the key specified by keyName is pressed, the listener is called. See Keys for available key names.
Example:
// Enable key listening
events.observeKey();
// Listen for volume up pressed
events.onKeyDown("volume_up", function (event) {
toast("Volume up pressed");
});
// Listen for menu pressed
events.onKeyDown("menu", function (event) {
toast("Menu pressed");
exit();
});events.onKeyUp(keyName, listener)
keyName{string} Key name to listen forlistener{Function} Listener function. Parameter is a KeyEvent.
Register a key-up listener. When the key specified by keyName is released, the listener is called. See Keys for available key names.
A complete key action includes press and release. A key-down event triggers at the moment the finger presses the key; a key-up event triggers when the finger releases it.
Example:
// Enable key listening
events.observeKey();
// Listen for volume down released
events.onKeyUp("volume_down", function (event) {
toast("Volume down released");
});
// Listen for Home released
events.onKeyUp("home", function (event) {
toast("Home released");
exit();
});events.onceKeyDown(keyName, listener)
keyName{string} Key name to listen forlistener{Function} Listener function. Parameter is a KeyEvent.
Register a one-time key-down listener. When the key specified by keyName is pressed, the listener is called once and then unregistered.
In other words, listener is only called for the first key event after onceKeyDown() is set.
events.onceKeyUp(keyName, listener)
keyName{string} Key name to listen forlistener{Function} Listener function. Parameter is a KeyEvent.
Register a one-time key-up listener. When the key specified by keyName is released, the listener is called once and then unregistered.
In other words, listener is only called for the first key event after onceKeyUp() is set.
events.removeAllKeyDownListeners(keyName)
keyName{string} Key name
Remove all KeyDown listeners for the given key.
events.removeAllKeyUpListeners(keyName)
keyName{string} Key name
Remove all KeyUp listeners for the given key.
events.setKeyInterceptionEnabled(enabled, key)
enabled{boolean} Whether to enable key interceptionkey{string} Key to intercept
Enable or disable key interception. Interception means disabling the original system behavior of a key (e.g. volume keys no longer adjust volume), while still allowing you to receive key events.
If key is omitted, all keys are intercepted.
For example, calling events.setKeyInterceptionEnabled(true) disables the system behavior of volume/Home/back keys (adjust volume, go home, go back), while still letting you listen to them via key events.
This is usually used together with key listening. For example, to listen to volume up and prevent the system volume UI from showing:
events.setKeyInterceptionEnabled(true, "volume_up");
events.observeKey();
events.onKeyDown("volume_up", () => {
log("Volume up pressed");
});If any script intercepts a key, that key is intercepted. When the script exits, all interceptions set by the script are automatically cleared.
events.observeTouch()
Enable touch event listening. (Requires root.)
Only after this function succeeds will touch event listeners take effect.
If you call it without root, nothing happens.
events.setTouchEventTimeout(timeout)
timeout{number} Minimum interval between two touch events, in milliseconds. Default 10 ms. Values < 0 are treated as 0.
Set the minimum dispatch interval between touch events.
For example, if the interval is 10 ms: after one touch event occurs and is handled by registered listeners, the next touch event will only be dispatched after at least 10 ms. Touch events within that 10 ms window will be ignored.
It is recommended to increase this interval as much as you can while still meeting your needs. A simple swipe may trigger hundreds of touch events; setting timeout too low may cause event congestion. Strongly recommended not to set timeout to 0.
events.getTouchEventTimeout()
- Returns {number}
Return the minimum touch event interval.
events.onTouch(listener)
listener{Function} Function whose argument is a Point
Register a touch listener. Equivalent to on("touch", listener).
Example:
// Enable touch listening
events.observeTouch();
// Register touch listener
events.onTouch(function (p) {
// When a touch event occurs, print coordinates
log(p.x + ", " + p.y);
});events.removeAllTouchListeners()
Remove all touch listeners.
events.observeNotification()
Enable notification listening (e.g. QQ/WeChat messages, push notifications).
Notification listening depends on the notification listener service. If the service is not running, it throws and navigates to the notification access settings. (Sometimes the permission is enabled but the service is not running; in that case toggle the permission off and on again.)
Example:
events.observeNotification();
events.on("notification", function (notification) {
log(notification.getText());
});Event: notification
Triggered when a notification is posted (e.g. QQ/WeChat messages, push notifications).
events.observeNotification();
events.on("notification", function (notification) {
log("Title: " + notification.getTitle());
log("Text: " + notification.getText());
log("Package: " + notification.getPackageName());
});events.observeToast()
Enable toast listening.
Toast listening depends on the accessibility service, so this function ensures accessibility is running.
Event: toast
Triggered when a toast appears.
events.observeToast();
events.on("toast", function (event) {
log("Toast text: " + event.getText());
log("Toast package: " + event.getPackageName());
});Event: key
Triggered when a key event occurs. Requires calling events.observeKey() first.
events.observeKey();
events.on("key", function (event) {
log("Key: " + event.getKeyCode());
});Event: key_down
Triggered when a key is pressed down. Requires calling events.observeKey() first.
Event: key_up
Triggered when a key is released. Requires calling events.observeKey() first.
EventEmitter
Stability: 2 - Stable
EventEmitter.defaultMaxListeners
By default, each event can register up to 10 listeners. The limit for a single EventEmitter instance can be changed with emitter.setMaxListeners(n). The default for all EventEmitter instances can be changed with EventEmitter.defaultMaxListeners.
Be careful when changing EventEmitter.defaultMaxListeners, as it affects all emitters, including ones already created. Prefer emitter.setMaxListeners(n) over setting EventEmitter.defaultMaxListeners.
Unlike Node.js, this is a hard limit. An EventEmitter instance will not allow more listeners; exceeding the limit throws TooManyListenersException.
emitter.setMaxListeners(emitter.getMaxListeners() + 1);
emitter.once("event", () => {
// do something
emitter.setMaxListeners(Math.max(emitter.getMaxListeners() - 1, 0));
});EventEmitter.addListener(eventName, listener)
eventName{any}listener{Function}
Alias of emitter.on(eventName, listener).
Alias of emitter.on(eventName, listener).
EventEmitter.emit(eventName[, ...args])
eventName{any}args{any}
Synchronously calls each listener registered for eventName, in the order they were registered, passing the provided arguments.
Returns true if the event had listeners, otherwise false.
EventEmitter.eventNames()
Returns an array of event names for which the emitter has registered listeners. Values are strings or symbols.
const myEE = events.emitter();
myEE.on('foo', () => \{\});
myEE.on('bar', () => \{\});
const sym = Symbol('symbol');
myEE.on(sym, () => \{\});
console.log(myEE.eventNames());
// Prints: [ 'foo', 'bar', Symbol(symbol) ]EventEmitter.getMaxListeners()
Return the current max listener limit for this EventEmitter. It can be set via emitter.setMaxListeners(n), or defaults to EventEmitter.defaultMaxListeners.
EventEmitter.listenerCount(eventName)
eventName{string} Event name being listened to
Return the number of listeners listening to eventName.
EventEmitter.listeners(eventName)
eventName{string}
Return a copy of the listeners array for event eventName.
server.on("connection", (stream) => {
console.log("someone connected!");
});
console.log(util.inspect(server.listeners("connection")));
// Prints: [ [Function] ]EventEmitter.on(eventName, listener)
eventName{any} Event namelistener{Function} Callback function
Add listener to the end of the listeners array for event eventName. It does not check whether the listener has already been added. Calling it multiple times with the same eventName and listener results in the listener being added (and called) multiple times.
server.on("connection", (stream) => {
console.log("Someone connected!");
});Returns the emitter itself (so calls can be chained).
By default, listeners are invoked in the order they are added. emitter.prependListener() can be used to add a listener to the beginning of the listeners array.
const myEE = events.emitter();
myEE.on("foo", () => console.log("a"));
myEE.prependListener("foo", () => console.log("b"));
myEE.emit("foo");
// Prints:
// b
// aEventEmitter.once(eventName, listener)#
eventName{any} Event namelistener{Function} Callback function
Add a one-time listener for event eventName. The next time eventName is emitted, the listener is removed and then invoked.
server.once("connection", (stream) => {
console.log("First call!");
});Returns the emitter itself (so calls can be chained).
By default, listeners are invoked in the order they are added. emitter.prependOnceListener() can be used to add a one-time listener to the beginning of the listeners array.
const myEE = events.emitter();
myEE.once("foo", () => console.log("a"));
myEE.prependOnceListener("foo", () => console.log("b"));
myEE.emit("foo");
// Prints:
// b
// aEventEmitter.prependListener(eventName, listener)
eventName{any} Event namelistener{Function} Callback function
Add listener to the beginning of the listeners array for event eventName. It does not check whether the listener has already been added. Calling it multiple times with the same eventName and listener results in the listener being added (and called) multiple times.
server.prependListener("connection", (stream) => {
console.log("Someone connected!");
});Returns the emitter itself (so calls can be chained).
EventEmitter.prependOnceListener(eventName, listener)
eventName{any} Event namelistener{Function} Callback function
Add a one-time listener to the beginning of the listeners array for event eventName. The next time eventName is emitted, the listener is removed and then invoked.
server.prependOnceListener("connection", (stream) => {
console.log("First call!");
});Returns the emitter itself (so calls can be chained).
EventEmitter.removeAllListeners([eventName])
eventName{any}
Remove all listeners, or those of the specified eventName.
Note: removing listeners added elsewhere is usually a bad practice, especially when the emitter is created by another component/module.
Returns the emitter itself (so calls can be chained).
EventEmitter.removeListener(eventName, listener)
eventName{any}listener{Function}
Remove the specified listener from the listeners array of event eventName.
const callback = (stream) => {
console.log("Someone connected!");
};
server.on("connection", callback);
// ...
server.removeListener("connection", callback);removeListener removes at most one instance of a listener from the listeners array. If the same listener is added multiple times for the same event, you must call removeListener multiple times to remove each instance.
Note that once an event is emitted, all listeners bound to it are invoked in order. This means that after the event starts emitting and before the last listener finishes, any calls to removeListener() or removeAllListeners() will not remove them from the current emit() cycle. Subsequent emits behave as expected.
const myEmitter = events.emitter();
const callbackA = () => {
console.log("A");
myEmitter.removeListener("event", callbackB);
};
const callbackB = () => {
console.log("B");
};
myEmitter.on("event", callbackA);
myEmitter.on("event", callbackB);
// callbackA removes listener callbackB, but it will still be called.
// During this emit, the internal listener array is [callbackA, callbackB]
myEmitter.emit("event");
// Prints:
// A
// B
// callbackB is now removed.
// Internal listener array is [callbackA]
myEmitter.emit("event");
// Prints:
// ABecause listeners are managed using an internal array, removing a listener can change the position indices of any listeners registered after it. While this does not affect invocation order, it means the copy returned by emitter.listeners() needs to be recreated.
Returns the emitter itself (so calls can be chained).
EventEmitter.setMaxListeners(n)
n{number}
By default, if you add more than 10 listeners for a particular event, EventEmitter prints a warning. This limit helps find memory leaks, but not all events need to be limited to 10. emitter.setMaxListeners() lets you change the limit for a specific emitter instance. Setting it to Infinity (or 0) means unlimited listeners.
Returns the emitter itself (so calls can be chained).
events.broadcast: Inter-script broadcast
For inter-script communication, besides ScriptEngine.emit() from the engines module, you can also use events.broadcast.
events.broadcast itself is an EventEmitter, but its events are shared across scripts: all scripts can send and listen to these events. Event handling runs on the script main thread (a future onThisThread(eventName, ...args) may be added to support running handlers on another thread).
For example, send a broadcast hello from one script:
events.broadcast.emit("hello", "Xiao Ming");Listen and handle it in another script:
events.broadcast.on("hello", function (name) {
toast("Hello, " + name);
});
// Keep the script running
setInterval(() => {}, 1000);KeyEvent
Key event object. It is passed as the argument to key listener callbacks.
KeyEvent.getAction()
- Returns {number}
Return the action of the event. Includes:
KeyEvent.ACTION_DOWNKey downKeyEvent.ACTION_UPKey up
KeyEvent.getKeyCode()
- Returns {number}
Return the key code. Includes:
KeyEvent.KEYCODE_HOMEHomeKeyEvent.KEYCODE_BACKBackKeyEvent.KEYCODE_MENUMenuKeyEvent.KEYCODE_VOLUME_UPVolume upKeyEvent.KEYCODE_VOLUME_DOWNVolume down
KeyEvent.getEventTime()
- Returns {number}
Return the timestamp when the event occurred.
KeyEvent.getDownTime()
- Returns {number}
Return the timestamp of the most recent down event. If this event itself is a down event, it's the same as getEventTime().
KeyEvent.keyCodeToString(code)
code{number} Key code- Returns {string}
Convert a key code to a string. For example, KEYCODE_HOME -> "KEYCODE_HOME".
Notification
Notification object. You can read details such as title, text, package name, timestamp, etc., and also operate on the notification (click, remove).
Notification.number
- {number}
Notification count. For example, if QQ receives two messages in a row, number is 2.
Notification.when
- {number}
Timestamp when the notification was posted. Can be used to construct a Date. Example:
events.observeNotification();
events.on("notification", function (n) {
log("Notification time: " + new Date(n.when));
});Notification.getPackageName()
- Returns {string}
Get the package name of the app that posted the notification.
Notification.getTitle()
- Returns {string | null}
Get notification title.
Notification.getText()
- Returns {string | null}
Get notification text.
Notification.click()
Click the notification. For example, clicking a QQ message opens the corresponding chat.
Notification.delete()
- Returns {boolean}
Remove the notification. It will disappear from the notification shade.
ToastEvent
Toast event object. It is passed as the argument to toast listener callbacks.
ToastEvent.getText()
- Returns {string | null}
Get the toast text.
ToastEvent.text
- {string | null}
Toast text (read-only property).
ToastEvent.getPackageName()
- Returns {string}
Get the package name of the app that posted the toast.
ToastEvent.packageName
- {string}
Toast package name (read-only property).
Keys
Available key names for key listening functions:
"home"Home key"back"Back key"menu"Menu key"volume_up"Volume up"volume_down"Volume down
