marketplace/apps

App Keys

One chord per app: focus its window if it is running, launch it if it is not.

@rebindv0.1.1free

More install options
$rebind install @rebind/app-keys

Gallery

App Keys preview

Readme

Six slots. Each slot pairs a key with an application. Hold the modifier, press the key: the app's window comes forward if it is running, otherwise the app is launched.

Setup

  1. Pick the modifier in Settings. The default is Ctrl+Alt; slot keys default to F1 through F6.
  2. In each slot tab, set the key and the application.
    • Windows: the executable name, for example notepad.exe or code.exe. If the executable is not on your PATH, use the full path. Arguments are optional and split on spaces.
    • macOS: the application name as it appears in Finder, for example Safari. Arguments are not used.
  3. Restart the script after changing a key.

Behavior

  • Windows: a visible window whose process matches the executable name is focused. The window is restored if minimized, and a maximized window stays maximized. If the operating system refuses to change focus, or the launch fails, the reason is logged and shown as a notice.
  • macOS: activation goes through the system's own launch or focus path for the named application. A missing application is reported the same way.

Limits

  • Slot keys are captured system wide while the script runs.
  • Matching is by process name only. Two apps that share an executable name resolve to whichever window the system lists first.

Reviews

No reviews yet. Write a review in the app.

Source

main.luau

-- App Keys: a chord focuses a running app or launches it.

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 IS_MAC = _REBIND.platform == "macos"

local schema = {
  modifier = UI.Select(
    "Ctrl+Alt",
    MOD_NAMES,
    { label = "Modifier held with every slot key", tab = "Settings" }
  ),
}
for n = 1, SLOTS do
  local tab = `Slot {n}`
  schema[`key{n}`] = UI.Keybind(`F{n}`, { label = "Key", tab = tab })
  schema[`app{n}`] = UI.Text("", {
    label = if IS_MAC then "Application name" else "Executable",
    placeholder = if IS_MAC then "Safari" else "notepad.exe",
    tab = tab,
  })
  schema[`args{n}`] = UI.Text("", {
    label = "Arguments",
    placeholder = if IS_MAC then "not used on macOS" else "--new-window",
    tab = tab,
  })
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 report(n, message)
  Log.Warn(`slot {n}: {message}`)
  UI.Notify(message, "warning")
end

-- Windows: a running app is a visible window whose process name contains
-- the configured executable name (notepad.exe matches "notepad.exe" and
-- "notepad"). Window.List reports the file name only, so a full path is
-- reduced to its file name before matching. Focus it; otherwise launch the
-- executable with its arguments.
local function windowsActivate(n, app, args)
  local needle = app:lower():gsub("^.*[\\/]", ""):gsub("%.exe$", "")
  for _, w in Window.List() do
    if w.process:lower():find(needle, 1, true) then
      local ok, err = pcall(Window.Activate, w.handle)
      if not ok then
        report(n, `could not focus {w.process}: {err}`)
      end
      return
    end
  end
  local argv = {}
  for word in args:gmatch("%S+") do
    table.insert(argv, word)
  end
  local ok, err = pcall(System.ExecDetached, app, argv)
  if not ok then
    report(n, `could not launch {app}: {err}`)
  end
end

-- macOS: App.Activate launches or focuses by application name and reports
-- when the app cannot be found. Arguments do not apply.
local function macActivate(n, app)
  local ok, err = pcall(App.Activate, app)
  if not ok then
    report(n, `could not activate {app}: {err}`)
  end
end

for n = 1, SLOTS do
  Bind(cfg[`key{n}`], {
    when = chordHeld,
    action = function()
      local app = cfg[`app{n}`]
      if app == "" then
        report(n, `slot {n} has no application`)
      elseif IS_MAC then
        macActivate(n, app)
      else
        windowsActivate(n, app, cfg[`args{n}`])
      end
      return nil
    end,
  })
end

function OnStart()
  Log.Info(
    `{cfg.modifier} + slot key focuses or launches the slot's app. Change keys, then restart the script.`
  )
end