marketplace/productivity

Quick Replies

Six shortcut slots that type a saved reply, address, date or timestamp into the focused app.

@rebindv0.1.0free

More install options
$rebind install @rebind/quick-replies

Gallery

Quick Replies preview

Readme

Six slots. Each holds a line of text and a key. Hold the modifier, press the key, release, and the text is typed into whatever has focus.

Setup

  1. Pick the modifier in Settings. The default is Ctrl+Alt.
  2. Open a slot tab, set its key and its text.
  3. Restart the script after changing a key. Text edits apply immediately.

Tokens

  • {date} and {time} expand with the formats in Settings (os.date syntax, so %Y-%m-%d and %H:%M work).
  • {datetime} is both, separated by a space.
  • \n in the text becomes a new line.

How it types

Text is typed through the operating system, not through the Rebind Link, so it works the same in hardware and software mode and carries Unicode. Insertion waits until the chord is released; a slot with no text raises a notice instead of typing nothing.

Limits

  • The slot key is captured system wide while the script runs. Other uses of that exact chord in other apps will not fire.
  • Some apps drop characters when text arrives faster than they read it. Shorter replies are safer than paragraphs.

Reviews

No reviews yet. Write a review in the app.

Source

Version 0.1.0 (current)

main.luau

-- Quick Replies: a chord types a saved line into whatever has focus.

local SLOTS = 6

local MOD_NAMES = {
  "Ctrl+Alt",
  "Ctrl+Shift",
  "Alt+Shift",
  "Ctrl+Alt+Shift",
  "Cmd/Win+Alt",
  "Cmd/Win+Shift",
}
local MODS = {
  ["Ctrl+Alt"] = { ctrl = true, alt = true },
  ["Ctrl+Shift"] = { ctrl = true, shift = true },
  ["Alt+Shift"] = { alt = true, shift = true },
  ["Ctrl+Alt+Shift"] = { ctrl = true, alt = true, shift = true },
  ["Cmd/Win+Alt"] = { win = true, alt = true },
  ["Cmd/Win+Shift"] = { win = true, shift = true },
}

local schema = {
  modifier = UI.Select(
    "Ctrl+Alt",
    MOD_NAMES,
    { label = "Modifier held with every slot key", tab = "Settings" }
  ),
  dateFormat = UI.Text("%Y-%m-%d", {
    label = "{date} format",
    placeholder = "%Y-%m-%d",
    tab = "Settings",
  }),
  timeFormat = UI.Text("%H:%M", {
    label = "{time} format",
    placeholder = "%H:%M",
    tab = "Settings",
  }),
}
for n = 1, SLOTS do
  schema[`key{n}`] =
    UI.Keybind(tostring(n), { label = "Key", tab = `Slot {n}` })
  schema[`text{n}`] = UI.Text("", {
    label = "Text",
    placeholder = "Thanks, {date}. Use \\n for a new line.",
    maxLength = 2000,
    tab = `Slot {n}`,
  })
end
local cfg = UI.Schema(schema)

local function chordHeld()
  local want = MODS[cfg.modifier] or {}
  local have = Input.GetModifiers()
  for _, m in { "ctrl", "alt", "shift", "win" } do
    if (want[m] == true) ~= have[m] then
      return false
    end
  end
  return true
end

local function expand(text)
  local tokens = {
    date = os.date(cfg.dateFormat),
    time = os.date(cfg.timeFormat),
    datetime = os.date(cfg.dateFormat .. " " .. cfg.timeFormat),
  }
  local out = text:gsub("{(%w+)}", function(name)
    return tokens[name]
  end)
  return (out:gsub("\\n", "\n"))
end

-- type only after the chord is fully released: a modifier still held turns
-- the inserted characters into shortcuts in the receiving app.
local function insert(n)
  Run(function()
    local waited = 0
    while waited < 1000 do
      local m = Input.GetModifiers()
      if not (m.ctrl or m.alt or m.shift or m.win) then
        break
      end
      Sleep(10)
      waited += 10
    end
    if waited >= 1000 then
      UI.Notify("Release the modifier keys to insert", "warning")
      return
    end
    local text = cfg[`text{n}`]
    if text == "" then
      UI.Notify(`Slot {n} has no text`, "warning")
      return
    end
    local ok, err = pcall(System.TypeText, expand(text))
    if not ok then
      Log.Error(`slot {n}: {err}`)
      UI.Notify(`Slot {n} could not be typed`, "error")
    end
  end)
end

for n = 1, SLOTS do
  Bind(cfg[`key{n}`], {
    when = chordHeld,
    action = function()
      return nil
    end,
    release = function()
      insert(n)
    end,
  })
end

function OnStart()
  Log.Info(
    `{cfg.modifier} + slot key types the slot. Change keys, then restart the script.`
  )
end