mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
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:
@@ -37,7 +37,11 @@ std::vector<Button> GameAPI::Buttons::sortButtons(
|
||||
for (auto &bt : buttons) {
|
||||
if (name == bt.getName()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -47,6 +51,7 @@ std::vector<Button> GameAPI::Buttons::sortButtons(
|
||||
|
||||
if (vkey_defaults) {
|
||||
button.setVKey(vkey_defaults->at(index));
|
||||
button.setVKeyDefault(vkey_defaults->at(index));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-17
@@ -44,7 +44,7 @@ std::string Button::getVKeyString() {
|
||||
case 0x0C:
|
||||
return "Clear";
|
||||
case 0x0D:
|
||||
return "Enter";
|
||||
return "Enter/Return";
|
||||
case 0x10:
|
||||
return "Shift";
|
||||
case 0x11:
|
||||
@@ -183,37 +183,37 @@ std::string Button::getVKeyString() {
|
||||
case 0x5D:
|
||||
return "Apps";
|
||||
case 0x60:
|
||||
return "Num 0";
|
||||
return "Numpad 0";
|
||||
case 0x61:
|
||||
return "Num 1";
|
||||
return "Numpad 1";
|
||||
case 0x62:
|
||||
return "Num 2";
|
||||
return "Numpad 2";
|
||||
case 0x63:
|
||||
return "Num 3";
|
||||
return "Numpad 3";
|
||||
case 0x64:
|
||||
return "Num 4";
|
||||
return "Numpad 4";
|
||||
case 0x65:
|
||||
return "Num 5";
|
||||
return "Numpad 5";
|
||||
case 0x66:
|
||||
return "Num 6";
|
||||
return "Numpad 6";
|
||||
case 0x67:
|
||||
return "Num 7";
|
||||
return "Numpad 7";
|
||||
case 0x68:
|
||||
return "Num 8";
|
||||
return "Numpad 8";
|
||||
case 0x69:
|
||||
return "Num 9";
|
||||
return "Numpad 9";
|
||||
case 0x6A:
|
||||
return "*";
|
||||
return "Numpad *";
|
||||
case 0x6B:
|
||||
return "+";
|
||||
return "Numpad +";
|
||||
case 0x6C:
|
||||
return "Seperator";
|
||||
return "Numpad Seperator";
|
||||
case 0x6D:
|
||||
return "-";
|
||||
return "Numpad -";
|
||||
case 0x6E:
|
||||
return ".";
|
||||
return "Numpad .";
|
||||
case 0x6F:
|
||||
return "/";
|
||||
return "Numpad /";
|
||||
case 0x70:
|
||||
return "F1";
|
||||
case 0x71:
|
||||
|
||||
@@ -49,6 +49,10 @@ private:
|
||||
std::string name;
|
||||
std::string device_identifier = "";
|
||||
unsigned short vKey = INVALID_VKEY;
|
||||
|
||||
// default bindings are always naive
|
||||
unsigned short vKey_default = INVALID_VKEY;
|
||||
|
||||
ButtonAnalogType analog_type = BAT_NONE;
|
||||
double debounce_up = 0.0;
|
||||
double debounce_down = 0.0;
|
||||
@@ -125,6 +129,14 @@ public:
|
||||
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 {
|
||||
return this->analog_type;
|
||||
}
|
||||
|
||||
@@ -401,7 +401,8 @@ namespace games {
|
||||
vkey_defaults.push_back(unit == 0 ? VK_NUMPAD9 : 0xFF);
|
||||
|
||||
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");
|
||||
vkey_defaults.push_back(unit == 0 ? VK_DECIMAL : 0xFF);
|
||||
|
||||
@@ -590,14 +590,75 @@ namespace overlay::windows {
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
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::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)) {
|
||||
// longest column is probably "Toggle Virtual Keypad P1" in Overlay tab
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(220));
|
||||
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
|
||||
if (!buttons || buttons->empty()) {
|
||||
@@ -651,7 +712,14 @@ namespace overlay::windows {
|
||||
|
||||
// get button info
|
||||
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_velocity = GameAPI::Buttons::getVelocity(RI_MGR, *button);
|
||||
|
||||
@@ -899,9 +967,13 @@ namespace overlay::windows {
|
||||
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->setVKey(0xFF);
|
||||
if (vKey_default.has_value()) {
|
||||
button->setVKey(vKey_default.value());
|
||||
} else {
|
||||
button->setVKey(0xFF);
|
||||
}
|
||||
button->setAnalogType(BAT_NONE);
|
||||
button->setDebounceUp(0.0);
|
||||
button->setDebounceDown(0.0);
|
||||
@@ -915,6 +987,41 @@ namespace overlay::windows {
|
||||
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(
|
||||
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) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
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();
|
||||
if (ImGui::BeginTable("AnalogsTable", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
|
||||
|
||||
@@ -2419,9 +2559,6 @@ namespace overlay::windows {
|
||||
ImGui::OpenPopup("Clear all light bindings");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
if (ImGui::IsItemHovered(ImGui::TOOLTIP_FLAGS)) {
|
||||
ImGui::SetTooltip("Unbind all lights.");
|
||||
}
|
||||
if (ImGui::BeginPopupModal("Clear all light bindings", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextUnformatted("Are you sure? This can't be undone.");
|
||||
ImGui::Spacing();
|
||||
|
||||
@@ -124,7 +124,9 @@ namespace overlay::windows {
|
||||
Button *button,
|
||||
const float button_velocity,
|
||||
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 edit_analog_popup(Analog &analog);
|
||||
|
||||
Reference in New Issue
Block a user