overlay: "reset all" buttons for buttons/overlay/analog tabs (#578)

## Link to GitHub Issue or related Pull Request, if one exists
#576 

## Description of change
Add `Reset All` buttons to these tabs which clears out bindings to none
/ default.

For keypads, introduce a special `Use Preset` button which lets users
pick between numpad and top row number keys.

Update UI-visible string used for vKeys, especially the numpad ones
(e.g., `.` is now `Numpad .` to distinguish from the regular `.`
period).

Breaking change: if the user never had `P1 Keypad 00` set, the default
will change from `Enter` to `Numpad -` since both enter keys trigger the
same. This will affect a small number of popn/ddr players. They can just
change it back.

## Testing
*how was the code tested?*
This commit is contained in:
bicarus
2026-03-17 18:47:54 -07:00
committed by GitHub
parent a9f0e86aa3
commit 97d65b137a
6 changed files with 185 additions and 28 deletions
+6 -1
View File
@@ -37,7 +37,11 @@ std::vector<Button> GameAPI::Buttons::sortButtons(
for (auto &bt : buttons) { for (auto &bt : buttons) {
if (name == bt.getName()) { if (name == bt.getName()) {
button_found = true; button_found = true;
sorted.push_back(bt); Button button_new = bt;
if (vkey_defaults) {
button_new.setVKeyDefault(vkey_defaults->at(index));
}
sorted.push_back(button_new);
break; break;
} }
} }
@@ -47,6 +51,7 @@ std::vector<Button> GameAPI::Buttons::sortButtons(
if (vkey_defaults) { if (vkey_defaults) {
button.setVKey(vkey_defaults->at(index)); button.setVKey(vkey_defaults->at(index));
button.setVKeyDefault(vkey_defaults->at(index));
} }
} }
+17 -17
View File
@@ -44,7 +44,7 @@ std::string Button::getVKeyString() {
case 0x0C: case 0x0C:
return "Clear"; return "Clear";
case 0x0D: case 0x0D:
return "Enter"; return "Enter/Return";
case 0x10: case 0x10:
return "Shift"; return "Shift";
case 0x11: case 0x11:
@@ -183,37 +183,37 @@ std::string Button::getVKeyString() {
case 0x5D: case 0x5D:
return "Apps"; return "Apps";
case 0x60: case 0x60:
return "Num 0"; return "Numpad 0";
case 0x61: case 0x61:
return "Num 1"; return "Numpad 1";
case 0x62: case 0x62:
return "Num 2"; return "Numpad 2";
case 0x63: case 0x63:
return "Num 3"; return "Numpad 3";
case 0x64: case 0x64:
return "Num 4"; return "Numpad 4";
case 0x65: case 0x65:
return "Num 5"; return "Numpad 5";
case 0x66: case 0x66:
return "Num 6"; return "Numpad 6";
case 0x67: case 0x67:
return "Num 7"; return "Numpad 7";
case 0x68: case 0x68:
return "Num 8"; return "Numpad 8";
case 0x69: case 0x69:
return "Num 9"; return "Numpad 9";
case 0x6A: case 0x6A:
return "*"; return "Numpad *";
case 0x6B: case 0x6B:
return "+"; return "Numpad +";
case 0x6C: case 0x6C:
return "Seperator"; return "Numpad Seperator";
case 0x6D: case 0x6D:
return "-"; return "Numpad -";
case 0x6E: case 0x6E:
return "."; return "Numpad .";
case 0x6F: case 0x6F:
return "/"; return "Numpad /";
case 0x70: case 0x70:
return "F1"; return "F1";
case 0x71: case 0x71:
+12
View File
@@ -49,6 +49,10 @@ private:
std::string name; std::string name;
std::string device_identifier = ""; std::string device_identifier = "";
unsigned short vKey = INVALID_VKEY; unsigned short vKey = INVALID_VKEY;
// default bindings are always naive
unsigned short vKey_default = INVALID_VKEY;
ButtonAnalogType analog_type = BAT_NONE; ButtonAnalogType analog_type = BAT_NONE;
double debounce_up = 0.0; double debounce_up = 0.0;
double debounce_down = 0.0; double debounce_down = 0.0;
@@ -125,6 +129,14 @@ public:
this->vKey = vKey; this->vKey = vKey;
} }
inline unsigned short getVKeyDefault() const {
return this->vKey_default;
}
inline void setVKeyDefault(unsigned short vKey_default) {
this->vKey_default = vKey_default;
}
inline ButtonAnalogType getAnalogType() const { inline ButtonAnalogType getAnalogType() const {
return this->analog_type; return this->analog_type;
} }
+2 -1
View File
@@ -401,7 +401,8 @@ namespace games {
vkey_defaults.push_back(unit == 0 ? VK_NUMPAD9 : 0xFF); vkey_defaults.push_back(unit == 0 ? VK_NUMPAD9 : 0xFF);
names.emplace_back(prefix + "00"); names.emplace_back(prefix + "00");
vkey_defaults.push_back(unit == 0 ? VK_RETURN : 0xFF); // this used to be VK_RETURN, but that shares a value with normal Enter key
vkey_defaults.push_back(unit == 0 ? VK_SUBTRACT : 0xFF);
names.emplace_back(prefix + "Decimal"); names.emplace_back(prefix + "Decimal");
vkey_defaults.push_back(unit == 0 ? VK_DECIMAL : 0xFF); vkey_defaults.push_back(unit == 0 ? VK_DECIMAL : 0xFF);
+144 -7
View File
@@ -590,14 +590,75 @@ namespace overlay::windows {
} }
void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) { void Config::build_buttons(const std::string &name, std::vector<Button> *buttons, int min, int max) {
ImGui::AlignTextToFramePadding();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "%s Buttons", name.c_str()); ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "%s Buttons", name.c_str());
std::string reset_button_str = "Reset all";
if (name == "Keypad") {
reset_button_str = "Use Preset";
}
const float clear_w = ImGui::CalcTextSize(reset_button_str.c_str()).x
+ ImGui::GetStyle().FramePadding.x * 2;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - clear_w);
std::string reset_str = "Reset all " + name + " button bindings";
// clear all
ImGui::PushID(name.c_str());
if (ImGui::Button(reset_button_str.c_str())) {
ImGui::OpenPopup(reset_str.c_str());
}
if (ImGui::BeginPopupModal(reset_str.c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextUnformatted("Are you sure? This can't be undone.");
ImGui::Spacing();
ImGui::Separator(); ImGui::Separator();
ImGui::Spacing();
if (name == "Keypad") {
if (ImGui::Button("Use Numpad")) {
for (auto &button : *buttons) {
reset_button_to_default(&button, button.getVKeyDefault());
}
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Use Top Row")) {
for (auto &button : *buttons) {
reset_button_to_default(&button, get_keypad_top_row(button));
}
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Remove All")) {
for (auto &button : *buttons) {
reset_button_to_default(&button, 0xFF);
}
ImGui::CloseCurrentPopup();
}
} else {
if (ImGui::Button("Yes")) {
for (auto &button : *buttons) {
reset_button_to_default(&button, button.getVKeyDefault());
}
ImGui::CloseCurrentPopup();
}
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::PopID();
ImGui::Separator();
if (ImGui::BeginTable("ButtonsTable", 3, ImGuiTableFlags_Resizable)) { if (ImGui::BeginTable("ButtonsTable", 3, ImGuiTableFlags_Resizable)) {
// longest column is probably "Toggle Virtual Keypad P1" in Overlay tab // longest column is probably "Toggle Virtual Keypad P1" in Overlay tab
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(220)); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(220));
ImGui::TableSetupColumn("Binding", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("Binding", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(180)); ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(140));
// check if empty // check if empty
if (!buttons || buttons->empty()) { if (!buttons || buttons->empty()) {
@@ -651,7 +712,14 @@ namespace overlay::windows {
// get button info // get button info
ImGui::PushID(button); ImGui::PushID(button);
const auto button_name = button->getName(); auto button_name = button->getName();
if (button_name == "Service") {
button_name = "Insert Service Coin";
} else if (button_name == "Test") {
button_name = "Enter Test Menu";
} else if (button_name == "Coin Mech") {
button_name = "Activate Coin Mech";
}
const auto button_display = button->getDisplayString(RI_MGR.get()); const auto button_display = button->getDisplayString(RI_MGR.get());
const auto button_velocity = GameAPI::Buttons::getVelocity(RI_MGR, *button); const auto button_velocity = GameAPI::Buttons::getVelocity(RI_MGR, *button);
@@ -899,9 +967,13 @@ namespace overlay::windows {
ImGui::PopID(); ImGui::PopID();
} }
void Config::clear_button(Button *button, const int alt_index) { void Config::clear_button(Button *button, const int alt_index, std::optional<unsigned short> vKey_default) {
button->setDeviceIdentifier(""); button->setDeviceIdentifier("");
if (vKey_default.has_value()) {
button->setVKey(vKey_default.value());
} else {
button->setVKey(0xFF); button->setVKey(0xFF);
}
button->setAnalogType(BAT_NONE); button->setAnalogType(BAT_NONE);
button->setDebounceUp(0.0); button->setDebounceUp(0.0);
button->setDebounceDown(0.0); button->setDebounceDown(0.0);
@@ -915,6 +987,41 @@ namespace overlay::windows {
alt_index - 1); alt_index - 1);
} }
void Config::reset_button_to_default(Button *button, unsigned short vKey_default) {
// delete all alternatives
int alt_index = 1; // 0 is primary
for (auto &alt : button->getAlternatives()) {
clear_button(&alt, alt_index);
alt_index++;
}
// reset primary button to default
clear_button(button, 0, vKey_default);
}
unsigned int Config::get_keypad_top_row(const Button &button) {
static const std::unordered_map<std::string, unsigned short> keypad_top_row_defaults = {
{"P1 Keypad 0", 0x30}, // 0 (top row number key)
{"P1 Keypad 1", 0x31},
{"P1 Keypad 2", 0x32},
{"P1 Keypad 3", 0x33},
{"P1 Keypad 4", 0x34},
{"P1 Keypad 5", 0x35},
{"P1 Keypad 6", 0x36},
{"P1 Keypad 7", 0x37},
{"P1 Keypad 8", 0x38},
{"P1 Keypad 9", 0x39},
{"P1 Keypad 00", VK_OEM_MINUS},
{"P1 Keypad Decimal", VK_OEM_PLUS},
{"P1 Keypad Insert Card", VK_BACK}};
for (const auto &[key, value] : keypad_top_row_defaults) {
if (button.getName() == key) {
return value;
}
}
return 0xFF;
}
void Config::bind_button_popup( void Config::bind_button_popup(
const std::string &bind_name, Button *button, const int button_it_max, const int alt_index) { const std::string &bind_name, Button *button, const int button_it_max, const int alt_index) {
@@ -1872,7 +1979,40 @@ namespace overlay::windows {
} }
void Config::build_analogs(const std::string &name, std::vector<Analog> *analogs) { void Config::build_analogs(const std::string &name, std::vector<Analog> *analogs) {
ImGui::AlignTextToFramePadding();
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Analogs"); ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Analogs");
const float clear_w = ImGui::CalcTextSize("Clear All").x
+ ImGui::GetStyle().FramePadding.x * 2;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - clear_w);
// clear all
if (ImGui::Button("Clear All")) {
ImGui::OpenPopup("Clear all analog bindings");
}
if (ImGui::BeginPopupModal("Clear all analog bindings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextUnformatted("Are you sure? This can't be undone.");
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
if (ImGui::Button("Yes")) {
for (auto &analog : *analogs) {
// explicitly not checking for analog.isSet() here
// since it doesn't account for a binding with valid device but invalid index
analog.clearBindings();
analog.setLastState(0.f);
::Config::getInstance().updateBinding(games_list[games_selected], analog);
}
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::Separator(); ImGui::Separator();
if (ImGui::BeginTable("AnalogsTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) { if (ImGui::BeginTable("AnalogsTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
@@ -2419,9 +2559,6 @@ namespace overlay::windows {
ImGui::OpenPopup("Clear all light bindings"); ImGui::OpenPopup("Clear all light bindings");
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGui::TOOLTIP_FLAGS)) {
ImGui::SetTooltip("Unbind all lights.");
}
if (ImGui::BeginPopupModal("Clear all light bindings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { if (ImGui::BeginPopupModal("Clear all light bindings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextUnformatted("Are you sure? This can't be undone."); ImGui::TextUnformatted("Are you sure? This can't be undone.");
ImGui::Spacing(); ImGui::Spacing();
+3 -1
View File
@@ -124,7 +124,9 @@ namespace overlay::windows {
Button *button, Button *button,
const float button_velocity, const float button_velocity,
const int alt_index); const int alt_index);
void clear_button(Button *button, const int alt_index); void clear_button(Button *button, const int alt_index, std::optional<unsigned short> vKey_default = std::nullopt);
void reset_button_to_default(Button *button, unsigned short vKey_default);
unsigned int get_keypad_top_row(const Button &button);
void build_analogs(const std::string &name, std::vector<Analog> *analogs); void build_analogs(const std::string &name, std::vector<Analog> *analogs);
void edit_analog_popup(Analog &analog); void edit_analog_popup(Analog &analog);