From 0589aeddd540459a88e339e041d5bdb49ca4db2e Mon Sep 17 00:00:00 2001 From: Stefano Date: Fri, 5 Apr 2024 19:31:47 +0200 Subject: [PATCH] Allow a button to be mapped to multiple keys --- README.md | 2 +- .../keyboard-joypad/KeyboardJoypad.cpp | 91 +++++++++++++------ 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index e35a381..ea1dbfd 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,4 @@ The device can be configured using the following parameters. They are all option - ``axes``: definition of the list of axes. The allowed values are "ws", "ad", "up_down" and "left_right". It is possible to select the default sign for an axis prepending a "+" or a "-" to the axis name. For example, "+ws" will set the "ws" axis with the default sign, while "-ws" will set the "ws" axis with the inverted sign. It is also possible to repeat some axis, and use "none" or "" to have dummy axes with always zero value. The order matters. (default: ("ad", "ws", "left_right", "up_down")) - ``wasd_label``: label for the "WASD" widget (default: "WASD") - ``arrows_label``: label for the "Arrows" widget (default: "Arrows") -- ``buttons``: definition of the list of buttons. The allowed values are all the letters from A to Z, all the numbers from 0 to 9, "SPACE", "ENTER", "ESCAPE", "BACKSPACE", "DELETE", "LEFT", "RIGHT", "UP", "DOWN". It is possible to repeat some button. It is possible to specify an alias after a ":". For example "A:Some Text" will create a button with the label "Some Text" that can be activated by pressing "A". It is possible to use "none" or "" to indicate a dummy button always zero. It is possible to repeat buttons. The order matters. (default: ()) +- ``buttons``: definition of the list of buttons. The allowed values are all the letters from A to Z, all the numbers from 0 to 9, "SPACE", "ENTER", "ESCAPE", "BACKSPACE", "DELETE", "LEFT", "RIGHT", "UP", "DOWN". It is possible to repeat some button. It is possible to specify an alias after a ":". For example "A:Some Text" will create a button with the label "Some Text" that can be activated by pressing "A". It is possible to use "none" or "" to indicate a dummy button always zero. It is possible to spcify multiple keys using the "-" delimiter. For example, "A-B:Some Text" creates a button named "Some Text" that can be activated pressing either A or B. It is possible to repeat buttons. The order matters. (default: ()) diff --git a/src/devices/keyboard-joypad/KeyboardJoypad.cpp b/src/devices/keyboard-joypad/KeyboardJoypad.cpp index c7c97e0..26d0771 100644 --- a/src/devices/keyboard-joypad/KeyboardJoypad.cpp +++ b/src/devices/keyboard-joypad/KeyboardJoypad.cpp @@ -102,7 +102,7 @@ struct ButtonState { bool buttonReleased = ImGui::Button(alias.c_str(), buttonSize); bool buttonKeptPressed = ImGui::IsItemActive(); - if (buttonReleased && (toggleButton || regularButton && hold_active)) + if (buttonReleased && (toggleButton || (regularButton && hold_active))) { active = !active; //Toggle the button } @@ -426,12 +426,12 @@ class yarp::dev::KeyboardJoypad::Impl int col = 0; for (size_t i = 0; i < buttons_list->size(); i++) { - std::string button_with_alias; + std::string buttons_with_alias; if (!buttons_list->get(i).isString()) { if (buttons_list->get(i).isInt64() || buttons_list->get(i).isInt32()) { - button_with_alias = std::to_string(buttons_list->get(i).asInt64()); + buttons_with_alias = std::to_string(buttons_list->get(i).asInt64()); } else { @@ -441,31 +441,45 @@ class yarp::dev::KeyboardJoypad::Impl } else { - button_with_alias = buttons_list->get(i).asString(); + buttons_with_alias = buttons_list->get(i).asString(); } - if (button_with_alias == "" || button_with_alias == "none") + if (buttons_with_alias == "" || buttons_with_alias == "none") { continue; } - std::string button = button_with_alias; + std::string buttons_keys = buttons_with_alias; std::string alias = ""; - size_t pos = button_with_alias.find(':'); + size_t pos = buttons_with_alias.find(':'); bool have_alias = false; if (pos != std::string::npos) { - button = button_with_alias.substr(0, pos); - alias = button_with_alias.substr(pos + 1); + buttons_keys = buttons_with_alias.substr(0, pos); + alias = buttons_with_alias.substr(pos + 1); have_alias = true; } else { - alias = button; + alias = buttons_keys; } - std::transform(button.begin(), button.end(), button.begin(), ::toupper); + std::transform(buttons_keys.begin(), buttons_keys.end(), buttons_keys.begin(), ::toupper); + + std::vector buttons_key_list; + std::string delimiter = "-"; + pos = buttons_keys.find(delimiter); + while (pos != std::string::npos) + { + buttons_key_list.push_back(buttons_keys.substr(0, pos)); + buttons_keys.erase(0, pos + delimiter.length()); + pos = buttons_keys.find(delimiter); + } + buttons_key_list.push_back(buttons_keys); + + ButtonState newButton; + newButton.values.push_back({ .sign = 1, .index = i }); std::unordered_map supportedButtons = { {"SPACE", ImGuiKey_Space}, @@ -480,27 +494,50 @@ class yarp::dev::KeyboardJoypad::Impl {"TAB", ImGuiKey_Tab} }; - - ButtonState newButton; - newButton.values.push_back({.sign = 1, .index = i}); - - if (button.size() == 1 && button[0] >= 'A' && button[0] <= 'Z') - { - newButton.keys.push_back(static_cast(ImGuiKey_A + button[0] - 'A')); - } - else if (button.size() && button[0] >= '0' && button[0] <= '9') + std::string parsedButtons; + for (auto& button : buttons_key_list) { - newButton.keys.push_back(static_cast(ImGuiKey_0 + button[0] - '0')); - newButton.keys.push_back(static_cast(ImGuiKey_Keypad0 + button[0] - '0')); + yError() << "Button: " << button; + bool parsed = true; + if (button.size() == 1 && button[0] >= 'A' && button[0] <= 'Z') + { + newButton.keys.push_back(static_cast(ImGuiKey_A + button[0] - 'A')); + } + else if (button.size() && button[0] >= '0' && button[0] <= '9') + { + newButton.keys.push_back(static_cast(ImGuiKey_0 + button[0] - '0')); + newButton.keys.push_back(static_cast(ImGuiKey_Keypad0 + button[0] - '0')); + } + else if (supportedButtons.find(button) != supportedButtons.end()) + { + newButton.keys.push_back(supportedButtons[button]); + } + else + { + parsed = false; + } + + if (parsed) + { + if (!parsedButtons.empty()) + { + parsedButtons += ", " + button; + } + else + { + parsedButtons = button; + } + } } - else if (supportedButtons.find(button) != supportedButtons.end()) + yError() << "Parsed buttons: " << parsedButtons; + + if (!parsedButtons.empty() && have_alias) { - newButton.keys.push_back(supportedButtons[button]); + alias += " (" + parsedButtons + ")"; } - - if (!newButton.keys.empty() && have_alias) + else if (!parsedButtons.empty() && !have_alias) { - alias += " (" + button + ")"; + alias = parsedButtons; } if (buttons.rows.empty() || buttons.rows.back().size() == settings.buttons_per_row)