Skip to content

Commit 7ce44a5

Browse files
committed
Improve api ergonomics and add missing locks
1 parent 2ee9d7e commit 7ce44a5

File tree

5 files changed

+77
-41
lines changed

5 files changed

+77
-41
lines changed

docs/dev/Lua API.rst

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,11 +1439,11 @@ Hotkey module
14391439
for details on format).
14401440
Returns false on failure to create keybind.
14411441

1442-
* ``dfhack.hotkey.clearKeybind(keyspec, any_focus, command)``
1442+
* ``dfhack.hotkey.removeKeybind(keyspec, [match_focus=true, command])``
14431443

14441444
Removes keybinds matching the provided keyspec.
1445-
If any_focus is true, the focus portion of the keyspec is ignored.
1446-
If command is not an empty string, the command is matched against as well.
1445+
If match_focus is set, the focus portion of the keyspec is matched against.
1446+
If command is provided and not an empty string, the command is matched against.
14471447
Returns false if no keybinds were removed.
14481448

14491449
* ``dfhack.hotkey.listActiveKeybinds()``
@@ -1460,15 +1460,16 @@ Hotkey module
14601460
:spec: The keyspec for the hotkey
14611461
:command: The command the hotkey runs when pressed
14621462

1463-
* ``dfhack.hotkey.requestKeybindInput()``
1463+
* ``dfhack.hotkey.requestKeybindingInput([cancel=false])``
14641464

1465-
Requests that the next hotkey-compatible input is saved and not processed,
1466-
retrievable with ``dfhack.hotkey.readKeybindInput()``.
1465+
Enqueues or cancels a request that the next hotkey-compatible input is saved
1466+
and not processed, retrievable with ``dfhack.hotkey.getKeybindingInput()``.
1467+
If cancel is true, any current request is cancelled.
14671468

1468-
* ``dfhack.hotkey.readKeybindInput()``
1469+
* ``dfhack.hotkey.getKeybindingInput()``
14691470

14701471
Reads the latest saved keybind input that was requested.
1471-
Returns a keyspec string for the input, or nil if no input is saved.
1472+
Returns a keyspec string for the input, or nil if no input has been saved.
14721473

14731474
Units module
14741475
------------

library/LuaApi.cpp

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,20 +1874,19 @@ static bool hotkey_addKeybind(const std::string spec, const std::string cmd) {
18741874
return hotkey_mgr->addKeybind(spec, cmd);
18751875
}
18761876

