Skip to main content

How scripts run

  • One thread per dispatch. Each triggered script runs on a thread of its own, with its own variables and enumeration caches. Two gestures fired close together run at the same time. A named lock keeps them from interleaving shared work. A serial monitor is the exception: its lines run one at a time, in the order they arrived.
  • A script can block. UtilityWait, message boxes, a ShellRunProgram that waits for exit, and serial reads all block their own script's thread and nothing else. Mouse and keyboard input keep flowing.
  • Stopping. The stop-all-actions hotkey and EngineStopAllActions() end every running script at its next instruction, so an endless loop can always be stopped. UtilityWait, the lock and serial waits, a ShellRunProgram that waits for exit, ShellShowToast, MultimediaPlayMp3File and UIShowConsole also notice a stop request while they wait. The last four then return false, and ShellRunProgram leaves the program running. Other builtins finish their current call first.
  • What persists between runs:
    • Storage*: named values of any kind, shared by every script, held in memory for as long as the engine runs. StorageGetValue of a name that was never set returns Integer 0. It holds up to 1,024 values, with names up to 256 characters and Text up to 32,768 characters; going past a limit stops the action with an error.
    • Window properties (WindowSetPropertyInteger/…Text): values attached to one window that go away when it closes or when Input.Observer exits. A text value is at most 1,024 characters, and up to 512 text values can be stored at once.
    • Named timers, folder watches and serial monitors, which the engine keeps running after the script that created them ends.
  • Scripts passed as Text. TimerCreate, FolderWatchCreate and SerialMonitorCreate take a script as a Text argument. It's compiled and dispatched on its own every time it fires, so it has fresh variables and can't see the variables of the script that created it. Quotes inside it need \" escapes, or keep the script in a snippet and pass SnippetGetScript("name").
  • Context. Context* builtins describe what triggered the current run: the gesture, its points and bounding box, the window and control under it, the button, the watch event, or the serial line. A timer's script has no trigger context. A folder watch's script gets the ContextGetWatch* values, and a serial monitor's gets the ContextGetSerial* values.
  • Snippets are named scripts in the configuration. SnippetExecuteScript runs one to completion before the caller continues, and returns true only when the snippet ran to the end. It shares the caller's trigger context but has its own variables.
  • Safe Mode blocks every script except those run from the diagnostic console.