All posts
·Rebind

Rebind Script Examples: From Beginner to Advanced

Ready-to-use Rebind Luau scripts: key remaps, text expansion, mouse precision, an auto-clicker, per-app shortcuts, an HTTP remote, and accessibility tools. Copy, paste, run.

rebind scriptrebind luauluau macroexamples

These are complete scripts you can paste directly into the Rebind UI. Each one demonstrates a different part of the SDK. Start with the ones that match your immediate need, then read the rest to see what else your input is allowed to do now.

All scripts are written in Luau (the getting started guide introduces the language) and run in the Rebind Engine on your PC. Their output reaches your applications as ordinary keyboard and mouse input.


Beginner

Log every input event

The best first script. Doesn't modify anything: just shows you what key names Rebind uses for every input event.

-- rebind: min_sdk=3.0.0
-- rebind: name=Input Logger

function OnDown(key)
    Log.Info("DOWN: " .. key)
    return true
end

function OnUp(key, duration)
    Log.Info("UP: " .. key .. " (held " .. duration .. "ms)")
    return true
end

function OnScroll(delta)
    Log.Info("SCROLL: " .. delta)
    return true
end

Open the Logs tab in the Rebind UI and press keys. You'll see exactly what string names to use in your own scripts.


Remap CapsLock to Escape

The classic Vim remap. Block CapsLock entirely and send Escape instead.

-- rebind: min_sdk=3.0.0
-- rebind: name=CapsLock to Escape

function OnDown(key)
    if key == "CapsLock" then
        HID.Down("Escape")
        return false
    end
    return true
end

function OnUp(key)
    if key == "CapsLock" then
        HID.Up("Escape")
        return false
    end
    return true
end

Mouse side buttons as media controls

Map Mouse4/Mouse5 to previous/next track.

-- rebind: min_sdk=3.2.2
-- rebind: name=Mouse Media Keys

function OnDown(key)
    if key == "Mouse4" then
        HID.Combo("MediaPrev")
        return false
    end
    if key == "Mouse5" then
        HID.Combo("MediaNext")
        return false
    end
    return true
end

HID.Combo presses and releases in one call, so this is a tap however long you hold the mouse button. That matters for media keys: holding one down auto-repeats on some hosts, which would skip several tracks instead of one. Combo is native and does not sleep, so it needs no Run().


Scroll to zoom with a modifier

Hold Right Alt and scroll to zoom. Works in browsers, image viewers, and editors, or whatever else responds to Ctrl+scroll.

-- rebind: min_sdk=3.0.0
-- rebind: name=Scroll Zoom

local cfg = UI.Schema({
    modifier = UI.Keybind("RAlt", { label = "Modifier Key" }),
})

function OnScroll(delta)
    if Input.IsDown(cfg.modifier) then
        HID.Down("LCtrl")
        HID.Scroll(delta)
        HID.Up("LCtrl")
        return false
    end
    return true
end

Intermediate

Text expander

Type an abbreviation and hit a trigger key to expand it. @@ expands to your email address, ## to your signature, /date to today's date.

-- rebind: min_sdk=3.0.0
-- rebind: name=Text Expander

local cfg = UI.Schema({
    trigger = UI.Keybind("F8",           { label = "Expand Key" }),
    email   = UI.Text("user@example.com", { label = "Email", maxLength = 60 }),
    sig     = UI.Text("Best regards,",   { label = "Signature", maxLength = 100 }),
})

local snippets = {}

function OnStart()
    snippets = {
        ["@@"]    = cfg.email,
        ["##"]    = cfg.sig,
        ["/date"] = function()
            local t = os.date("*t")
            return string.format("%04d-%02d-%02d", t.year, t.month, t.day)
        end,
        ["/time"] = function()
            local t = os.date("*t")
            return string.format("%02d:%02d", t.hour, t.min)
        end,
    }
end

local buffer = ""