1877-
static bool hotkey_clearKeybind(const std::string spec, bool any_focus, std::string cmd) {
1877+
static int hotkey_requestKeybindingInput(lua_State *L) {
18781878
auto hotkey_mgr = Core::getInstance().getHotkeyManager();
1879-
if (!hotkey_mgr) return false;
1880-
return hotkey_mgr->clearKeybind(spec, any_focus, cmd);
1881-
}
1882-
1883-
static void hotkey_requestKeybindingInput() {
1884-
auto hotkey_mgr = Core::getInstance().getHotkeyManager();
1885-
if (hotkey_mgr) hotkey_mgr->requestKeybindInput();
1879+
if (!hotkey_mgr) return 0;
1880+
bool cancel = false;
1881+
if (lua_gettop(L) == 1)
1882+
cancel = lua_toboolean(L, -1);
1883+
hotkey_mgr->requestKeybindingInput(cancel);
1884+
return 0;
18861885
}
18871886

1888-
static int hotkey_readKeybindInput(lua_State *L) {
1887+
static int hotkey_getKeybindingInput(lua_State *L) {
18891888
auto hotkey_mgr = Core::getInstance().getHotkeyManager();
1890-
auto input = hotkey_mgr->readKeybindInput();
1889+
auto input = hotkey_mgr->getKeybindingInput();
18911890

18921891
if (input.empty()) {
18931892
lua_pushnil(L);
@@ -1897,6 +1896,38 @@ static int hotkey_readKeybindInput(lua_State *L) {
18971896
return 1;
18981897
}
18991898

1899+
static int hotkey_removeKeybind(lua_State *L) {
1900+
auto hotkey_mgr = Core::getInstance().getHotkeyManager();
1901+
if (!hotkey_mgr) {
1902+
lua_pushboolean(L, false);
1903+
return 1;
1904+
}
1905+
1906+
bool res = false;
1907+
switch (lua_gettop(L)) {
1908+
case 1:
1909+
luaL_checkstring(L, -1);
1910+
res = hotkey_mgr->removeKeybind(lua_tostring(L, -1));
1911+
break;
1912+
case 2:
1913+
luaL_checkstring(L, -2);
1914+
res = hotkey_mgr->removeKeybind(lua_tostring(L, -2), lua_toboolean(L, -1));
1915+
break;
1916+
case 3:
1917+
luaL_checkstring(L, -3);
1918+
luaL_checkstring(L, -1);
1919+
res = hotkey_mgr->removeKeybind(
1920+
lua_tostring(L, -3),
1921+
lua_toboolean(L, -2),
1922+
lua_tostring(L, -1)
1923+
);
1924+
break;
1925+
}
1926+
1927+
lua_pushboolean(L, res);
1928+
return 1;
1929+
}
1930+
19001931
void hotkey_pushBindArray(lua_State *L, const std::vector<Hotkey::KeyBinding>& binds) {
19011932
lua_createtable(L, binds.size(), 0);
19021933
int i = 1;
@@ -1932,16 +1963,16 @@ static int hotkey_listAllKeybinds(lua_State *L) {
19321963
}
19331964

19341965
static const luaL_Reg dfhack_hotkey_funcs[] = {
1966+
{ "removeKeybind", hotkey_removeKeybind },
19351967
{ "listActiveKeybinds", hotkey_listActiveKeybinds },
19361968
{ "listAllKeybinds", hotkey_listAllKeybinds },
1937-
{ "readKeybindInput", hotkey_readKeybindInput },
1969+
{ "requestKeybindingInput", hotkey_requestKeybindingInput },
1970+
{ "getKeybindingInput", hotkey_getKeybindingInput },
19381971
{ NULL, NULL }
19391972
};
19401973

19411974
static const LuaWrapper::FunctionReg dfhack_hotkey_module[] = {
19421975
WRAPN(addKeybind, hotkey_addKeybind),
1943-
WRAPN(clearKeybind, hotkey_clearKeybind),
1944-
WRAPN(requestKeybindInput, hotkey_requestKeybindingInput),
19451976
{ NULL, NULL }
19461977
};
19471978

library/include/modules/Hotkey.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ namespace DFHack {
3737
bool addKeybind(std::string keyspec, std::string cmd);
3838
bool addKeybind(Hotkey::KeySpec spec, std::string cmd);
3939
// Clear a keybind with the given keyspec, optionally for any focus, or with a specific command
40-
bool clearKeybind(std::string keyspec, bool any_focus=false, std::string_view cmdline="");
41-
bool clearKeybind(const Hotkey::KeySpec& spec, bool any_focus=false, std::string_view cmdline="");
40+
bool removeKeybind(std::string keyspec, bool match_focus=true, std::string_view cmdline="");
41+
bool removeKeybind(const Hotkey::KeySpec& spec, bool match_focus=true, std::string_view cmdline="");
4242

4343
std::vector<std::string> listKeybinds(std::string keyspec);
4444
std::vector<std::string> listKeybinds(const Hotkey::KeySpec& spec);
@@ -49,11 +49,11 @@ namespace DFHack {
4949
bool handleKeybind(int sym, int modifiers);
5050
void setHotkeyCommand(std::string cmd);
5151

52-
// Used to request the next keybind input is saved.
52+
// Used to request the next hotkey-compatible input is saved.
5353
// This is to allow for graphical keybinding menus.
54-
void requestKeybindInput();
54+
void requestKeybindingInput(bool cancel=false);
5555
// Returns the latest requested keybind input
56-
std::string readKeybindInput();
56+
std::string getKeybindingInput();
5757

5858
private:
5959
std::thread hotkey_thread;
@@ -64,7 +64,7 @@ namespace DFHack {
6464
std::string requested_keybind;
6565

6666
int hotkey_sig = 0;
67-
std::string queued_command = "";
67+
std::string queued_command;
6868

6969
std::map<int, std::vector<Hotkey::KeyBinding>> bindings;
7070

library/modules/Hotkey.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,17 @@ bool HotkeyManager::addKeybind(std::string keyspec, std::string cmd) {
181181
return this->addKeybind(spec_opt.value(), cmd);
182182
}
183183

184-
bool HotkeyManager::clearKeybind(const KeySpec& spec, bool any_focus, std::string_view cmdline) {
184+
bool HotkeyManager::removeKeybind(const KeySpec& spec, bool match_focus, std::string_view cmdline) {
185185
std::lock_guard<std::mutex> l(lock);
186186
if (!bindings.contains(spec.sym))
187187
return false;
188188
auto& binds = bindings[spec.sym];
189189

190-
auto new_end = std::remove_if(binds.begin(), binds.end(), [any_focus, spec, &cmdline](const auto& v) {
191-
return (any_focus
192-
? v.spec.sym == spec.sym && v.spec.modifiers == spec.modifiers
193-
: v.spec == spec) && (cmdline.empty() || v.cmdline == cmdline);
190+
auto new_end = std::remove_if(binds.begin(), binds.end(), [match_focus, spec, &cmdline](const auto& v) {
191+
return v.spec.sym == spec.sym
192+
&& v.spec.modifiers == spec.modifiers
193+
&& (!match_focus || v.spec.focus == spec.focus)
194+
&& (cmdline.empty() || v.cmdline == cmdline);
194195
});
195196
if (new_end == binds.end())
196197
return false; // No bindings removed
@@ -199,11 +200,11 @@ bool HotkeyManager::clearKeybind(const KeySpec& spec, bool any_focus, std::strin
199200
return true;
200201
}
201202

202-
bool HotkeyManager::clearKeybind(std::string keyspec, bool any_focus, std::string_view cmdline) {
203+
bool HotkeyManager::removeKeybind(std::string keyspec, bool match_focus, std::string_view cmdline) {
203204
std::optional<KeySpec> spec_opt = Hotkey::parseKeySpec(keyspec);
204205
if (!spec_opt.has_value())
205206
return false;
206-
return this->clearKeybind(spec_opt.value(), any_focus, cmdline);
207+
return this->removeKeybind(spec_opt.value(), match_focus, cmdline);
207208
}
208209

209210
std::vector<std::string> HotkeyManager::listKeybinds(const KeySpec& spec) {
@@ -237,13 +238,15 @@ std::vector<std::string> HotkeyManager::listKeybinds(const KeySpec& spec) {
237238
}
238239

239240
std::vector<std::string> HotkeyManager::listKeybinds(std::string keyspec) {
241+
std::lock_guard<std::mutex> l(lock);
240242
std::optional<KeySpec> spec_opt = Hotkey::parseKeySpec(keyspec);
241243
if (!spec_opt.has_value())
242244
return {};
243245
return this->listKeybinds(spec_opt.value());
244246
}
245247

246248
std::vector<KeyBinding> HotkeyManager::listActiveKeybinds() {
249+
std::lock_guard<std::mutex> l(lock);
247250
std::vector<KeyBinding> out;
248251

249252
for(const auto& [_, bind_set] : bindings) {
@@ -267,6 +270,7 @@ std::vector<KeyBinding> HotkeyManager::listActiveKeybinds() {
267270
}
268271

269272
std::vector<KeyBinding> HotkeyManager::listAllKeybinds() {
273+
std::lock_guard<std::mutex> l(lock);
270274
std::vector<KeyBinding> out;
271275

272276
for (const auto& [_, bind_set] : bindings) {
@@ -351,13 +355,13 @@ void HotkeyManager::setHotkeyCommand(std::string cmd) {
351355
cond.notify_all();
352356
}
353357

354-
void HotkeyManager::requestKeybindInput() {
358+
void HotkeyManager::requestKeybindingInput(bool cancel) {
355359
std::lock_guard<std::mutex> l(lock);
356-
keybind_save_requested = true;
357-
requested_keybind = "";
360+
keybind_save_requested = !cancel;
361+
requested_keybind.clear();
358362
}
359363

360-
std::string HotkeyManager::readKeybindInput() {
364+
std::string HotkeyManager::getKeybindingInput() {
361365
std::lock_guard<std::mutex> l(lock);
362366
return requested_keybind;
363367
}
@@ -367,7 +371,7 @@ void HotkeyManager::handleKeybindingCommand(color_ostream &con, const std::vecto
367371
if (parts.size() >= 3 && (parts[0] == "set" || parts[0] == "add")) {
368372
std::string keystr = parts[1];
369373
if (parts[0] == "set")
370-
clearKeybind(keystr);
374+
removeKeybind(keystr);
371375
for (const auto& part : parts | std::views::drop(2) | std::views::reverse) {
372376
auto spec = Hotkey::parseKeySpec(keystr, &parse_error);
373377
if (!spec.has_value()) {
@@ -386,7 +390,7 @@ void HotkeyManager::handleKeybindingCommand(color_ostream &con, const std::vecto
386390
if (!spec.has_value()) {
387391
con.printerr("%s\n", parse_error.c_str());
388392
}
389-
if (!clearKeybind(spec.value())) {
393+
if (!removeKeybind(spec.value())) {
390394
con.printerr("No matching keybinds to remove\n");
391395
break;
392396
}

plugins/hotkeys.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static int cleanupHotkeys(lua_State *) {
4646
std::for_each(sorted_keys.begin(), sorted_keys.end(), [](const string &sym) {
4747
string keyspec = sym + "@" + MENU_SCREEN_FOCUS_STRING;
4848
DEBUG(log).print("clearing keybinding: %s\n", keyspec.c_str());
49-
Core::getInstance().getHotkeyManager()->clearKeybind(keyspec);
49+
Core::getInstance().getHotkeyManager()->removeKeybind(keyspec);
5050
});
5151
valid = false;
5252
sorted_keys.clear();

0 commit comments

Comments
 (0)