SDK Reference
Rebind scripts are Luau running on a Rust core. The runtime dispatches your hooks up to 8,000 times a second; output leaves as standard USB HID from a Teensy 4.x, or as OS-level input in software mode. This page is the complete reference for every namespace, global, hook, and modeline option.
The whole SDK runs free in software mode — no hardware required. To install or update, run the one-line installer in the quickstart.
A few namespaces depend on OS-specific APIs; see Platforms & limits for the authoritative per-namespace support matrix.
Globals
Run
local handle = Run(fn: function) -> TaskHandle
Launches a function as a coroutine. Returns immediately. The function executes concurrently with other script code.
Returns a TaskHandle with:
handle:Cancel()– stop the coroutinehandle:IsRunning()– returnsboolean
If the coroutine errors, the runtime logs it with a traceback (visible in the Logs tab), stops that coroutine (handle:IsRunning() then returns false), and marks the script’s error state — other coroutines and hooks keep running. Wrap fallible work in pcall to let a coroutine survive a recoverable error.
Sleep
Sleep(ms: number)
Pauses the current coroutine for ms milliseconds. Only valid inside a Run() block. Calling Sleep() outside a coroutine will raise a clear error. Does not block anything else.
After
local handle = After(ms: number, fn: function) -> TaskHandle
Shorthand for running a function after a delay. Equivalent to Run(function() Sleep(ms) fn() end). Returns a TaskHandle.
After(2000, function()
Log.Info("2 seconds later")
end)
Async
local wrappedFn = Async(fn: function) -> function
Returns a new function that automatically runs fn in a coroutine when called. This lets you use Sleep() and other coroutine features inside callbacks that are normally synchronous (like Bind handlers).
When the wrapped function is called from the main thread, it spawns a Run() and returns false (swallow). When called from inside an existing coroutine, it calls fn directly to avoid double-wrapping.
-- without Async: manual Run() wrapping
Bind("F10", function()
Run(function()
HID.Down("W")
Sleep(500)
HID.Up("W")
end)
return false
end)
-- with Async: Sleep() just works
Bind(
"F10",
Async(function()
HID.Down("W")
Sleep(500)
HID.Up("W")
end)
)
require
require(module: string) -> any
Loads a sibling module file relative to the script’s own directory and returns
its value (a module is a file that returns something, usually a table). Modules
are cached — the file is evaluated once on first require, and later requires of
the same path return that same value.
Resolution for an extensionless name, in order: <name>.luau, <name>.lua,
<name>/init.luau, <name>/init.lua. Dots are path separators
(require("lib.math") → lib/math.luau); a leading ./ is stripped; an explicit
.lua / .luau suffix pins that exact file.
Sandboxed to the script directory: a name containing .., or any candidate that
resolves outside the directory, raises path traversal not allowed; an unresolved
name raises module '<name>' not found. There are no external packages,
registries, package.path, or aliases — local files only.
local helpers = require("helpers") -- helpers.luau next to the script
local m = require("lib.math") -- lib/math.luau
Only a directly-run script needs a
min_sdkmodeline; arequire’d module is loaded through that script, not run directly, so it needs no header. See the scripting guide.
_REBIND
_REBIND: {
name: string,
version: string,
min_sdk: string,
tick_rate: number,
runtime_uuid: string,
instance: string,
}
Read-only table injected by the host with metadata about the current script and runtime. Available immediately at load time.
Log.Info("Running " .. _REBIND.name .. " v" .. _REBIND.version)
Log.Info("SDK: " .. _REBIND.min_sdk .. ", tick rate: " .. _REBIND.tick_rate)
Hooks
Global functions your script defines. The runtime calls them when events occur.
Lifecycle
function OnStart() -- script loaded
function OnStop() -- script about to unload
function OnFocus(window) -- target window gained focus ({ title, process, x, y, width, height })
function OnBlur(window) -- target window lost focus ({ title, process, x, y, width, height })
function OnTick(dtMs) -- dtMs = ms elapsed since the previous OnTick (0 on the first)
OnTick fires on a fixed cadence set by the tick_rate modeline (default 1,000/s,
max 8,000/s) while the script is active. Its argument dtMs is the real time
elapsed since this script’s previous OnTick, in milliseconds — fractional
(at 8,000/s it’s ~0.125), and 0 on the very first call. Use it for frame-rate-
independent work, e.g. pos += velocity * dtMs. Run() coroutines, Timer
callbacks, and network I/O are serviced on every engine tick regardless of tick_rate.
OnStart runs once per load, before any other hook. For a targeted script that
is already focused at load time, OnFocus fires immediately on the same load; an
unfocused targeted script gets OnStart only, and its OnFocus/OnTick/timers
wait until the target gains focus.
Top-level code runs immediately when the script file is loaded, before OnStart is called. Use it for constants, module initialization, and guards that must run before anything else.
-- top-level: runs at load time
local BASE_SENS = 0.8
function OnStart()
-- runs after the script is fully registered
Log.Info("ready, sensitivity = " .. BASE_SENS)
end
OnStart is the right place for anything that needs the script to be fully registered first — such as reading persisted UI values or starting timers.
Input
All input hooks can return false to block the event from reaching the PC, or return true to pass it through.
function OnDown(key) -- key/button pressed
function OnUp(key, durationMs) -- key/button released
function OnMove(dx, dy) -- mouse moved
function OnScroll(delta) -- vertical scroll
Other (reserved, not yet dispatched)
These hooks are recognized by the script validator but are not dispatched by the relay in the current release. Defining them will not cause errors; they simply won’t fire.
function OnScrollH(delta) -- horizontal scroll (tilt wheel)
function OnReload() -- script reloaded from disk
function OnError(message) -- runtime error in a hook or coroutine
System
Read-only methods updated automatically every tick.
| Function | Returns | Description |
|---|---|---|
System.Time() | number | Current timestamp in milliseconds |
System.Mouse() | x, y | Cursor position in pixels (multiple return values) |
System.Screen() | width, height | Primary display dimensions in pixels (multiple return values) |
System.Window() | table | Active window info: { title, process, x, y, width, height } |
System.Exec(cmd, options?) | table | Run a shell command synchronously, capturing output |
System.ExecDetached(cmd, args?, options?) | number | Launch a detached process, return its PID |
System.Exec
local result = System.Exec(cmd: string, options?: { timeout?: number, cwd?: string })
Runs a shell command (cmd.exe /C on Windows, sh -c on macOS/Linux) and returns when it completes.
Returns: { exit: number, stdout: string, stderr: string }
Options:
timeout– max execution time in ms (default: 5000). The process is killed if it exceeds this.cwd– working directory for the command.
Output is capped at 64KB per stream. The console window is suppressed on Windows.
-- list files
local result = System.Exec("dir /b", { cwd = "C:\\Users" })
Log.Info(result.stdout)
-- run a Python script
local result = System.Exec("python analyze.py", { timeout = 10000 })
if result.exit ~= 0 then
Log.Error("Failed: " .. result.stderr)
end
Warning: System.Exec blocks the script tick while the command runs. Place long-running commands inside Run() to avoid stalling input processing.
Permission: System.Exec requires the exec permission. It is granted by default, but once the modeline declares any permission= line you must include permission=exec, or the call raises System.Exec() requires 'exec' permission at call time. (System.ExecDetached is not gated — see Permissions.)
System.ExecDetached
local pid = System.ExecDetached(cmd: string, args?: string[], options?: { cwd?: string })
Launches cmd as a detached, fire-and-forget process and returns immediately with its PID. Unlike System.Exec, it does not wait for the process or capture its output — stdio is discarded (null).
Returns: the spawned process PID as a number.
Options:
cwd– working directory for the process.
The console window is suppressed on Windows. The process keeps running after the script exits.
-- open a file in the default editor and keep going
local pid = System.ExecDetached("notepad.exe", { "notes.txt" })
Log.Info("launched editor, PID " .. pid)
System.Exec vs System.ExecDetached:
System.Exec– synchronous, blocks until the command finishes, capturesstdout/stderr/exit. Use when you need the output.System.ExecDetached– detached, returns instantly with a PID, no output captured. Use to launch apps or background processes.
HID
Sends keyboard and mouse output through the active transport.
Keyboard
| Function | Description |
|---|---|
HID.Down(key) | Hold a key or button. Non-blocking, safe anywhere. |
HID.Up(key) | Release a key or button. Non-blocking, safe anywhere. |
HID.Press(key, holdMs?) | Tap a key (Down + Sleep + Up). Coroutine only. Default hold: 50ms |
HID.Type(text, delayMs?) | Type a string character by character. Coroutine only. Default delay: 30ms |
Important:
HID.PressandHID.TypeuseSleep()internally and must be called inside aRun()coroutine or anAsync()handler. Calling them outside a coroutine (e.g. directly inOnDown) will raise an error. UseHID.Down/HID.Upfor non-blocking key control in hooks, or wrap your logic withAsync().
-- WRONG: Press in a hook blocks the hot path
function OnDown(key)
if key == "F1" then
HID.Press("A") -- ERROR: not in a coroutine
end
end
-- CORRECT: use Async to wrap the handler
Bind(
"F1",
Async(function()
HID.Press("LCtrl+V") -- works: Async provides a coroutine context
end)
)
-- CORRECT: use Run inside a hook
function OnDown(key)
if key == "F1" then
Run(function()
HID.Press("A") -- works: Run provides a coroutine context
end)
return false
end
return true
end
-- CORRECT: non-blocking alternative (no coroutine needed)
function OnDown(key)
if key == "F1" then
HID.Down("A") -- instant, non-blocking
return false
end
return true
end
Combos
Down, Up, and Press all support + for modifier combos:
HID.Press("LCtrl+V") -- Ctrl+V paste (coroutine only)
HID.Press("LCtrl+LShift+T") -- Ctrl+Shift+T (coroutine only)
HID.Down("LCtrl+LShift") -- hold both modifiers (non-blocking, works anywhere)
HID.Up("LCtrl+LShift") -- release both in reverse order (non-blocking)
HID.Press with combos presses keys left-to-right, sleeps for the hold duration (default 50ms), then releases right-to-left. HID.Down presses left-to-right. HID.Up releases right-to-left.
The + key itself is spelled Equal (unshifted) or KpPlus (numpad), so there is no ambiguity.
Mouse
| Function | Description |
|---|---|
HID.Move(dx, dy) | Relative mouse movement (pixels) |
HID.MoveTo(x, y) | Move to absolute position via relative movement |
HID.Scroll(amount) | Vertical scroll (positive = up) |
Mouse Mode
| Function | Description |
|---|---|
HID.SetMouseMode(mode) | "relative" or "absolute" |
HID.GetMouseMode() | Returns current mode string |
Relative mode (default): single-pass movement, fast (~0.5ms), may drift. Best for fast cursor movement.
Absolute mode: iterative correction with position validation, slower (1-3ms), sub-5px accuracy. Best for desktop automation.
Input
Reads the current physical state of input devices.
| Function | Returns | Description |
|---|---|---|
Input.IsDown(key) | boolean | Whether key/button is currently held |
Input.GetDuration(key) | number | Milliseconds held, 0 if not pressed |
Input.GetActiveKeys() | string[] | All currently held keys |
Input.GetMousePos() | {x, y} | Current cursor position |
Input.GetModifiers() | table | {ctrl, shift, alt, win} booleans |
Input.IsDown / Input.GetDuration accept the same names as the rest of the SDK, including mouse buttons (Mouse1–Mouse5); an unknown or never-pressed code returns false / 0 rather than erroring.
UI
Defines a settings panel rendered in the Rebind UI.
Schema
local cfg = UI.Schema({
key = UI.Widget(default, options?),
...
})
Returns a proxy handle. Read values with cfg.key, write with cfg.key = value.
Widgets
| Constructor | Default Type | Description |
|---|---|---|
UI.Toggle(default, opts?) | boolean | On/off switch |
UI.Slider(default, opts?) | number | Numeric slider |
UI.Keybind(default, opts?) | string | Key binding selector |
UI.Select(default, choices, opts?) | string | Dropdown selection |
UI.Text(default, opts?) | string | Text input field |
UI.Color(default, opts?) | string | Color picker; value is a hex string (e.g. "#ff0000") |
Widget Options
| Option | Type | Applies to | Description |
|---|---|---|---|
label | string | all | Display label (overrides key name) |
tooltip | string | all | Hover description |
group | string | all | Visual section header |
tab | string | all | Tab panel name |
showIf | string | all | Show only when referenced toggle is on |
min | number | Slider | Minimum value |
max | number | Slider | Maximum value |
step | number | Slider | Increment size |
suffix | string | Slider | Unit label (e.g. "%") |
placeholder | string | Text | Hint when empty |
maxLength | number | Text | Character limit |
A Slider with no min/max defaults to a 0–100 range. tooltip, group, tab, and showIf apply to every widget, including UI.Color.
Other
| Function | Description |
|---|---|
UI.Get(id) | Read value by string key |
UI.Set(id, value) | Write value by string key |
UI.GetAll() | All current values as a table |
UI.GetSchema() | Full schema descriptor array (for advanced introspection) |
UI.Notify(message, variant?) | Show notification. Variant: "info" (default), "success", "warning", "error" |
Persistence
Values are saved automatically on every change and restored at startup. Persistence is keyed to the script’s file path – no configuration required.
Macro
Record and play back input sequences.
Playback
| Function | Description |
|---|---|
Macro.Play(macro, speed?, mode?) | Play a macro. Returns a handle. |
Macro.StopAll() | Stop all running macros |
Speed: 1.0 = normal, 0.5 = half speed, 2.0 = double speed. Default: 1.0.
Mode: "parallel" (default), "replace".
Handle methods:
handle:Stop()handle:Pause()handle:Resume()handle:IsPlaying()– returnsbooleanhandle:GetProgress()– returns0.0to1.0handle:Wait()– blocks the current coroutine until playback ends. must be called insideRun()
Hardware Streaming
| Function | Description |
|---|---|
Macro.Stream(macro) | Stream to device for hardware-precision playback |
Macro.Abort() | Stop device-side playback immediately |
Macros containing "type" actions always play host-side, since firmware cannot render text. Macro.Play() automatically falls back to host-side execution when any Type action is present.
Recording
| Function | Description |
|---|---|
Macro.Record(options?) | Start recording input events |
Macro.Finish() | Stop recording, return macro table |
Record options: { ignore_mouse = false, ignore_keyboard = false, precision = "normal" } (keys are snake_case — camelCase is silently ignored)
Format
Actions in a macro table:
| Action | Fields | Description |
|---|---|---|
| (shorthand) | x, y, delay | Mouse movement |
"move" | dx, dy, delay | Mouse movement (explicit) |
"down" | code, delay | Hold key |
"up" | code, delay | Release key |
"press" | code, holdMs, delay | Tap key |
"type" | text, charDelay, delay | Type string |
"scroll" | amount, delay | Scroll wheel |
"sleep" | delay | Pause |
Timer
| Function | Returns | Description |
|---|---|---|
Timer.After(ms, callback) | handle | Execute once after delay |
Timer.Every(ms, callback) | handle | Execute repeatedly at interval |
Timer.CancelAll() | – | Cancel all active timers |
Handle methods: handle:Cancel(), handle:Pause(), handle:Resume()
Math
Random
| Function | Returns | Description |
|---|---|---|
Math.Random(min, max) | number | Uniform random number |
Math.Gaussian(mean, stdDev) | number | Normal distribution random |
Transforms
All transform functions return a new table (original is unchanged).
| Function | Description |
|---|---|
Math.Scale(macro, xFactor, yFactor) | Multiply movement values |
Math.Spline(macro, tension) | Catmull-Rom curve smoothing |
Math.Resample(macro, intervalMs) | Normalize timing to fixed intervals |
Math.Interpolate(macro, intervalMs, mode?) | Resample the mouse path at a fixed interval — mode is "catmull" (default, smooth curves) or "linear". Movement-only: clicks, key presses, scroll, and sleeps are dropped from the result. |
Math.TimeComp(macro, targetMs) | Scale total duration to target |
Interpolate vs Resample:
Resamplechanges all delays uniformly (normalizing recorded macros)Interpolateadds intermediate steps between existing points (smoothing patterns)
JSON
| Function | Returns | Description |
|---|---|---|
JSON.Parse(str) | table | Parse JSON string to Luau table |
JSON.Stringify(tbl) | string | Serialize table to JSON string |
Hash
Common cryptographic and checksum hashing. All inputs are treated as raw bytes.
| Function | Returns | Description |
|---|---|---|
Hash.MD5(data) | string | MD5 digest as a lowercase hex string |
Hash.SHA1(data) | string | SHA-1 digest as a lowercase hex string |
Hash.SHA256(data) | string | SHA-256 digest as a lowercase hex string |
Hash.SHA512(data) | string | SHA-512 digest as a lowercase hex string |
Hash.CRC32(data) | number | CRC32 checksum as a number (not hex) |
Hash.HMAC(algo, key, data) | string | Keyed HMAC digest as a lowercase hex string |
Hash.HMAC accepts algo of "sha256", "sha512", or "sha1". Any other value raises an error.
Log.Info(Hash.SHA256("abc")) --> "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
-- sign an API request
local sig = Hash.HMAC("sha256", apiSecret, payload)
Codec
Base64 and hex encoding/decoding. These are encodings, not encryption — they provide no confidentiality.
| Function | Returns | Description |
|---|---|---|
Codec.Base64(data) | string | Encode bytes to a Base64 string |
Codec.Base64Decode(str) | string | Decode a Base64 string to bytes |
Codec.Hex(data) | string | Encode bytes to a lowercase hex string |
Codec.HexDecode(str) | string | Decode a hex string to bytes |
local encoded = Codec.Base64("hello") --> "aGVsbG8="
local decoded = Codec.Base64Decode(encoded) --> "hello"
Log
| Function | Description |
|---|---|
Log.Info(message) | Info-level log |
Log.Warn(message) | Warning-level log |
Log.Error(message) | Error-level log |
Log.Debug(message) | Debug-level log (dev mode only) |
Globals: print(...) and log(...) are both aliases for Log.Info. They accept multiple arguments, joined by tabs — identical to standard Lua print behaviour.
log("feature enabled, sensitivity =", sensitivity)
print("device ready")
Logs appear in the Rebind UI Logs tab.
File
All paths are relative to your script’s directory. Path traversal (..) is rejected.
| Function | Returns | Description |
|---|---|---|
File.Read(path) | string | Read file contents |
File.Write(path, content) | – | Overwrite file |
File.Append(path, content) | – | Append to file |
File.Exists(path) | boolean | Check if file exists |
File.Delete(path) | boolean | Delete file |
File.List(path) | string[] | List directory contents |
File.MkDir(path) | boolean | Create directory |
File.RmDir(path) | – | Remove a directory and all its contents (recursive) |
File.IsDir(path) | boolean | Whether the path is a directory. false on error. |
File.IsFile(path) | boolean | Whether the path is a file. false on error. |
File.GetSize(path) | number | File size in bytes |
File.GetTime(path) | number | Last-modified time (Unix seconds) |
File.Copy(src, dst) | – | Copy a file from src to dst |
File.Move(src, dst) | – | Move or rename a file from src to dst |
File.ReadJSON(path) | table | Read and parse JSON file |
File.WriteJSON(path, table) | – | Write table as JSON |
File.GetScriptDir() | string | Absolute path to script directory |
File.IsDir and File.IsFile never throw — they return false for missing or out-of-sandbox paths. File.Move uses a rename and may fail across filesystems.
Net
Client
Client calls yield — wrap them in
Run()/Async(). Every HTTP client method below blocks on a background thread and yields the coroutine, so calling one directly inOnDown, top-level code, or any synchronous hook raisesNet.X() must be called inside Run(). The snippets below assume they run inside aRun()block or anAsync()handler. (The WebSocket callsNet.WSListen/Net.WSConnectare exempt — their I/O runs on dedicated threads.)
| Function | Returns | Description |
|---|---|---|
Net.Get(url, headers?, options?) | response | HTTP GET |
Net.Post(url, body, headers?, options?) | response | HTTP POST |
Net.Put(url, body, headers?, options?) | response | HTTP PUT |
Net.Patch(url, body, headers?, options?) | response | HTTP PATCH |
Net.Delete(url, headers?, options?) | response | HTTP DELETE |
Net.Head(url, headers?, options?) | response | HTTP HEAD |
Net.Request(options) | response | Generic HTTP request |
Response: { status: number, body: string, headers: table }
Options: { timeout = milliseconds } – optional trailing table for convenience methods.
Net.Request options: { method: string, url: string, body?: string, headers?: table, timeout?: number }
-- simple GET
local resp = Net.Get("https://api.example.com/data")
-- POST with headers
local resp = Net.Post(
"https://api.example.com/data",
JSON.Stringify({ key = "value" }),
{ ["Content-Type"] = "application/json", ["Authorization"] = "Bearer token" }
)
-- DELETE with timeout
local resp =
Net.Delete("https://api.example.com/item/123", nil, { timeout = 5000 })
-- generic request
local resp = Net.Request({
method = "PATCH",
url = "https://api.example.com/item/123",
body = JSON.Stringify({ name = "updated" }),
headers = { ["Content-Type"] = "application/json" },
timeout = 10000,
})
Custom headers (including User-Agent) can be set on any request via the headers table.
HTTP Server
local server = Net.Listen(port, handler)
Handler: receives request, returns { status, body, headers? }.
Request fields: req.method (e.g. "GET", "POST"), req.path (e.g. "/click"), req.body (string), req.headers (table).
Server handle: server:Stop()
Net.Listen binds 127.0.0.1 (localhost only) — it is not reachable from
other machines. For a LAN-facing endpoint use Net.WSListen, which binds 0.0.0.0.
Under burst load only the newest queued request per server is dispatched to your
handler each tick; older queued requests receive an automatic 200 OK, so keep
handlers fast and idempotent.
For a worked “HTTP request in, hardware out” example, see Automation in the cookbook.
WebSocket Server
local server = Net.WSListen(port, handlers)
Handlers table: all optional.
| Handler | Signature | Fires when |
|---|---|---|
OnConnect | function(client) | a new client has completed the WS handshake |
OnMessage | function(client, payload, is_binary) | the server received a frame |
OnClose | function(client) | the connection was closed (by either side) |
Client handle (passed to handlers): client.id, client:Send(text), client:SendBinary(bytes), client:Close().
Server handle: server:Broadcast(text), server:BroadcastBinary(bytes), server:ClientCount(), server:Stop().
Binary frames arrive as Lua strings (read bytes with string.byte / string.unpack); the is_binary flag distinguishes them from text. The maximum message/frame size is 64 MiB per connection — a larger frame drops the connection. WebSocket handlers run on dedicated threads, so they are exempt from the Run() requirement the HTTP client methods have.
The server binds 0.0.0.0:<port>. Events are dispatched to Lua handlers on the
script’s tick loop. Up to 32 events are processed per tick per server; excess
messages backlog into the next tick. There is no built-in rate limiting —
scripts exposed to untrusted networks should implement their own.
For measured throughput and latency, see Remote control.
Example:
local server = Net.WSListen(19561, {
OnMessage = function(client, payload, is_binary)
if payload == "hello" then
client:Send("world")
else
server:Broadcast("someone said: " .. payload)
end
end,
})
WebSocket Client
local conn = Net.WSConnect(url, handlers)
URL: ws://host:port/path or wss://host:port/path. TLS via rustls
(webpki roots).
Handlers table: all optional.
| Handler | Signature | Fires when |
|---|---|---|
OnOpen | function() | the WS handshake completed |
OnMessage | function(payload, is_binary) | a frame arrived from the server |
OnClose | function() | the connection closed |
Connection handle: conn:Send(text), conn:SendBinary(bytes), conn:Close().
Example:
local conn = Net.WSConnect("wss://echo.websocket.events", {
OnOpen = function()
conn:Send("hello from rebind")
end,
OnMessage = function(payload, is_binary)
Log.Info("got: " .. payload)
end,
})
Remote clients are available for TypeScript, Python, and Rust — drive a running script’s HTTP/WebSocket server from any program.
Screen
Pixel color sampling from the screen. Works on Windows (GDI BitBlt) and macOS (CoreGraphics / ScreenCaptureKit). Not yet available on Linux.
| Function | Returns | Description |
|---|---|---|
Screen.GetPixelColor(x?, y?) | string | Hex color "rrggbb" at pixel coordinates. If no args, reads at current mouse position. |
Screen.SearchForColor(region, color, tolerance?) | {x, y}? | Search a screen region for a pixel matching color. Returns {x, y} or nil. |
Screen.List() | {MonitorEntry} | List all connected monitors. Each entry has index, x, y, width, height, primary. |
Screen.Capture(opts?) | {image, width, height, display, cursor} | Capture a display (or a region of it) as a base64 PNG at native resolution, plus geometry and cursor for mapping image coordinates back to the screen. |
GetPixelColor and SearchForColor read from a non-blocking buffer when one is available; the first 1-2 calls may return nil while the first frame is captured. Screen.Capture always captures live.
On macOS, capture handles Retina displays automatically. GetPixelColor/SearchForColor coordinates are in logical (non-retina) pixels; Screen.Capture returns native (physical) pixels and reports the scale via the returned dimensions vs the display’s logical size.
Screen.SearchForColor
region—{x1, y1, x2, y2}table of screen coordinatescolor— hex string"rrggbb", case-insensitive (matchesGetPixelColoroutput)tolerance— optional, 0.0 to 1.0 (default 0.0 = exact match). Per-channel percentage of 255.- Returns
{x, y}of first match (top-left to bottom-right scan), ornilif not found
-- find a dark-red pixel in a region of the screen
local match = Screen.SearchForColor({ 900, 500, 1100, 530 }, "8b0000", 0.05)
if match then
Log.Info("found at " .. match.x .. ", " .. match.y)
end
-- sample a color, then search for it elsewhere
local color = Screen.GetPixelColor(960, 540)
local match = Screen.SearchForColor({ 0, 0, 1920, 1080 }, color, 0.1)
Screen.List
Returns one entry per connected monitor. Use #Screen.List() for the monitor count.
Each entry:
| Field | Type | Description |
|---|---|---|
index | number | Monitor index |
x | number | Top-left X in virtual desktop coordinates |
y | number | Top-left Y in virtual desktop coordinates |
width | number | Monitor width in pixels |
height | number | Monitor height in pixels |
primary | boolean | Whether this is the primary monitor |
for _, m in ipairs(Screen.List()) do
Log.Info(
"Monitor "
.. m.index
.. ": "
.. m.width
.. "x"
.. m.height
.. (m.primary and " (primary)" or "")
)
end
Screen.Capture
Captures a display live and returns a lossless PNG plus the geometry needed to
map image pixels back to screen coordinates. This is the primitive behind
screenshot-driven automation (see the remote-control protocol’s screen.capture).
opts (all optional):
display— 1-based index fromScreen.List(). Defaults to the display under the cursor.region—{x, y, w, h}in that display’s local coordinates. Defaults to the full display; clamped to the display’s bounds.
Returns:
| Field | Type | Description |
|---|---|---|
image | string | Base64 lossless PNG of the captured pixels at native resolution. |
width / height | number | Native pixel dimensions of the returned frame. |
display | table | {index, x, y, width, height, primary} — signed virtual-desktop origin, so monitors left of / above the primary are addressable. |
cursor | table | {x, y} in screen coordinates, read together with the frame. |
local cap = Screen.Capture() -- display under the cursor
local cap = Screen.Capture({ display = 2 }) -- a specific monitor
local cap = Screen.Capture({ region = { x = 0, y = 0, w = 320, h = 240 } })
Log.Info(
"captured "
.. cap.width
.. "x"
.. cap.height
.. " from display "
.. cap.display.index
)
Window
Window manipulation functions. Handles are integer values obtained from Window.Find() or Window.List(). Passing nil for a handle targets the active (foreground) window.
Platform support: Full on Windows (Win32 API). On macOS, window enumeration (Find, List, GetTitle of active window) works via CoreGraphics, and Kill, IsActive, WaitActive, and WaitClose are fully supported; the remaining manipulation functions (Move, Activate, Minimize, SetTitle, SetAlwaysOnTop, etc.) are best-effort — those that require Accessibility entitlements either work via the Accessibility API or raise a “not supported on macOS” error. Not yet available on Linux.
Query
| Function | Returns | Description |
|---|---|---|
Window.Find(title) | number? | Find first visible window whose title contains title (case-insensitive). Returns handle or nil. |
Window.List(title?) | {WindowEntry} | List all visible windows. Optional title filter. Each entry has handle, title, process, x, y, width, height. |
Window.GetTitle(handle?) | string | Get window title. |
Window.GetClass(handle?) | string | Get the window class name. |
Window.GetPos(handle?) | {x, y, width, height} | Get window position and size. |
Window.GetPID(handle?) | number | Get the process ID that owns the window. |
Window.IsVisible(handle) | boolean | Check if a window is visible. |
Window.IsActive(handle?) | boolean | Check if the window is the active (foreground) window. |
Activation
| Function | Description |
|---|---|
Window.Activate(handle) | Bring window to foreground. Auto-restores if minimized. |
Movement / Sizing
| Function | Description |
|---|---|
Window.Move(handle, x?, y?, w?, h?) | Move and/or resize. Omit any param to leave unchanged. |
State Control
| Function | Description |
|---|---|
Window.Minimize(handle?) | Minimize to taskbar. |
Window.Maximize(handle?) | Maximize to full screen. |
Window.Restore(handle?) | Restore from minimized or maximized. |
Window.Hide(handle?) | Hide the window. |
Window.Show(handle?) | Show a hidden window. |
Window.SetTitle(handle, title) | Set the window title. |
Window.SetAlwaysOnTop(handle, enabled) | Pin (true) or unpin (false) the window above others. |
Window.SetTransparency(handle, alpha) | Set window opacity. alpha is 0 (transparent) to 255 (opaque). |
Window.Close(handle?) | Graceful close (sends WM_CLOSE). |
Window.Kill(handle?) | Force-terminate the owning process. |
Window.Close asks the window to close gracefully (it may prompt to save). Window.Kill force-terminates the process that owns the window — there is no prompt and unsaved work is lost. Window.Kill can take down sibling windows in the same process.
Window.SetAlwaysOnTop and Window.SetTransparency are best-effort: some fullscreen/DirectX apps repaint over them.
Waiting
| Function | Returns | Description |
|---|---|---|
Window.Wait(title, timeout?) | number? | Wait for a window to appear. Must be called inside Run(). Timeout in ms (default 5000). Returns handle or nil. |
Window.WaitActive(title, timeout?) | boolean | Wait for a matching window to become active. Must be called inside Run(). Timeout in ms (default 5000). Returns true if it activated, false on timeout. |
Window.WaitClose(title, timeout?) | boolean | Wait for a matching window to disappear. Must be called inside Run(). Timeout in ms (default 5000). Returns true if it closed, false on timeout. |
Examples
-- find and reposition a window
local hw = Window.Find("Notepad")
if hw then
Window.Move(hw, 0, 0, 800, 600)
Window.Activate(hw)
end
-- list all windows
for _, w in ipairs(Window.List()) do
Log.Info(w.title .. " [" .. w.process .. "]")
end
-- wait for an application to launch
Run(function()
local hw = Window.Wait("Untitled - Notepad", 30000)
if hw then
Window.Maximize(hw)
end
end)
Audio
| Function | Returns | Description |
|---|---|---|
Audio.Beep() | – | Play system beep |
Audio.Play(path, options?) | SoundHandle | Play an audio file (WAV, MP3, OGG, FLAC). Non-blocking. |
Audio.StopAll() | – | Stop all playing sounds |
Audio.SetMasterVolume(vol) | – | Set master volume (0.0 to 1.0) |
Audio.GetMasterVolume() | number | Get current master volume |
Audio.Play
local sound = Audio.Play("alert.wav")
local music = Audio.Play("bgm.mp3", { volume = 0.5, loop = true })
Options:
| Option | Type | Default | Description |
|---|---|---|---|
volume | number | 1.0 | Playback volume (0.0 to 1.0) |
loop | boolean | false | Repeat when playback finishes |
File paths are relative to the script directory (same sandboxing rules as File).
SoundHandle
The object returned by Audio.Play:
| Method | Returns | Description |
|---|---|---|
sound:Stop() | – | Stop playback and release resources |
sound:Pause() | – | Pause playback |
sound:Resume() | – | Resume paused playback |
sound:IsPlaying() | boolean | True if playing (not paused, not finished) |
sound:SetVolume(vol) | – | Set per-sound volume (0.0 to 1.0) |
sound:GetVolume() | number | Get current per-sound volume |
Always call Audio.StopAll() in OnStop and OnBlur to clean up playing sounds.
Clipboard
Read and write the system clipboard. Works on Windows and macOS. Not yet available on Linux.
| Function | Returns | Description |
|---|---|---|
Clipboard.Get() | string? | Read current clipboard text. Returns nil if empty or non-text. |
Clipboard.Set(text) | – | Set clipboard text. |
-- paste a multi-line message into a chat app
local msg = "Line one\nLine two\nLine three"
Clipboard.Set(msg)
HID.Press("LCtrl+V")
-- read clipboard contents
local text = Clipboard.Get()
if text then
Log.Info("Clipboard: " .. text)
end
Clipboard paste is the most reliable way to input multi-line or long text. Applications handle pasted newlines correctly, and there are no per-character timing concerns.
Process
Query and manage system processes.
| Function | Returns | Description |
|---|---|---|
Process.Exists(name) | number? | Find first process matching name (case-insensitive substring). Returns PID or nil. |
Process.List(name?) | {ProcessEntry} | List processes. Optional name filter. Each entry has pid and name. |
Process.Kill(pid) | boolean | Force-kill a process by PID. Returns true if killed, or false (never errors) when no such PID exists or the OS denies the kill (e.g. an elevated or another-user process). |
-- check if an application is running
local pid = Process.Exists("notepad")
if pid then
Log.Info("Notepad is running (PID " .. pid .. ")")
end
-- list all chrome processes
for _, p in ipairs(Process.List("chrome")) do
Log.Info(p.name .. " [" .. p.pid .. "]")
end
Dialog
Native OS dialogs for messages, confirmations, and file selection. All functions must be called inside Run() — they yield the coroutine while the dialog is open. Input processing, timers, and other coroutines continue running uninterrupted.
Linux/BSD: requires Zenity, KDialog, or YAD to be installed.
Message and Confirm
| Function | Returns | Description |
|---|---|---|
Dialog.Message(text, options?) | – | Show an alert box. Yields until dismissed. |
Dialog.Confirm(text, options?) | boolean | Show a yes/no dialog. Returns true if the user clicked Yes. |
Options: { title?: string, level?: string }
level controls the icon: "info" (default), "warning" (alias "warn"), or "error". Matching is case-insensitive, and any unrecognized value falls back to "info".
Run(function()
Dialog.Message("Script finished.", { title = "Done" })
local ok = Dialog.Confirm(
"Overwrite existing file?",
{ title = "Confirm", level = "warning" }
)
if not ok then
return
end
end)
File Dialogs
| Function | Returns | Description |
|---|---|---|
Dialog.OpenFile(options?) | string? | Pick a single file. Returns path or nil if cancelled. |
Dialog.OpenDir(options?) | string? | Pick a directory. Returns path or nil if cancelled. |
Dialog.SaveFile(options?) | string? | Choose a save location. Returns path or nil if cancelled. |
Options: { title?: string, location?: string, filters?: { { name: string, extensions: { string } } } }
location– initial directory the dialog opens in.filters– restrict the file types shown. Each entry has a displaynameand a list ofextensions(without leading dot).
Run(function()
-- open a single Lua file
local path = Dialog.OpenFile({
title = "Open Script",
filters = {
{ name = "Lua Scripts", extensions = { "lua", "luau" } },
},
})
if path then
local code = File.Read(path)
end
-- save a file
local dest = Dialog.SaveFile({
title = "Save As",
location = File.GetScriptDir(),
filters = {
{ name = "JSON", extensions = { "json" } },
},
})
if dest then
File.WriteJSON(dest, data)
end
-- pick a directory
local dir = Dialog.OpenDir({ title = "Select Output Folder" })
if dir then
Log.Info("Output: " .. dir)
end
end)
Regex
Pattern matching using regular expressions (PCRE-style syntax via the Rust regex crate). Backtracking-free by design – no risk of catastrophic backtracking.
Use [[ ]] long strings for patterns to avoid Luau escape interpretation: [[\d+]] instead of "\\d+".
| Function | Returns | Description |
|---|---|---|
Regex.IsMatch(text, pattern) | boolean | Test if text matches the pattern |
Regex.Find(text, pattern) | table? | First match with captures, or nil |
Regex.FindAll(text, pattern) | {table} | All matches with captures |
Regex.Replace(text, pattern, rep) | string | Replace first match |
Regex.ReplaceAll(text, pattern, rep) | string | Replace all matches |
Regex.Split(text, pattern) | {string} | Split text on pattern |
Match result
Regex.Find and Regex.FindAll return tables with:
{
match = "full matched text",
captures = { "group1", "group2" }, -- positional capture groups
start = 8, -- 1-indexed byte offset of match start
finish = 11, -- 1-indexed byte offset of match end
}
Replacement syntax
Replacements use $1, $2, etc. for capture group references:
Regex.ReplaceAll("John Smith", [[(\w+) (\w+)]], "$2, $1") --> "Smith, John"
Examples
-- test a pattern
if Regex.IsMatch(win.process, "discord|slack|teams") then
-- chat app behavior
end
-- extract data
local m = Regex.Find("Price: 500g", [[(\d+)g]])
if m then
local amount = tonumber(m.captures[1]) --> 500
end
-- split CSV
local fields = Regex.Split("a,b,,d", ",") --> {"a", "b", "", "d"}
Note: Luau also has built-in Lua patterns (string.find, string.match, string.gmatch) which use different syntax (%d instead of \d). The Regex namespace uses standard regex syntax and supports features Lua patterns lack: alternation (|), non-greedy quantifiers, lookahead, and more.
Config
Read and write TOML configuration files. TOML is a superset of INI for common use cases – simple key = value files work as-is, with support for typed values (booleans, numbers, strings), arrays, and nested tables.
| Function | Returns | Description |
|---|---|---|
Config.ParseTOML(text) | table | Parse a TOML string into a Lua table |
Config.ToTOML(table) | string | Serialize a Lua table to a TOML string |
Config.ReadTOML(path) | table | Read and parse a TOML file |
Config.WriteTOML(path, table) | – | Serialize and write a TOML file |
File paths are relative to the script directory (same sandboxing rules as File).
-- settings.toml:
-- [general]
-- sensitivity = 0.8
-- enabled = true
-- profile = "default"
local cfg = Config.ReadTOML("settings.toml")
Log.Info(cfg.general.sensitivity) --> 0.8
Log.Info(cfg.general.profile) --> "default"
-- modify and save
cfg.general.sensitivity = 1.0
Config.WriteTOML("settings.toml", cfg)
For JSON config files, use the File.ReadJSON / File.WriteJSON functions in the File namespace.
Env
Environment variables and known user folders.
Variables
| Function | Returns | Description |
|---|---|---|
Env.Get(name) | string? | Read an environment variable. nil if unset. |
Env.Set(name, value) | – | Set an environment variable for this process and its children. |
Env.Set mutates the Rebind process-wide environment: the change is visible to Env.Get in every other running script and to any later System.Exec / System.ExecDetached, and persists until Rebind exits — it is not scoped to your script. Prefer File / Config for per-script state.
Known Folders
Each returns an absolute path, or nil if the location cannot be determined. Env.Temp is the exception — it always returns a string.
| Function | Returns | Description |
|---|---|---|
Env.Home() | string? | User home directory |
Env.Config() | string? | User config directory |
Env.Data() | string? | User data directory |
Env.Desktop() | string? | Desktop directory |
Env.Documents() | string? | Documents directory |
Env.Downloads() | string? | Downloads directory |
Env.AppData() | string? | Application data directory |
Env.Temp() | string | System temporary directory (always present) |
These paths point outside the File sandbox — use them for informational purposes (such as a Dialog.OpenFile start location), not for sandboxed File.* operations.
local downloads = Env.Downloads()
local path = Dialog.OpenFile({ location = downloads })
Pipe
Shared memory IPC for communicating with external processes (Python, Node.js, etc). Windows only. Returns an error on macOS and Linux (POSIX shared memory support planned).
Opening
local pipe = Pipe.Open(name, options?)
Creates or opens a shared memory region backed by the OS object
Local\Rebind_<name> — the tag an external process opens (so Pipe.Open("vision")
maps Local\Rebind_vision). The name must be 1–64 characters of ASCII letters,
digits, -, or _. The size option (default 65536) is rounded up to the
next power of two, then clamped to 1024–16 MiB, so pipe.size (and
pipe.capacity = size/2 − 12) may exceed what you requested.
Methods
| Method | Returns | Description |
|---|---|---|
pipe:Read() | string or nil | Read latest data from external process. nil if nothing new. |
pipe:Write(data) | – | Write data for external process to read |
pipe:Close() | – | Release shared memory |
Properties
| Property | Type | Description |
|---|---|---|
pipe.name | string | Pipe name |
pipe.size | number | Total shared memory size |
pipe.capacity | number | Max payload size per message |
Wire protocol
The region is split into two fixed channels so both sides can read and write
without locking: the script writes to channel A (offset 0) and reads from
channel B (offset size / 2). An external peer does the inverse — it writes to
channel B and reads from channel A.
Each channel is a 12-byte header followed by the payload:
| Bytes | Field |
|---|---|
0..8 | u64 sequence number, little-endian (bumped on every write) |
8..12 | u32 payload length, little-endian |
12.. | payload bytes (up to pipe.capacity = size/2 − 12) |
A writer lays down the payload, then the length, then the sequence number last
(a release barrier); a reader compares the sequence to the one it last saw and only
reads when it changed. Each channel is a single slot, last-writer-wins — not a
queue, so an unread message is overwritten by the next write. Pace writes to the
reader’s poll interval. Working Python, Rust, and Node peers are in
packages/lua-sdk/examples/sidecars/.
Registry
Read and write the Windows registry. Windows only. Every function raises an error on macOS and Linux.
| Function | Returns | Description |
|---|---|---|
Registry.Read(keyPath, valueName) | string or number | Read a value. Returns a string or number depending on the value type. |
Registry.Write(keyPath, type, valueName, value) | – | Write a typed value. |
Registry.DeleteValue(keyPath, valueName) | – | Delete a single value. |
Registry.DeleteKey(keyPath) | – | Delete a key and all its subkeys (recursive). |
Registry.CreateKey(keyPath) | – | Create a key. |
keyPath begins with a hive: HKLM / HKEY_LOCAL_MACHINE, HKCU, HKCR, HKU, or HKCC.
Registry.Write accepts a type of REG_SZ, REG_DWORD, REG_QWORD, REG_EXPAND_SZ, REG_MULTI_SZ, or REG_BINARY.
Registry.CreateKey([[HKCU\Software\MyScript]])
Registry.Write([[HKCU\Software\MyScript]], "REG_SZ", "Profile", "default")
local profile = Registry.Read([[HKCU\Software\MyScript]], "Profile")
Log.Info(profile) --> "default"
Registry.DeleteKey([[HKCU\Software\MyScript]])
Script
| Function | Description |
|---|---|
Script.Exit(reason?) | Stop the current script. Optional reason is logged. |
Script.Reload() | Reload the current script from disk |
Globals: exit(reason?) and die(reason?) are aliases for Script.Exit.
die("shutting down for maintenance")
Bind
Declarative key binding as an alternative to writing OnDown/OnUp handlers.
-- simple binding (action on press, key is blocked by default)
local handle = Bind("F10", function()
HID.Type("Hello!")
end)
-- explicitly pass the key through to the PC
local handle = Bind("F10", function()
Log.Info("F10 was pressed")
return true -- pass through (must be explicit)
end)
-- binding with condition, press, and release handlers
local handle = Bind("Mouse1", {
when = function()
return Input.IsDown("LAlt") -- only activate when Alt is held
end,
action = function()
Log.Info("pressed")
end,
release = function()
Log.Info("released")
end,
})
-- toggle a UI boolean on keypress
local handle = Bind.Toggle("F9", "enabled")
-- simple remap (no logic needed)
local handle = Bind.Remap("Mouse4", "4")
Blocking
Bind blocks by default. This is the opposite of OnDown/OnUp.
| Return value | OnDown/OnUp | Bind action |
|---|---|---|
return true | pass through | pass through |
return false | block | block |
no return / nil | pass through | block |
Most binds remap or trigger actions where blocking the original key is what you want. To pass the key through, you must explicitly return true.
When using Async() with Bind, the wrapper always returns false (block) immediately when it spawns the coroutine. Any return value inside the coroutine body has no effect on propagation – the decision was already made.
Handle
Handle methods: handle:unbind(), handle:disable(), handle:enable(), handle.enabled (read-only).
Routing
Keys claimed by Bind do not reach OnDown/OnUp. If a bind’s when guard returns false, the key falls through to the next bind or to OnDown/OnUp.
Modeline
A modeline at the top of a script sets its configuration. A directly-run script
must include a modeline that declares min_sdk — the relay refuses to run a
plaintext script whose modeline omits the Rebind version (Script can't run without a Rebind version in its modeline). Every other key is optional and falls
back to its default. (require’d modules and DRM/packaged scripts load by other
paths and are not gated, so this requirement applies only to scripts you run directly.)
Three comment forms are accepted. The multi-line block is the recommended
header — one rebind: line per setting reads cleanly as a script grows, and it is
the exact form the relay suggests on failure:
-- multi-line block (recommended) — one rebind: per line
--[[
rebind: min_sdk=3.0.0
rebind: name=My Script
rebind: process=chrome.exe
rebind: process=firefox.exe
--]]
-- single-line, best for one or two keys
-- rebind: min_sdk=3.0.0 name="My Script" tick_rate=8000
-- inline block
--[[ rebind: min_sdk=3.0.0 name="My Script" tick_rate=8000 --]]
Values may be unquoted (ending at the next space) or wrapped in " or ' to include spaces and =: name="My Script". A string-valued key alone on its own line (as in the block form) takes the rest of the line, so rebind: name=My Script needs no quotes. Repeatable keys (window, process, permission) take one value per entry. Unknown keys are ignored, so a newer SDK key never breaks an older script. The legacy -- ghostpeek: prefix is also accepted.
| Property | Type | Default | Description |
|---|---|---|---|
name | string | filename | Display name |
version | string | "0.0.0" | Script version |
author | string | — | Creator attribution |
description | string | — | Brief explanation |
min_sdk | string | required | Minimum Rebind version the script needs. Must be numeric (partials allowed: 3 means 3.0.0; a leading v and any pre-release/build suffix are ignored). The relay refuses to run a plaintext script that omits it or asks for a version newer than the installed build. |
window | string | — | Window-title match (repeatable, case-insensitive substring) |
process | string | — | Process-name match (repeatable, case-insensitive) |
tick_rate | number | 1000 | OnTick frequency in Hz (max 8000) |
z_index | integer | 1 | Input priority (higher sees input first) |
instance | string | "replace" | "replace", "single", or "multiple" |
mouse_mode | string | "relative" | "relative" or "absolute" |
mouse_block | boolean | false | When true, OnMove can block by returning false; when false, moves forward immediately and OnMove fires asynchronously. Requires a Rebind device — software mode cannot suppress mouse movement. (Note: defining OnMove at all requires a device, even without this key.) |
hardware_only | boolean | false | When true, the script refuses to load unless an authenticated Rebind device is present (This script requires a Rebind device). Accepts true/1/yes. |
permission | string | — | Restrict the script’s access (repeatable): exec, net. See Permissions below. |
The former id key is deprecated and ignored — UI state now persists automatically by file path.
Permissions
By default a script can access every namespace. The moment any permission=
line is present, the script switches to allow-list mode: only the listed
permissions are granted and everything else is denied — so permission=net alone
also denies exec, and vice-versa.
Only exec and net actually gate anything; any other permission= value grants
nothing real but still flips the script into allow-list mode. A denied call fails
as a runtime error when it runs (e.g. Net.Get() requires 'net' permission),
not as a load-time refusal — so a gated call inside a branch only fails when reached.
--[[
rebind: min_sdk=3.0.0
rebind: permission=exec
rebind: permission=net
--]]
| Permission | Gates |
|---|---|
exec | System.Exec only — System.ExecDetached is not gated and runs even under a restricted allow-list |
net | the Net namespace (HTTP client, Net.Listen, and WebSocket) |
Scripts published to the marketplace should declare the minimum permissions they need.
Platform Support
Most SDK namespaces work identically across all platforms. For the per-namespace support matrix, see Platforms & limits.
Key Reference
Key names are case-insensitive. "F1", "f1", and "F1" are all identical.
Use these strings with HID.Down, HID.Up, HID.Press, Bind, and in OnDown/OnUp hooks.
Letters
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
Numbers
0 1 2 3 4 5 6 7 8 9
Function Keys
F1 through F24. F13-F24 are HID output only (they work with HID.Press but will not appear in OnDown/OnUp hooks).
Mouse Buttons
| Button | Name |
|---|---|
| Left click | Mouse1 |
| Right click | Mouse2 |
| Middle click | Mouse3 |
| Back | Mouse4 |
| Forward | Mouse5 |
Modifiers
| Key | Name | Aliases |
|---|---|---|
| Left Ctrl | LCtrl | Ctrl, Control |
| Right Ctrl | RCtrl | |
| Left Shift | LShift | Shift |
| Right Shift | RShift | |
| Left Alt | LAlt | Alt |
| Right Alt | RAlt | |
| Left Win / Cmd | LWin | Win, GUI, Windows, Command, Meta |
| Right Win / Cmd | RWin | RGui, RMeta |
Editing and Control
| Key | Name | Aliases |
|---|---|---|
| Enter | Enter | Return |
| Escape | Escape | Esc |
| Backspace | Backspace | |
| Tab | Tab | |
| Space | Space | |
| Caps Lock | CapsLock |
Navigation
| Key | Name | Aliases |
|---|---|---|
| Insert | Insert | |
| Delete | Delete | Del |
| Home | Home | |
| End | End | |
| Page Up | PageUp | PgUp |
| Page Down | PageDown | PgDn |
| Arrow Up | Up | |
| Arrow Down | Down | |
| Arrow Left | Left | |
| Arrow Right | Right |
System
| Key | Name | Aliases |
|---|---|---|
| Print Screen | PrintScreen | PrintScr, PrtSc |
| Scroll Lock | ScrollLock | |
| Pause / Break | Pause | Break |
| Application / Menu | Menu | App, ContextMenu |
Punctuation
These names refer to the physical key, regardless of shift state.
| Key | Name | Aliases |
|---|---|---|
- / _ | Minus | |
= / + | Equal | Equals |
[ / { | LeftBracket | LeftBrace, LBracket |
] / } | RightBracket | RightBrace, RBracket |
\ / | | Backslash | |
; / : | Semicolon | |
' / " | Apostrophe | Quote |
` / ~ | Grave | Backtick, Tilde |
, / < | Comma | |
. / > | Period | Dot |
/ / ? | Slash |
Numpad
| Key | Name | Aliases |
|---|---|---|
| Num Lock | NumLock | |
| Numpad / | KpDivide | NpDivide |
| Numpad * | KpMultiply | NpMultiply, KpAsterisk |
| Numpad - | KpMinus | NpSubtract |
| Numpad + | KpPlus | NpAdd |
| Numpad Enter | KpEnter | NpEnter |
| Numpad . | KpDot | NpDecimal, NpDot |
| Numpad 0-9 | Kp0 through Kp9 | NP0-NP9, Numpad0-Numpad9 |
Media Keys (HID Output Only)
These can be sent via HID.Press but will not appear in input hooks.
| Key | Name | Aliases |
|---|---|---|
| Next Track | MediaNext | MediaNextTrack |
| Previous Track | MediaPrev | MediaPrevTrack |
| Stop | MediaStop | |
| Play / Pause | MediaPlay | MediaPlayPause |
| Volume Up | VolumeUp | VolUp |
| Volume Down | VolumeDown | VolDown |
| Mute | Mute | VolumeMute |