1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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
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
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