-
Notifications
You must be signed in to change notification settings - Fork 1
/
keychains.lua
282 lines (250 loc) · 6.49 KB
/
keychains.lua
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
----------------------------------------------------------------------------
-- @author Zsolt Udvari <[email protected]>
-- @copyright 2012-2013 Zsolt Udvari
-- @license GPLv2
-- @release 1.1
-- (tested with awesome 3.5)
----------------------------------------------------------------------------
-- Grab environment
local pairs = pairs
local type = type
local awful = require("awful")
local root = root
local naughty = require("naughty")
local capi = { timer = timer }
module("keychains")
-- variables
local keychain = {}
local globalkeys = {}
local chains = {}
local notify = nil
local menu = nil
local options = {}
-- the keygrabber object
local grabber
-- the timer object of timeout
local timer_timeout
---
-- Parameters for function 'init'.
-- @field menu menu options
-- @field notify notify options
--
-- The options are awesome-compatible.
-- @see init
-- @table opt
---
---
-- Initialize the Keychain object.
--
-- @param globkeys the main root-hotkeys (without keychains!)
-- @param opt table of notify's and menu's options.
--
-- The 'text', 'icon', 'title' and 'timeout' fields in notify is ignored!
--
-- The options of notify and menu are awesome-compatible (see awesome's
-- documentation).
-- @see opt
---
function init(globkeys,opt)
globalkeys = globkeys
opt = opt or {}
opt["notify"] = opt["notify"] or {}
opt["menu"] = opt["menu"] or {}
-- the text, icon, title and timeout field is set at runtime
local v
for _,v in pairs({"text","icon","title","timeout"}) do
opt["notify"][v] = nil
end
options["notify"] = opt["notify"]
options["menu"] = opt["menu"]
end
---
-- Starts the keychain-grabs.
-- @param timeout seconds to cancel after first key the hotkey-grabbing.
-- 0 means no timeout.
---
function start(timeout)
timeout = timeout or 0
timer_timeout = capi.timer({timeout = timeout})
if (timeout>0) then
timer_timeout:connect_signal("timeout",function()
reset()
end)
end
root.keys( awful.util.table.join(
globalkeys,
chains
))
end
---
-- Stop the keychain-grabs. It's very possible that you will not
-- use this function.
---
function stop()
root.keys( globalkeys )
end
---
-- Hotkey table.
-- @field func function to call
-- @field info information to show
-- @table hotkeys
-- @see add
---
---
-- Add a new keychain-table.
-- @param mod_hk hotkey modifiers (table, same as in awful.key)
-- @param hk hotkey to jump into this hotkey-chain
-- @param title title of hotkeys
-- @param icon icon to show
-- @param hotkeys table, keys of table are hotkey.
-- @param style one of notify or menu (default is notify)
--
-- The param hotkeys can be a function which returns table as describe
-- in table hotkeys.
-- @see hotkeys
---
function add(mod_hk,hk,title,icon,hotkeys,style)
local nr = #(keychain)+1
keychain[nr] = keychain[nr] or {}
keychain[nr].icon = icon
keychain[nr].title = title
keychain[nr].hotkeys = hotkeys
keychain[nr].style = style or "notify"
chains = awful.util.table.join(
chains,
awful.key(mod_hk,hk,function()
activite(nr)
end)
)
end
---
-- Returns the hotkeys.
-- @param which which table
-- @return table.
-- If hotkeys is a function get_hotkeys will return hotkeys result else will return hotkeys.
---
function get_hotkeys(which)
local ret
if (type(keychain[which]["hotkeys"])=="function") then
ret = keychain[which].hotkeys()
else
ret = keychain[which].hotkeys
end
return ret
end
---
-- Generate information about hotkeys
-- @param which which table
-- @return information string
---
function get_info(which)
local i,hk
local txt = ""
local hotkeys = get_hotkeys(which)
for i,hk in pairs(hotkeys) do
txt = txt .. i .. " " ..
(hk.info or awful.util.escape("[[ no description ]]")) .. "\n"
end
return txt
end
---
-- Generate menu
-- @param which which table
-- @return awful.menu
---
function get_menu(which)
local i,hk
local menu = {}
local hotkeys = get_hotkeys(which)
for i,hk in pairs(hotkeys) do
menu[i] =
{
i .. " || " .. (hk.info or awful.util.escape("[[ no description ]]")),
cmd = function()
reset()
hk.func()
end,
}
end
return awful.menu({
items = menu,
theme = options["menu"]
})
end
---
-- Generate awful keys
-- @param which which hotkeys
-- @return awesome-compatible table
---
function get_awful_keys(which)
local i, hkt,ret
local hotkeys = get_hotkeys(which)
ret = {}
for i,hkt in pairs(hotkeys) do
ret = awful.util.table.join(
ret,
awful.key({},i,function()
reset()
hkt.func()
end)
)
end
return ret
end
---
-- Activite a keychain and displays its information.
-- @param which which keychain should activite
---
function activite(which)
timer_timeout:start()
local style = keychain[which].style or "notify"
if (style=="menu") then
menu = get_menu(which)
menu:show()
elseif (style=="notify") then
notify = naughty.notify(awful.util.table.join(
{
title = keychain[which].title,
text = get_info(which),
icon = keychain[which].icon,
timeout = 0
}, options["notify"]
))
end
grabber = awful.keygrabber.run(function(mod,key,event)
local hotkeys = get_hotkeys(which)
if event == "release" then return end
if key == "Escape" then
reset()
elseif hotkeys[key] then
reset()
hotkeys[key].func()
elseif menu then
if key == "Up" or key == "Down" or key == "Return" then
-- we will pass these keys to displayed 'menu'
return false
end
else
-- what do we if user press a bad key?
-- maybe beep or similar or a user-specified function?
end
end)
end
---
-- Reset keychains.
-- Reset the hotkeys and destroy the keychain notify.
---
function reset()
timer_timeout:stop()
if grabber then
awful.keygrabber.stop(grabber)
end
if naughty then
naughty.destroy(notify)
end
if menu then
menu:hide()
-- we need to delete because 'activite' function checks it
menu = nil
end
end