function OnDown(key)
    if key == cfg.trigger then
        for abbr, expansion in pairs(snippets) do
            if buffer:sub(-#abbr) == abbr then
                if type(expansion) == "function" then expansion = expansion() end
                Run(function()
                    for i = 1, #abbr do
                        HID.Press("Backspace")
                        Sleep(20)
                    end
                    HID.Type(expansion)
                end)
                buffer = ""
                return false
            end
        end
        return false
    end

    if #key == 1 then
        buffer = buffer .. key
        if #buffer > 20 then buffer = buffer:sub(-20) end
    elseif key == "Backspace" and #buffer > 0 then
        buffer = buffer:sub(1, -2)
    elseif key == "Space" or key == "Enter" then
        buffer = ""
    end

    return true
end

HID.Press sleeps between the key down and the key up, so it only works inside a coroutine. Hooks like OnDown are not coroutines. Wrap the press in Run, which starts one and returns immediately. HID.Down, HID.Up, and HID.Type are native and can be called from a hook directly.


Browser tab navigation

Mouse4/Mouse5 navigate tabs in Chrome, Firefox, Edge, and Brave. Middle-click + Alt closes the tab. Completely inert in all other applications.

-- rebind: min_sdk=3.0.0
-- rebind: name=Browser Tabs
-- rebind: process=chrome.exe
-- rebind: process=firefox.exe
-- rebind: process=msedge.exe
-- rebind: process=brave.exe

function OnDown(key)
    if key == "Mouse4" then
        Run(function() HID.Press("LCtrl+PageUp") end)
        return false
    end
    if key == "Mouse5" then
        Run(function() HID.Press("LCtrl+PageDown") end)
        return false
    end
    if key == "Mouse3" and Input.IsDown("LAlt") then
        Run(function() HID.Press("LCtrl+W") end)
        return false
    end
    return true
end

Sticky modifier

Tap Shift once and it stays held until you tap it again. Useful for accessibility or one-handed workflows.

-- rebind: min_sdk=3.0.0
-- rebind: name=Sticky Modifier

local cfg = UI.Schema({
    target = UI.Keybind("LShift", { label = "Modifier to Toggle" }),
})

local held = false

function OnDown(key)
    if key == cfg.target then
        held = not held
        if held then
            HID.Down(cfg.target)
            UI.Notify("Modifier locked", "info")
        else
            HID.Up(cfg.target)
            UI.Notify("Modifier released", "info")
        end
        return false
    end
    return true
end

function OnUp(key)
    if key == cfg.target then
        return false
    end
    return true
end

function OnStop()
    if held then
        HID.Up(cfg.target)
    end
end

Precision mouse

Hold middle mouse to slow movement down to a configurable percentage. Useful for image editing, CAD, and other precision work.

-- rebind: min_sdk=3.0.0
-- rebind: name=Precision Mouse
-- rebind: mouse_block=true

local cfg = UI.Schema({
    hold_key = UI.Keybind("Mouse3",  { label = "Hold Key" }),
    slowdown = UI.Slider(25, { min = 5, max = 75, suffix = "%", label = "Speed %" }),
})

function OnMove(dx, dy)
    if Input.IsDown(cfg.hold_key) then
        local factor = cfg.slowdown / 100
        HID.Move(dx * factor, dy * factor)
        return false
    end
    return true
end

Intercepting mouse movement (mouse_block=true) requires a Rebind Link.


Photoshop shortcuts

Alt+scroll changes brush size. Mouse4/Mouse5 become undo/redo. Only active when Photoshop is focused.

-- rebind: min_sdk=3.0.0
-- rebind: name=Photoshop Shortcuts
-- rebind: process=Photoshop.exe

local cfg = UI.Schema({
    brush_step = UI.Slider(5, { min = 1, max = 20, label = "Brush Step" }),
})

function OnScroll(delta)
    if Input.IsDown("LAlt") then
        Run(function()
            for i = 1, cfg.brush_step do
                HID.Press(delta > 0 and "RightBrace" or "LeftBrace")
                Sleep(10)
            end
        end)
        return false
    end
    return true
end

function OnDown(key)
    if key == "Mouse4" then
        Run(function() HID.Press("LCtrl+Z") end)
        return false
    end
    if key == "Mouse5" then
        Run(function() HID.Press("LCtrl+LShift+Z") end)
        return false
    end
    return true
end

Advanced

Auto-clicker with timer

Toggle an auto-clicker with a hotkey. Uses Timer.Every for clean repeating intervals rather than a loop.

-- rebind: min_sdk=3.0.0
-- rebind: name=Auto Clicker

local cfg = UI.Schema({
    cps        = UI.Slider(5,  { min = 1, max = 20, label = "Clicks Per Second" }),
    toggle_key = UI.Keybind("F7", { label = "Toggle" }),
})

local active = false
local clickTimer = nil

function OnDown(key)
    if key == cfg.toggle_key then
        active = not active
        if active then
            clickTimer = Timer.Every(1000 / cfg.cps, function()
                Run(function() HID.Press("Mouse1", 20) end)
            end)
            UI.Notify("ON", "info")
        else
            if clickTimer then clickTimer:Cancel() end
            UI.Notify("OFF", "info")
        end
        return false
    end
    return true
end

function OnStop()
    if clickTimer then clickTimer:Cancel() end
end

Workflow hub

Mouse4/Mouse5 do different things depending on which app is focused, all from a single script.

-- rebind: min_sdk=3.0.0
-- rebind: name=Workflow Hub

local cfg = UI.Schema({
    enabled = UI.Toggle(true, { label = "Enable" }),
})

local function isProcess(name)
    return System.Window().process:lower():find(name:lower()) ~= nil
end

function OnDown(key)
    if not cfg.enabled then return true end

    if key == "Mouse4" then
        local combo
        if isProcess("Photoshop") then
            combo = "LCtrl+Z"
        elseif isProcess("chrome") or isProcess("firefox") or isProcess("msedge") then
            combo = "LCtrl+PageUp"
        elseif isProcess("explorer") then
            combo = "LAlt+Left"
        else
            return true
        end
        Run(function() HID.Press(combo) end)
        return false
    end

    if key == "Mouse5" then
        local combo
        if isProcess("Photoshop") then
            combo = "LCtrl+LShift+Z"
        elseif isProcess("chrome") or isProcess("firefox") or isProcess("msedge") then
            combo = "LCtrl+PageDown"
        elseif isProcess("explorer") then
            combo = "LAlt+Right"
        else
            return true
        end
        Run(function() HID.Press(combo) end)
        return false
    end

    return true
end

HTTP remote control

Control Rebind over HTTP: curl, Python, a browser, a home automation system.

-- rebind: min_sdk=3.0.0
-- rebind: name=HTTP Remote
-- rebind: permission=net

local cfg = UI.Schema({
    port = UI.Slider(8080, { min = 1024, max = 65535, label = "Port" }),
})

local server = nil

function OnStart()
    server = Net.Listen(cfg.port, function(req)
        if req.path == "/click" then
            Run(function() HID.Press("Mouse1") end)
            return { status = 200, body = "clicked" }
        elseif req.path == "/type" and req.body then
            HID.Type(req.body)
            return { status = 200, body = "typed" }
        elseif req.path == "/press" and req.body then
            local key = req.body
            Run(function() HID.Press(key) end)
            return { status = 200, body = "pressed" }
        end
        return { status = 404, body = "not found" }
    end)
    Log.Info("Listening on port " .. cfg.port)
end

function OnStop()
    if server then server:Stop() end
end

Send commands with curl: curl -X POST http://localhost:8080/type -d "Hello World"


Python IPC bridge

Communicate with an external Python process via shared memory. The Python side writes commands; the Rebind script reads and executes them. The Pipe API is Windows only.

-- rebind: min_sdk=3.0.0
-- rebind: name=Python Bridge

local pipe = nil

function OnStart()
    pipe = Pipe.Open("myapp", { size = 65536 })

    Timer.Every(10, function()
        local msg = pipe:Read()
        if msg then
            local data = JSON.Parse(msg)
            if data.action == "type" and data.text then
                HID.Type(data.text)
            elseif data.action == "press" and data.key then
                Run(function() HID.Press(data.key) end)
            end
        end
    end)
end

function OnStop()
    if pipe then pipe:Close() end
end

Python side. An external peer writes to channel B (offset size / 2); each channel is a 12-byte header (u64 sequence, u32 length) followed by the payload, and the sequence is written last:

import mmap, struct, json

shm = mmap.mmap(-1, 65536, tagname="Local\\Rebind_myapp")
offset = 65536 // 2
data = json.dumps({"action": "type", "text": "Hello from Python!"}).encode()

shm.seek(offset + 12)
shm.write(data)                        # payload first
shm.seek(offset + 8)
shm.write(struct.pack('<I', len(data)))  # then length
shm.seek(offset)
shm.write(struct.pack('<Q', 1))        # sequence number last

The wire protocol, plus complete Python, Rust, and Node peers, is documented in the Pipe reference.


Accessibility

Tremor smoothing

Filters out small jittery movements and applies exponential smoothing. Configurable threshold and smoothing strength.

-- rebind: min_sdk=3.0.0
-- rebind: name=Steady Hand
-- rebind: mouse_block=true

local cfg = UI.Schema({
    enabled   = UI.Toggle(true),
    smoothing = UI.Slider(50, { min = 0, max = 90, suffix = "%" }),
    threshold = UI.Slider(5,  { min = 1, max = 20, suffix = "px" }),
})

local buffer = { x = 0, y = 0 }

function OnMove(dx, dy)
    if not cfg.enabled then return true end

    local magnitude = math.sqrt(dx * dx + dy * dy)
    if magnitude < cfg.threshold then
        return false
    end

    local s = cfg.smoothing / 100
    buffer.x = buffer.x * s + dx * (1 - s)
    buffer.y = buffer.y * s + dy * (1 - s)

    HID.Move(buffer.x, buffer.y)
    return false
end

Intercepting mouse movement (mouse_block=true) requires a Rebind Link.


Dwell click

Click by hovering the cursor in one spot for a configurable duration. For users who cannot physically click a mouse button.

-- rebind: min_sdk=3.0.0
-- rebind: name=Dwell Click

local cfg = UI.Schema({
    enabled    = UI.Toggle(true),
    dwell_time = UI.Slider(1000, { min = 300, max = 3000, suffix = "ms" }),
    tolerance  = UI.Slider(10,   { min = 5, max = 50, suffix = "px" }),
    click_type = UI.Select("Left Click", { "Left Click", "Right Click", "Double Click" }),
    sound      = UI.Toggle(true, { label = "Audio Feedback" }),
})

local dwellStart = nil
local dwellPos = { x = 0, y = 0 }

function OnTick()
    if not cfg.enabled then dwellStart = nil return end

    local pos = Input.GetMousePos()
    local dx = pos.x - dwellPos.x
    local dy = pos.y - dwellPos.y

    if math.sqrt(dx*dx + dy*dy) > cfg.tolerance then
        dwellPos = pos
        dwellStart = System.Time()
        return
    end

    if not dwellStart then dwellStart = System.Time() return end

    if System.Time() - dwellStart >= cfg.dwell_time then
        if cfg.click_type == "Left Click" then
            Run(function() HID.Press("Mouse1") end)
        elseif cfg.click_type == "Right Click" then
            Run(function() HID.Press("Mouse2") end)
        elseif cfg.click_type == "Double Click" then
            Run(function()
                HID.Press("Mouse1", 30)
                Sleep(50)
                HID.Press("Mouse1", 30)
            end)
        end
        if cfg.sound then Audio.Beep() end
        dwellStart = nil
    end
end

Where to go from here

These scripts are starting points. The Documentation covers the full SDK. If you'd rather describe what you want in plain English, RebindGPT knows the SDK and writes the script for you.

The in-app marketplace has community-built scripts for gaming, streaming, productivity, and accessibility, each with a settings panel you can customize without touching code.

All posts