From 060d8740f5f7ed49f2ae1c2643e20c9f61eab53b Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Sat, 7 Jan 2012 18:00:07 -0200 Subject: [PATCH] lua hotkeys system --- TODO | 3 - modules/addon_terminal/terminal.lua | 12 +- modules/addon_terminal/terminal.otui | 1 + modules/client_entergame/entergame.lua | 4 +- modules/client_options/options.lua | 38 ++++-- modules/client_options/options.otui | 4 +- modules/client_topmenu/topmenu.lua | 21 ++-- modules/core_lib/.hotkeys.lua.swp | Bin 0 -> 12288 bytes modules/core_lib/const.lua | 168 +++++++++++++++++++++---- modules/core_lib/core_lib.otmod | 1 + modules/core_lib/ext/string.lua | 29 +++-- modules/core_lib/ext/table.lua | 12 +- modules/core_lib/hotkeys.lua | 92 +++++++++++++- 13 files changed, 318 insertions(+), 67 deletions(-) create mode 100644 modules/core_lib/.hotkeys.lua.swp diff --git a/TODO b/TODO index 20c7889f..19518818 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ == Core -[bart] a class for binding hotkeys [bart] review directories loading search [bart] load modules from zip packages [bart] create a class for reading binary files @@ -44,12 +43,10 @@ [bart] padding [bart] review and make more error prone with more warnings [bart] a real working border and background property in otui -[bart] merge states declared in inherited styles [bart] reapply anchor styles when adding new childs == Client modules [bart] modules managment interface -[bart] restore Console key binding [bart] console history, text selection, scrolling == Client diff --git a/modules/addon_terminal/terminal.lua b/modules/addon_terminal/terminal.lua index 8eed8ad6..8d43f60e 100644 --- a/modules/addon_terminal/terminal.lua +++ b/modules/addon_terminal/terminal.lua @@ -124,7 +124,8 @@ function Terminal.init() terminalWidget = displayUI('terminal.otui') terminalWidget:setVisible(false) - terminalButton = TopMenu.addButton('terminalButton', 'Terminal', '/core_styles/icons/terminal.png', Terminal.show) + terminalButton = TopMenu.addButton('terminalButton', 'Terminal (Ctrl + T)', '/core_styles/icons/terminal.png', Terminal.toggle) + Hotkeys.bind('Ctrl+T', Terminal.toggle) commandLineEdit = terminalWidget:getChildById('commandLineEdit') connect(commandLineEdit, { onKeyPress = onCommandLineKeyPress }) @@ -135,6 +136,7 @@ function Terminal.init() end function Terminal.terminate() + Hotkeys.unbind('Ctrl+T') Logger.setOnLog(nil) terminalButton:destroy() terminalButton = nil @@ -145,6 +147,14 @@ function Terminal.terminate() commandEnv = nil end +function Terminal.toggle() + if terminalWidget:isVisible() then + Terminal.hide() + else + Terminal.show() + end +end + function Terminal.show() terminalWidget:show() terminalWidget:lock() diff --git a/modules/addon_terminal/terminal.otui b/modules/addon_terminal/terminal.otui index fc9a3793..0d6eec95 100644 --- a/modules/addon_terminal/terminal.otui +++ b/modules/addon_terminal/terminal.otui @@ -7,6 +7,7 @@ RectPanel background-color: #000000 opacity: 216 anchors.fill: parent + @onEscape: Terminal.hide() Panel id: terminalBuffer diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 58dba10e..790d864d 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -54,7 +54,8 @@ end -- public functions function EnterGame.init() - enterGameButton = TopMenu.addButton('enterGameButton', 'Login', '/core_styles/icons/login.png', EnterGame.openWindow) + enterGameButton = TopMenu.addButton('enterGameButton', 'Login (Ctrl + G)', '/core_styles/icons/login.png', EnterGame.openWindow) + Hotkeys.bind('Ctrl+G', EnterGame.openWindow) motdButton = TopMenu.addButton('motdButton', 'Message of the day', '/core_styles/icons/motd.png', EnterGame.displayMotd) motdButton:hide() enterGame = displayUI('entergame.otui') @@ -79,6 +80,7 @@ function EnterGame.init() end function EnterGame.terminate() + Hotkeys.unbind('Ctrl+G') enterGame:destroy() enterGame = nil enterGameButton:destroy() diff --git a/modules/client_options/options.lua b/modules/client_options/options.lua index eb5d7d2b..d5c887c4 100644 --- a/modules/client_options/options.lua +++ b/modules/client_options/options.lua @@ -1,17 +1,15 @@ Options = {} +local optionsWindow local optionsButton function Options.init() - optionsButton = TopMenu.addButton('settingsButton', 'Options', '/core_styles/icons/settings.png', Options.show) - Options.load() -end - -function Options.terminate() - TopMenu.removeButton(optionsButton) -end + optionsWindow = displayUI('options.otui') + optionsWindow:setVisible(false) + optionsButton = TopMenu.addButton('settingsButton', 'Options (Ctrl+O)', '/core_styles/icons/settings.png', Options.toggle) + Hotkeys.bind('Ctrl+O', Options.toggle) -function Options.load() + -- load settings local booleanOptions = { vsync = true, showfps = true, fullscreen = false, @@ -23,8 +21,30 @@ function Options.load() end end +function Options.terminate() + Hotkeys.unbind('Ctrl+O') + optionsWindow:destroy() + optionsWindow = nil + optionsButton:destroy() + optionsButton = nil +end + +function Options.toggle() + if optionsWindow:isVisible() then + Options.hide() + else + Options.show() + end +end + function Options.show() - displayUI('options.otui', { locked = true }) + optionsWindow:show() + optionsWindow:lock() +end + +function Options.hide() + optionsWindow:unlock() + optionsWindow:hide() end function Options.openWebpage() diff --git a/modules/client_options/options.otui b/modules/client_options/options.otui index e5f688aa..b3fe2daf 100644 --- a/modules/client_options/options.otui +++ b/modules/client_options/options.otui @@ -20,6 +20,8 @@ MainWindow id: optionsWindow title: Options size: 286 140 + @onEnter: Options.hide() + @onEscape: Options.hide() OptionCheckBox id: vsync @@ -45,4 +47,4 @@ MainWindow anchors.bottom: parent.bottom margin-right: 10 margin-bottom: 10 - @onClick: self:getParent():destroy() \ No newline at end of file + @onClick: Options.hide() \ No newline at end of file diff --git a/modules/client_topmenu/topmenu.lua b/modules/client_topmenu/topmenu.lua index 32d93260..d1c5de34 100644 --- a/modules/client_topmenu/topmenu.lua +++ b/modules/client_topmenu/topmenu.lua @@ -5,24 +5,27 @@ local topMenu local leftButtonsPanel local rightButtonsPanel +-- private functions +local function onLogout() + if Game.isOnline() then + Game.logout(false) + else + exit() + end +end + -- public functions function TopMenu.init() topMenu = displayUI('topmenu.otui') leftButtonsPanel = topMenu:getChildById('leftButtonsPanel') rightButtonsPanel = topMenu:getChildById('rightButtonsPanel') - TopMenu.addRightButton('logoutButton', 'Logout', '/core_styles/icons/logout.png', - function() - if Game.isOnline() then - Game.logout(false) - else - exit() - end - end - ) + TopMenu.addRightButton('logoutButton', 'Logout (Ctrl+Q)', '/core_styles/icons/logout.png', onLogout) + Hotkeys.bind('Ctrl+Q', onLogout) end function TopMenu.terminate() + Hotkeys.unbind('Ctrl+Q') leftButtonsPanel = nil rightButtonsPanel = nil topMenu:destroy() diff --git a/modules/core_lib/.hotkeys.lua.swp b/modules/core_lib/.hotkeys.lua.swp new file mode 100644 index 0000000000000000000000000000000000000000..32e3325d4a3478dd3c708b142056d72bbf7e6d2f GIT binary patch literal 12288 zcmeI2O>7la6vw9;rJ^9}#z-{7hqh=-zi9yrwy&=rw6A^bYiap*-n`qsq4Q=QGxMNL zEyN9yU>C*>EJ#e;kfFa6?enx^N>HB{3TRbMBopEr_s%Op{;d{{QF9 zojYglop+nQeB<7MjNZPrMZ?cJO*?$HdSq;RwN`vV)AEKFg!a9D49_eUgg<+)ypv&v z4Q0dtF%+N znMc$OomR)H+m1>mhok~Y1(FIR6-X+OR3NE9Qh}rbNd=M$Bo#<1kW}CStbkF_w9}7j z+Lw=E@c93K^!NYGr#0;c_zC<7J_GN8CGajd3WmWRFaSEhi=YbpyjIh`2cLuU;B7Di zGN27S1O8frJa83!3NCsrt8R?Gu`lL-f^c$pbVAB2g;Twhbe;2l&zqadWnRmQjrtX{;!D6z&NPO zu%o-Q&}SH--}ogjao23R^n)JdQh2T#Oj?B*5!C4my6X&z`K%{=U+;t%Ly(QdEt)1A zyz*_=H0;}=wI@^``0iE8Er>cDjd3xDUeULC}dc zbu}l|AjhnkVvwqM_IwnHYSC?Yk@c2J9um_la~D*g&ohp5*KaCw!YSZ!h2N~Beva@! zQidmjsPDte2h!~s=4>20q+;E0ecSMhbkac#Uj@Pe-FD6a71~d^`}v~#Nbh4kMS6<$ zB*^Y0_!dJ*0bBr%0z*ca!dB-9@@9)Cqhb@sGuC~~& zjqI+n>j$1&F3NR&u!aMrGF||9CsX&YL^f`~#CLDWd^s|ET-#PJoXwFpTq)&+$J1m} zdJbBvxMjgMOF zhfk60u)%JRdqO_#u)*#`nKCEJ>|~7@!MTxG5mo1ev1R9_)hxh~v-{nWd^BN$-K=Lh z0q#|(>9DHaRlj_`;L-Et?!kJJG9!TI`RBpyJ7z$RvLz z7hQK&6m)SM>&Tb;DqZe{u+#Am&{hYna1@SZYtt3S43~!9ufE-0aq^Z^kXs_;@s27w nab*|Sui1Hg1mD@uieBpUC=vbf_-XSM?gtkZ@u#S~zEuAL^0dYR literal 0 HcmV?d00001 diff --git a/modules/core_lib/const.lua b/modules/core_lib/const.lua index 0d18d8bf..d63a59f4 100644 --- a/modules/core_lib/const.lua +++ b/modules/core_lib/const.lua @@ -14,6 +14,38 @@ LogFatal = 4 ActiveFocusReason = 2 +KeyboardNoModifier = 0 +KeyboardCtrlModifier = 1 +KeyboardAltModifier = 2 +KeyboardCtrlAltModifier = 3 +KeyboardShiftModifier = 4 +KeyboardCtrlShiftModifier = 5 +KeyboardAltShiftModifier = 6 +KeyboardCtrlAltShiftModifier = 7 + +MouseNoButton = 0 +MouseLeftButton = 1 +MouseRightButton = 2 +MouseMidButton = 3 + +AlignNone = 0 +AlignLeft = 1 +AlignRight = 2 +AlignTop = 4 +AlignBottom = 8 +AlignHorizontalCenter = 16 +AlignVerticalCenter = 32 +AlignTopLeft = 5 +AlignTopRight = 6 +AlignBottomLeft = 9 +AlignBottomRight = 10 +AlignLeftCenter = 33 +AlignRightCenter = 34 +AlignTopCenter = 20 +AlignBottomCenter = 24 +AlignCenter = 48 + + KeyUnknown = 0 KeyEscape = 1 KeyTab = 2 @@ -123,29 +155,113 @@ KeyF10 = 138 KeyF11 = 139 KeyF12 = 140 -KeyboardNoModifier = 0 -KeyboardCtrlModifier = 1 -KeyboardAltModifier = 2 -KeyboardShiftModifier = 4 - -MouseNoButton = 0 -MouseLeftButton = 1 -MouseRightButton = 2 -MouseMidButton = 3 - -AlignNone = 0 -AlignLeft = 1 -AlignRight = 2 -AlignTop = 4 -AlignBottom = 8 -AlignHorizontalCenter = 16 -AlignVerticalCenter = 32 -AlignTopLeft = 5 -AlignTopRight = 6 -AlignBottomLeft = 9 -AlignBottomRight = 10 -AlignLeftCenter = 33 -AlignRightCenter = 34 -AlignTopCenter = 20 -AlignBottomCenter = 24 -AlignCenter = 48 +KeyCodeDescs = { + [KeyUnknown] = 'Unknown', + [KeyEscape] = 'Escape', + [KeyTab] = 'Tab', + [KeyBackspace] = 'Backspace', + [KeyReturn] = 'Return', + [KeyEnter] = 'Enter', + [KeyInsert] = 'Insert', + [KeyDelete] = 'Delete', + [KeyPause] = 'Pause', + [KeyPrintScreen] = 'PrintScreen', + [KeyHome] = 'Home', + [KeyEnd] = 'End', + [KeyPageUp] = 'PageUp', + [KeyPageDown] = 'PageDown', + [KeyUp] = 'Up', + [KeyDown] = 'Down', + [KeyLeft] = 'Left', + [KeyRight] = 'Right', + [KeyNumLock] = 'NumLock', + [KeyScrollLock] = 'ScrollLock', + [KeyCapsLock] = 'CapsLock', + [KeyCtrl] = 'Ctrl', + [KeyShift] = 'Shift', + [KeyAlt] = 'Alt', + [KeyAltGr] = 'AltGr', + [KeyMeta] = 'Meta', + [KeyMenu] = 'Menu', + [KeySpace] = 'Space', + [KeyExclamation] = '!', + [KeyQuote] = '\"', + [KeyNumberSign] = '#', + [KeyDollar] = '$', + [KeyPercent] = '%', + [KeyAmpersand] = '&', + [KeyApostrophe] = '\'', + [KeyLeftParen] = '(', + [KeyRightParen] = ')', + [KeyAsterisk] = '*', + [KeyPlus] = '+', + [KeyComma] = ',', + [KeyMinus] = '-', + [KeyPeriod] = '.', + [KeySlash] = '/', + [Key0] = '0', + [Key1] = '1', + [Key2] = '2', + [Key3] = '3', + [Key4] = '4', + [Key5] = '5', + [Key6] = '6', + [Key7] = '7', + [Key8] = '8', + [Key9] = '9', + [KeyColon] = ':', + [KeySemicolon] = ';', + [KeyLess] = '<', + [KeyEqual] = '=', + [KeyGreater] = '>', + [KeyQuestion] = '?', + [KeyAtSign] = '@', + [KeyA] = 'A', + [KeyB] = 'B', + [KeyC] = 'C', + [KeyD] = 'D', + [KeyE] = 'E', + [KeyF] = 'F', + [KeyG] = 'G', + [KeyH] = 'H', + [KeyI] = 'I', + [KeyJ] = 'J', + [KeyK] = 'K', + [KeyL] = 'L', + [KeyM] = 'M', + [KeyN] = 'N', + [KeyO] = 'O', + [KeyP] = 'P', + [KeyQ] = 'Q', + [KeyR] = 'R', + [KeyS] = 'S', + [KeyT] = 'T', + [KeyU] = 'U', + [KeyV] = 'V', + [KeyW] = 'W', + [KeyX] = 'X', + [KeyY] = 'Y', + [KeyZ] = 'Z', + [KeyLeftBracket] = '[', + [KeyBackslash] = '\\', + [KeyRightBracket] = ']', + [KeyCaret] = '^', + [KeyUnderscore] = '_', + [KeyGrave] = '`', + [KeyLeftCurly] = '{', + [KeyBar] = '|', + [KeyRightCurly] = '}', + [KeyTilde] = '~', + [KeyF1] = 'F1', + [KeyF2] = 'F2', + [KeyF3] = 'F3', + [KeyF4] = 'F4', + [KeyF5] = 'F5', + [KeyF6] = 'F6', + [KeyF7] = 'F7', + [KeyF8] = 'F8', + [KeyF9] = 'F9', + [KeyF10] = 'F10', + [KeyF11] = 'F11', + [KeyF12] = 'F12' +} \ No newline at end of file diff --git a/modules/core_lib/core_lib.otmod b/modules/core_lib/core_lib.otmod index 5bd5cd40..e6912f20 100644 --- a/modules/core_lib/core_lib.otmod +++ b/modules/core_lib/core_lib.otmod @@ -17,3 +17,4 @@ Module require 'dispatcher' require 'effects' require 'settings' + require 'hotkeys' diff --git a/modules/core_lib/ext/string.lua b/modules/core_lib/ext/string.lua index 5b20b8f6..39192be7 100644 --- a/modules/core_lib/ext/string.lua +++ b/modules/core_lib/ext/string.lua @@ -1,18 +1,23 @@ -function string:split(sep) - local t = { } - local function helper(word) - table.insert(t, word) - return "" - end - if not self:gsub("%w+", helper):find("%S") then - return t +function string.split(s, delim) + local start = 1 + local results = {} + while true do + local pos = string.find(s, delim, start, true) + if not pos then + break + end + table.insert(results, string.sub(s, start, pos-1)) + start = pos + string.len(delim) end + table.insert(results, string.sub(s, start)) + table.removevalue(results, '') + return results end -function string:starts(start) - return self:sub(1, #start) == start +function string.starts(s, start) + return string.sub(s, 1, #start) == start end -function string:trim() - return self:match('^%s*(.*%S)') or '' +function string.trim(s) + return string.match(s, '^%s*(.*%S)') or '' end diff --git a/modules/core_lib/ext/table.lua b/modules/core_lib/ext/table.lua index c7f3c190..6a8851d5 100644 --- a/modules/core_lib/ext/table.lua +++ b/modules/core_lib/ext/table.lua @@ -40,13 +40,17 @@ function table.find(t, value) end function table.removevalue(t, value) - local queue = {} for k,v in pairs(t) do if v == value then - table.insert(queue, k) + table.remove(t, k) end end - for i,v in pairs(queue) do - table.remove(t, i) +end + +function table.compare(t, other) + if #t ~= #other then return false end + for k,v in pairs(t) do + if v ~= other[k] then return false end end + return true end diff --git a/modules/core_lib/hotkeys.lua b/modules/core_lib/hotkeys.lua index 9c609c4b..0dd285d4 100644 --- a/modules/core_lib/hotkeys.lua +++ b/modules/core_lib/hotkeys.lua @@ -1,6 +1,96 @@ Hotkeys = {} -function Hotkeys.bindKey(keyDesc, func) +-- private functions +local function translateKeyCombo(keyCombo) + if not keyCombo or #keyCombo == 0 then return nil end + table.sort(keyCombo) + local keyComboDesc = '' + for k,v in pairs(keyCombo) do + local keyDesc = KeyCodeDescs[v] + if keyDesc == nil then return nil end + keyComboDesc = keyComboDesc .. '+' .. keyDesc + end + keyComboDesc = keyComboDesc:sub(2) + return keyComboDesc +end + +local function retranslateKeyComboDesc(keyComboDesc) + if keyComboDesc == nil then return nil end + local keyCombo = {} + for i,currentKeyDesc in ipairs(keyComboDesc:split('+')) do + for keyCode, keyDesc in pairs(KeyCodeDescs) do + if keyDesc:lower() == currentKeyDesc:trim():lower() then + table.insert(keyCombo, keyCode) + end + end + end + return translateKeyCombo(keyCombo) +end + +local function determineKeyComboDesc(keyCode, keyboardModifiers) + local keyCombo = {} + if keyCode == KeyShift or keyCode == KeyAlt or keyCode == KeyAltGr then + table.insert(keyCombo, keyCode) + elseif KeyCodeDescs[keyCode] ~= nil then + if keyboardModifiers == KeyboardCtrlModifier then + table.insert(keyCombo, KeyCtrl) + elseif keyboardModifiers == KeyboardAltModifier then + table.insert(keyCombo, KeyAlt) + elseif keyboardModifiers == KeyboardCtrlAltModifier then + table.insert(keyCombo, KeyCtrl) + table.insert(keyCombo, KeyAlt) + elseif keyboardModifiers == KeyboardShiftModifier then + table.insert(keyCombo, KeyShift) + elseif keyboardModifiers == KeyboardCtrlShiftModifier then + table.insert(keyCombo, KeyCtrl) + table.insert(keyCombo, KeyShift) + elseif keyboardModifiers == KeyboardAltShiftModifier then + table.insert(keyCombo, KeyAlt) + table.insert(keyCombo, KeyShift) + elseif keyboardModifiers == KeyboardCtrlAltShiftModifier then + table.insert(keyCombo, KeyCtrl) + table.insert(keyCombo, KeyAlt) + table.insert(keyCombo, KeyShift) + end + table.insert(keyCombo, keyCode) + end + table.sort(keyCombo) + return translateKeyCombo(keyCombo) +end +local function onWidgetKeyPress(widget, keyCode, keyText, keyboardModifiers) + local keyComboDesc = determineKeyComboDesc(keyCode, keyboardModifiers) + local callback = widget.boundKeyCombos[keyComboDesc] + if callback then + callback() + return true + end + return false end +local function connectWidgetHotkeyEvent(widget) + if widget.boundKeyCombos then return end + connect(widget, { onKeyPress = onWidgetKeyPress }) + widget.boundKeyCombos = {} +end + +-- public functions +function Hotkeys.bind(keyComboDesc, callback, widget) + widget = widget or rootWidget + connectWidgetHotkeyEvent(widget) + local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) + if keyComboDesc then + widget.boundKeyCombos[keyComboDesc] = callback + else + error('key combo \'' .. keyComboDesc .. '\' is failed') + end +end + +function Hotkeys.unbind(keyComboDesc, widget) + widget = widget or rootWidget + if widget.boundKeyCombos == nil then return end + local keyComboDesc = retranslateKeyComboDesc(keyComboDesc) + if keyComboDesc then + widget.boundKeyCombos[keyComboDesc] = nil + end +end