Productivity recipes
Your AutoHotkey or Karabiner logic, on any USB keyboard and mouse. The Rebind engine captures your input and runs your scripts; add the Rebind Link dongle for hardware output. Core input remapping runs on Windows, macOS, and Linux; some recipes below also use Clipboard and per-app window targeting, which are Windows/macOS only (noted per recipe).
Each recipe is a complete script. Copy it into a new script in the Rebind app and adjust the config.
Text expansion
Type a short abbreviation, then press a trigger key to expand it into full text. HID.Type sends each character through the hardware; for long or multi-line blocks, paste through the clipboard instead so it lands instantly and intact.
--[[
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 }),
address = UI.Text(
"123 Example St\nPortland, OR 97201",
{ label = "Address", maxLength = 200 }
),
})
local snippets = {}
function OnStart()
snippets = {
["@@"] = cfg.email,
[";addr"] = cfg.address,
["/date"] = os.date("%Y-%m-%d"),
["/time"] = os.date("%H:%M"),
}
end
local buffer = ""
function OnDown(key)
if key == cfg.trigger then
for abbr, expansion in pairs(snippets) do
if buffer:sub(-#abbr) == abbr then
Run(function()
for i = 1, #abbr do
HID.Press("Backspace")
Sleep(20)
end
-- multi-line text pastes intact; short text can use HID.Type
if expansion:find("\n") then
Clipboard.Set(expansion)
HID.Press("LCtrl+V")
else
HID.Type(expansion, 15)
end
end)
buffer = ""
return false
end
end
return false
end
-- track typed characters so we can match abbreviations
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
Tuning. Add more entries to the snippets table. Raise the HID.Type char delay (the 15) if an app drops characters; lower it for faster output. Multi-line blocks route through Clipboard.Set automatically.
Per-app shortcuts
A modeline scopes a script to one application by window title (window=) or executable (process=). The same physical key means one thing in your editor and nothing elsewhere — no profile switching, zero overhead when the app isn’t focused.
--[[
rebind: min_sdk=3.0.0
rebind: name=Editor Shortcuts
rebind: process=Code.exe
--]]
function OnDown(key)
-- F1 opens the command palette, only inside the editor
if key == "F1" then
Run(function()
HID.Press("LCtrl+LShift+P")
end)
return false
end
-- Mouse4 = undo, Mouse5 = redo
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
Tuning. Add multiple modelines to cover several apps; anything outside the match passes through untouched. (Windows/macOS only — see Platforms.) Full modeline semantics are in the SDK reference.
Clipboard transform
Read the clipboard, transform it in Luau, and paste the result. This example trims and lowercases the selection, but any string operation works — strip formatting, wrap in quotes, convert case, run a regex.
--[[
rebind: min_sdk=3.0.0
rebind: name=Clipboard Transform
--]]
local cfg = UI.Schema({
hotkey = UI.Keybind("F9", { label = "Transform + Paste" }),
})
Bind(
cfg.hotkey,
Async(function()
-- copy the current selection first
HID.Press("LCtrl+C")
Sleep(50)
local text = Clipboard.Get()
if not text or text == "" then
UI.Notify("Clipboard empty", "warning")
return
end
-- transform: trim whitespace and lowercase
local cleaned = text:gsub("^%s+", ""):gsub("%s+$", ""):lower()
Clipboard.Set(cleaned)
HID.Press("LCtrl+V")
end)
)
Tuning. Replace the cleaned line with your own transform. The Sleep(50) gives the foreground app time to populate the clipboard after the copy; raise it if the read comes back stale. Clipboard access is available on Windows and macOS.
Multi-step macro
Replay a fixed sequence of keystrokes on demand. Run plus Sleep controls each step and its timing; task:Cancel() aborts a long sequence mid-flight.
--[[
rebind: min_sdk=3.0.0
rebind: name=Macro Sequence
--]]
local cfg = UI.Schema({
play_key = UI.Keybind("F9", { label = "Play" }),
stop_key = UI.Keybind("F10", { label = "Stop" }),
})
local task = nil
function OnDown(key)
if key == cfg.play_key then
task = Run(function()
HID.Press("LCtrl+A") -- select all
Sleep(100)
HID.Press("LCtrl+C") -- copy
Sleep(100)
HID.Press("End") -- jump to end
HID.Press("Enter")
HID.Press("LCtrl+V") -- paste below
UI.Notify("Done", "success")
end)
return false
end
if key == cfg.stop_key and task and task:IsRunning() then
task:Cancel()
UI.Notify("Cancelled", "info")
return false
end
return true
end
function OnStop()
if task and task:IsRunning() then
task:Cancel()
end
end
Tuning. Edit the body of the Run block to define your sequence. Each Sleep is in milliseconds — tighten the delays for speed, widen them if a step fires before the previous one lands. To capture a sequence live instead of hand-writing it, see the macro recorder below.
Record and replay a macro
Capture a live sequence of keystrokes and mouse moves, then play it back with exact timing. Macro.Record starts capturing, Macro.Finish returns the recorded macro, and Macro.Play replays it — at any speed.
--[[
rebind: min_sdk=3.0.0
rebind: name=Macro Recorder
--]]
local cfg = UI.Schema({
record_key = UI.Keybind("F9", { label = "Record / Stop" }),
play_key = UI.Keybind("F10", { label = "Play" }),
speed = UI.Slider(100, { min = 25, max = 400, suffix = "%" }),
})
local recording = false
local macro = nil
function OnDown(key)
if key == cfg.record_key then
if recording then
macro = Macro.Finish()
recording = false
UI.Notify("Recorded " .. #macro .. " actions", "success")
else
Macro.Record({ ignore_mouse = false })
recording = true
UI.Notify("Recording — press again to stop", "info")
end
return false
end
if key == cfg.play_key and macro then
Macro.Play(macro, cfg.speed / 100)
return false
end
return true
end
Tuning. speed scales playback — 100 is the recorded speed, 200 plays it twice as fast. Pass { ignore_mouse = true } to Macro.Record to record keystrokes only. For frame-accurate, device-side replay use Macro.Stream(macro) instead of Macro.Play. The recorded action format and the macro transforms (Math.Scale, Math.Resample) are in the SDK reference.
Scroll to zoom
Hold a modifier and scroll to zoom in browsers, editors, and image viewers — the standard Ctrl + scroll gesture, bound to any key you prefer.
--[[
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
Tuning. Change modifier to any key. To slow the zoom, scale delta before passing it to HID.Scroll (for example, HID.Scroll(delta // 2)). Returning false swallows the original scroll so only the zoom fires.
Set your mouse output rate
A live demonstration of the 8,000 Hz loop: capture every raw mouse movement and re-emit it at exactly the rate you choose — effectively setting your mouse’s output polling rate. mouse_block=true hands OnMove control of every event (this requires a Rebind device), and an OnTick running at 8 kHz decides when to flush the accumulated motion.
--[[
rebind: min_sdk=3.0.0
rebind: name=Mouse Rate Limiter
rebind: mouse_block=true
rebind: tick_rate=8000
--]]
local cfg = UI.Schema({
rate = UI.Slider(
125,
{ min = 60, max = 1000, suffix = "Hz", label = "Output Rate" }
),
})
local accX, accY = 0, 0
local startTime = nil
local lastEmitTime = nil
function OnMove(dx, dy)
accX = accX + dx
accY = accY + dy
return false
end
function OnTick()
local now = System.Time()
if not startTime then
startTime = now
lastEmitTime = now
return
end
local interval = 1000 / cfg.rate
local elapsed = now - startTime
local expectedEmits = math.floor(elapsed / interval)
local actualEmits = math.floor((lastEmitTime - startTime) / interval)
if expectedEmits > actualEmits then
lastEmitTime = now
if accX ~= 0 or accY ~= 0 then
HID.Move(accX, accY)
accX, accY = 0, 0
end
end
end
Tuning. rate is the output rate in Hz — lower it to throttle a high-polling-rate mouse, raise it toward the device’s own rate. No motion is lost: OnMove accumulates the raw deltas and OnTick flushes them on schedule, so the cursor’s path is preserved and only its timing changes. This needs mouse_block=true (so OnMove can hold each event, hardware mode only) and a high tick_rate for an accurate output clock — see the scripting guide.
Mouse acceleration
Add a speed-dependent acceleration curve to any mouse: slow movements stay close to 1:1 for precision, fast flicks get multiplied so you cross the screen with less travel. mouse_block=true hands OnMove every raw event (requires a Rebind device), so the script rescales each delta and re-emits it with HID.Move — curve, threshold, and ceiling are all live in the config panel.
--[[
rebind: min_sdk=3.0.0
rebind: name=Mouse Acceleration
rebind: mouse_block=true
--]]
local cfg = UI.Schema({
enabled = UI.Toggle(true, { label = "Enable Acceleration" }),
toggle_key = UI.Keybind("F7", { label = "Toggle Key" }),
curve = UI.Select(
"Quadratic",
{ "Linear", "Quadratic", "Cubic", "Exponential" },
{ label = "Curve Type" }
),
multiplier = UI.Slider(
2.0,
{ min = 1.0, max = 5.0, step = 0.1, suffix = "x", label = "Max Multiplier" }
),
threshold = UI.Slider(
5,
{ min = 1, max = 30, suffix = "px", label = "Accel Threshold" }
),
sensitivity = UI.Slider(
100,
{ min = 25, max = 200, suffix = "%", label = "Base Sensitivity" }
),
})
local function getSpeed(dx, dy)
return math.sqrt(dx * dx + dy * dy)
end
local function applyAccel(speed)
local base = cfg.sensitivity / 100
local threshold = cfg.threshold
if speed <= threshold then
return base
end
local excess = speed - threshold
local maxMult = cfg.multiplier
local factor
if cfg.curve == "Linear" then
factor = 1 + (excess / 20) * (maxMult - 1)
elseif cfg.curve == "Quadratic" then
factor = 1 + (excess / 20) ^ 2 * (maxMult - 1)
elseif cfg.curve == "Cubic" then
factor = 1 + (excess / 20) ^ 3 * (maxMult - 1)
elseif cfg.curve == "Exponential" then
factor = 1 + (math.exp(excess / 20) - 1) * (maxMult - 1) / (math.exp(1) - 1)
else
factor = 1
end
factor = math.min(factor, maxMult)
return base * factor
end
function OnDown(key)
if key == cfg.toggle_key then
cfg.enabled = not cfg.enabled
UI.Notify(cfg.enabled and "Acceleration ON" or "Acceleration OFF", "info")
return false
end
return true
end
function OnMove(dx, dy)
if not cfg.enabled then
return true
end
local speed = getSpeed(dx, dy)
if speed == 0 then
return false
end
local factor = applyAccel(speed)
HID.Move(dx * factor, dy * factor)
return false
end
Tuning. curve controls how aggressively the multiplier ramps once a movement passes threshold — Linear is gentle, Exponential is sharp. multiplier caps the fastest flicks; sensitivity scales everything, slow moves included. Anything under threshold px stays at base sensitivity for pixel-precise aiming, and the bound key toggles the whole effect on the fly. Like the rate limiter, this needs mouse_block=true so OnMove can swallow the raw event and emit the accelerated one — hardware mode only (see the scripting guide).