-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyconfig.lua
217 lines (192 loc) · 8.46 KB
/
keyconfig.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
-- lk.isDown()
local shortcutsDown = {}
-- love.keypressed()
local shortcutsPressed = {}
local shortcutsList = nil
local lk = love.keyboard
local function combo2str(comboTbl)
local res = "["
for k, v in pairs(comboTbl) do
res = res .. v
if k < #comboTbl then
res = res .. "+"
end
end
return res .. "]"
end
local function prepareDrawing()
shortcutsList = require "list":new(5, 5)
for k, v in pairs(shortcutsDown) do
shortcutsList:add(v.description .. " " .. combo2str(v.combo), k)
end
for k, v in pairs(shortcutsPressed) do
shortcutsList:add(v.description .. " " .. combo2str(v.combo), k)
end
table.sort(shortcutsList.items, function(a, b)
return a.id < b.id
end)
shortcutsList:done()
end
local function drawList()
if not shortcutsList then
prepareDrawing()
end
shortcutsList:draw()
end
local function updateList()
if shortcutsList then
shortcutsList:update(dt)
end
end
-- рисовать список шорткатов, расположенный в определенных координатах
local function drawShortcutsList(x0, y0)
x0 = x0 and x0 or 0
y0 = y0 and y0 or 0
local x, y = x0, y0
local maxStringWidth = 0 -- сюда складывается максимальная длина строки символов, которая будет выводиться.
local delimiter = "+"
-- формирует и возвращает таблицу со списком комбинаций клавиш и описания их действия
function makeTextList(list)
local textList = {}
for k, v in pairs(list) do
local keyCombination = ""
for k, keyValue in pairs(v.combo) do
if k < #v.combo then
keyCombination = keyValue .. delimiter .. keyCombination
else
keyCombination = keyCombination .. keyValue
end
end
local common = {}
common[#common + 1] = {1, 0, 0} -- index 1
common[#common + 1] = "\"" .. keyCombination .. "\"" -- 2
common[#common + 1] = {0, 1, 0} -- 3
common[#common + 1] = ": " .. v.description -- 4
table.insert(textList, common) -- строка с цветами и строками для рисовки через lg.print()
local textLen = string.len(common[2]) + string.len(common[4])
maxStringWidth = textLen > maxStringWidth and textLen or maxStringWidth -- определение самой длинной текстовой строки для вывода цветного фонового прямоугольника
end
return textList
end
-- для списка list расчитывает высоту рисуемого поля текущим шрифтом
function calcHeight(list)
local h = 0
for k, v in pairs(list) do
h = h + lg.getFont():getHeight()
end
return h
end
local tmpFont = lg.getFont()
lg.setFont(keyBindingsFont)
local list1, list2 = makeTextList(shortcutsPressed), makeTextList(shortcutsDown)
-- XXX: здесь применен частный случай(workaround) - считается длина строки, потом считается ширина строки 'zzzzzzzzzzzzzzzzzz' такой длины.
local str = ""
for i = 1, maxStringWidth do str = str .. "z" end
--
-- расчет размера выводимого прямоугольника подложки
local rectW, rectH = lg.getFont():getWidth(str), (calcHeight(shortcutsDown) + calcHeight(shortcutsPressed))
lg.rectangle("fill", x0, y0, rectW, rectH)
local oldWidth = lg.getLineWidth()
local delta = 1
lg.setLineWidth(3)
lg.setColor{1, 0, 1}
lg.rectangle("line", x0 - delta, y0 - delta, rectW + delta, rectH + delta)
lg.setLineWidth(oldWidth)
lg.setColor{1, 1, 1}
function drawList(list)
for k, v in pairs(list) do
lg.print(v, x, y) -- выводится цветной текст
y = y + lg.getFont():getHeight()
end
end
drawList(list1) drawList(list2)
lg.setFont(tmpFont)
end
-- usage example:
-- bindKey({"q"}, quit)
-- bindKey({"lshift", "x"}, changeCameraMode)
-- use scancode
local function bindKeyDown(stringID, keyCombination, action, description)
assert(action, "action == nil in bindKey()")
assert(stringID, "stringID should'not be empty")
assert(action, "action == nil in bindKeyDown()")
--[[здесь добавить проверки в таблице keyCombination на допустимость закодированных в них сочетаний. Если сочетание клавиш используется, то вызывать
исключение, которое в идеале может обработать вызывающая функция.
--]]
-- assert(shortcuts[stringID]) -- слот должен быть пустой
-- assert(description, "description == nil in bindKey()")
-- извлечь из keyCombination значения
-- проверить на дубликаты
description = description and description or ""
shortcutsDown[stringID] = {combo = keyCombination, action = action,
description = description, enabled = true}
end
-- должна быть возможность запускать с пустым stringID
-- может поле description поставить после stringID?
local function bindKeyPressed(stringID, keyCombination, action, description)
assert(action, "action == nil in bindKeyPressed()")
assert(description, "description == nil in bindKeyPressed()")
shortcutsPressed[stringID] = {combo = keyCombination, action = action,
description = description, enabled = true}
end
-- очень неподходящее название
-- TODO: работает странно, если определить несколько горячих клавиш, к примеру f1 и f1+lshift
local function checkPressedKeys(key)
for k, v in pairs(shortcutsPressed) do
if v.enabled then
-- обрати внимание на магию - первый элемент проверяется на love.keypressed(),
-- а последущие - как дополнительные модификаторы на lk.isDown()
local pressed = key == v.combo[1]
-- print("checkKeyboardInput2", key, v.combo[1])
-- print("#shortcuts2", #shortcuts2, inspect(shortcuts2))
for i = 2, #v.combo do
-- print("checkKeyboardInput2", k, v.combo[i])
pressed = pressed and lk.isDown(v.combo[i]) -- эта строчка что делает? Добавляет проверку модификатора при нажатии клавиш.
if not pressed then break end
end
if pressed and v.action then
-- print("call action on shortcuts2", inspect(v.combo))
v.action()
end
end
end
end
-- проверка ввода. Используются значения, заранее
-- установленные при помощи bindKey(). Проверка выполняется через lk.isDown()
local function checkDownKeys()
-- а в чем хранить значения keyCombination? как назвать глобальную переменную?
for k, v in pairs(shortcutsDown) do
if v.enabled then
local pressed = true
for _, keyValue in pairs(v.combo) do
pressed = pressed and lk.isScancodeDown(keyValue)
if not pressed then break end -- если хоть одна клавиша в комбинации не нажата, то сбрасываю комбинацию.
end
if pressed and v.action then
v.action()
end
end
end
end
local function send(stringID)
local t = shortcutsDown[stringID]
if t and t.enabled and t.action then
t.action()
else
t = shortcutsPressed[stringID]
if t and t.enabled and t.action then
t.action()
end
end
end
return {
bindKeyPressed = bindKeyPressed,
bindKeyDown = bindKeyDown,
checkDownKeys = checkDownKeys,
checkPressedKeys = checkPressedKeys,
shortcutsPressed = shortcutsPressed,
drawShortcutsList = drawShortcutsList,
send = send,
updateList = updateList,
drawList = drawList,
}