From 06339d8952189f459a3e981539a3440b6c9f1935 Mon Sep 17 00:00:00 2001 From: iota97 Date: Thu, 4 Mar 2021 10:37:35 +0100 Subject: [PATCH] Customizable touch control (rebased with label) --- Common/Data/Format/IniFile.cpp | 25 +++ Common/Data/Format/IniFile.h | 6 + Common/Data/Text/Parsers.cpp | 20 ++ Common/Data/Text/Parsers.h | 1 + Core/Config.cpp | 93 ++++++--- Core/Config.h | 41 ++-- Core/ControlMapper.h | 2 +- UI/ComboKeyMappingScreen.cpp | 281 +++++++++++++++------------ UI/ComboKeyMappingScreen.h | 10 +- UI/EmuScreen.cpp | 2 +- UI/GameSettingsScreen.cpp | 13 +- UI/GameSettingsScreen.h | 1 - UI/GamepadEmu.cpp | 187 ++++++------------ UI/GamepadEmu.h | 151 +++++++++++---- UI/TouchControlLayoutScreen.cpp | 47 +++-- UI/TouchControlVisibilityScreen.cpp | 106 +++++++---- UI/TouchControlVisibilityScreen.h | 1 + atlasscript.txt | 8 +- source_assets/image/a.png | Bin 0 -> 941 bytes source_assets/image/b.png | Bin 0 -> 815 bytes source_assets/image/buttons.svg | 286 +++++++++++++++++++++++++++- source_assets/image/c.png | Bin 0 -> 749 bytes source_assets/image/d.png | Bin 0 -> 809 bytes source_assets/image/e.png | Bin 0 -> 512 bytes source_assets/image/f.png | Bin 0 -> 468 bytes 25 files changed, 864 insertions(+), 417 deletions(-) create mode 100644 source_assets/image/a.png create mode 100644 source_assets/image/b.png create mode 100644 source_assets/image/c.png create mode 100644 source_assets/image/d.png create mode 100644 source_assets/image/e.png create mode 100644 source_assets/image/f.png diff --git a/Common/Data/Format/IniFile.cpp b/Common/Data/Format/IniFile.cpp index 06ee1acd60f9..0900e28499da 100644 --- a/Common/Data/Format/IniFile.cpp +++ b/Common/Data/Format/IniFile.cpp @@ -170,6 +170,10 @@ void Section::Set(const char* key, uint32_t newValue) { Set(key, StringFromFormat("0x%08x", newValue).c_str()); } +void Section::Set(const char* key, uint64_t newValue) { + Set(key, StringFromFormat("0x%016lx", newValue).c_str()); +} + void Section::Set(const char* key, float newValue) { Set(key, StringFromFormat("%f", newValue).c_str()); } @@ -311,6 +315,16 @@ bool Section::Get(const char* key, uint32_t* value, uint32_t defaultValue) return false; } +bool Section::Get(const char* key, uint64_t* value, uint64_t defaultValue) +{ + std::string temp; + bool retval = Get(key, &temp, 0); + if (retval && TryParse(temp, value)) + return true; + *value = defaultValue; + return false; +} + bool Section::Get(const char* key, bool* value, bool defaultValue) { std::string temp; @@ -659,6 +673,17 @@ bool IniFile::Get(const char* sectionName, const char* key, uint32_t* value, uin } } +bool IniFile::Get(const char* sectionName, const char* key, uint64_t* value, uint64_t defaultValue) +{ + Section *section = GetSection(sectionName); + if (!section) { + *value = defaultValue; + return false; + } else { + return section->Get(key, value, defaultValue); + } +} + bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool defaultValue) { Section *section = GetSection(sectionName); diff --git a/Common/Data/Format/IniFile.h b/Common/Data/Format/IniFile.h index 6499562edb4f..87bd1d183062 100644 --- a/Common/Data/Format/IniFile.h +++ b/Common/Data/Format/IniFile.h @@ -35,6 +35,7 @@ class Section { bool Get(const char* key, std::string* value, const char* defaultValue); void Set(const char* key, uint32_t newValue); + void Set(const char* key, uint64_t newValue); void Set(const char* key, float newValue); void Set(const char* key, const float newValue, const float defaultValue); void Set(const char* key, double newValue); @@ -58,6 +59,7 @@ class Section { bool Get(const char* key, int* value, int defaultValue = 0); bool Get(const char* key, uint32_t* value, uint32_t defaultValue = 0); + bool Get(const char* key, uint64_t* value, uint64_t defaultValue = 0); bool Get(const char* key, bool* value, bool defaultValue = false); bool Get(const char* key, float* value, float defaultValue = false); bool Get(const char* key, double* value, double defaultValue = false); @@ -103,6 +105,9 @@ class IniFile { void Set(const char* sectionName, const char* key, uint32_t newValue) { GetOrCreateSection(sectionName)->Set(key, newValue); } + void Set(const char* sectionName, const char* key, uint64_t newValue) { + GetOrCreateSection(sectionName)->Set(key, newValue); + } void Set(const char* sectionName, const char* key, bool newValue) { GetOrCreateSection(sectionName)->Set(key, newValue); } @@ -114,6 +119,7 @@ class IniFile { bool Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue = ""); bool Get(const char* sectionName, const char* key, int* value, int defaultValue = 0); bool Get(const char* sectionName, const char* key, uint32_t* value, uint32_t defaultValue = 0); + bool Get(const char* sectionName, const char* key, uint64_t* value, uint64_t defaultValue = 0); bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false); bool Get(const char* sectionName, const char* key, std::vector& values); diff --git a/Common/Data/Text/Parsers.cpp b/Common/Data/Text/Parsers.cpp index ab7c05733970..5342b6fbcd9a 100644 --- a/Common/Data/Text/Parsers.cpp +++ b/Common/Data/Text/Parsers.cpp @@ -71,6 +71,26 @@ bool TryParse(const std::string &str, uint32_t *const output) { return true; } +bool TryParse(const std::string &str, uint64_t *const output) { + char *endptr = NULL; + + // Holy crap this is ugly. + + // Reset errno to a value other than ERANGE + errno = 0; + + uint64_t value = strtoul(str.c_str(), &endptr, 0); + + if (!endptr || *endptr) + return false; + + if (errno == ERANGE) + return false; + + *output = value; + return true; +} + bool TryParse(const std::string &str, bool *const output) { if ("1" == str || !strcasecmp("true", str.c_str())) *output = true; diff --git a/Common/Data/Text/Parsers.h b/Common/Data/Text/Parsers.h index 909e667178ce..bfa111774c88 100644 --- a/Common/Data/Text/Parsers.h +++ b/Common/Data/Text/Parsers.h @@ -57,6 +57,7 @@ bool ParseMacAddress(std::string str, uint8_t macAddr[6]); bool TryParse(const std::string &str, bool *const output); bool TryParse(const std::string &str, uint32_t *const output); +bool TryParse(const std::string &str, uint64_t *const output); template static bool TryParse(const std::string &str, N *const output) { diff --git a/Core/Config.cpp b/Core/Config.cpp index 7be602f5edc0..c0cd9ba44264 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -68,46 +68,56 @@ struct ConfigSetting { TYPE_BOOL, TYPE_INT, TYPE_UINT32, + TYPE_UINT64, TYPE_FLOAT, TYPE_STRING, TYPE_TOUCH_POS, TYPE_PATH, + TYPE_CUSTOM_BUTTON }; union DefaultValue { bool b; int i; uint32_t u; + uint64_t lu; float f; const char *s; const char *p; // not sure how much point.. ConfigTouchPos touchPos; + ConfigCustomButton customButton; }; union SettingPtr { bool *b; int *i; uint32_t *u; + uint64_t *lu; float *f; std::string *s; Path *p; ConfigTouchPos *touchPos; + ConfigCustomButton *customButton; }; typedef bool (*BoolDefaultCallback)(); typedef int (*IntDefaultCallback)(); typedef uint32_t (*Uint32DefaultCallback)(); + typedef uint64_t (*Uint64DefaultCallback)(); typedef float (*FloatDefaultCallback)(); typedef const char *(*StringDefaultCallback)(); typedef ConfigTouchPos(*TouchPosDefaultCallback)(); typedef const char *(*PathDefaultCallback)(); + typedef ConfigCustomButton (*CustomButtonDefaultCallback)(); union Callback { BoolDefaultCallback b; IntDefaultCallback i; Uint32DefaultCallback u; + Uint64DefaultCallback lu; FloatDefaultCallback f; StringDefaultCallback s; PathDefaultCallback p; TouchPosDefaultCallback touchPos; + CustomButtonDefaultCallback customButton; }; ConfigSetting(bool v) @@ -144,6 +154,13 @@ struct ConfigSetting { default_.u = def; } + ConfigSetting(const char *ini, uint64_t *v, uint64_t def, bool save = true, bool perGame = false) + : iniKey_(ini), type_(TYPE_UINT64), report_(false), save_(save), perGame_(perGame) { + ptr_.lu = v; + cb_.lu = nullptr; + default_.lu = def; + } + ConfigSetting(const char *ini, float *v, float def, bool save = true, bool perGame = false) : iniKey_(ini), type_(TYPE_FLOAT), report_(false), save_(save), perGame_(perGame) { ptr_.f = v; @@ -172,6 +189,13 @@ struct ConfigSetting { default_.touchPos = def; } + ConfigSetting(const char *iniKey, const char *iniImage, const char *iniShape, const char *iniToggle, ConfigCustomButton *v, ConfigCustomButton def, bool save = true, bool perGame = false) + : iniKey_(iniKey), ini2_(iniImage), ini3_(iniShape), ini4_(iniToggle), type_(TYPE_CUSTOM_BUTTON), report_(false), save_(save), perGame_(perGame) { + ptr_.customButton = v; + cb_.customButton = nullptr; + default_.customButton = def; + } + ConfigSetting(const char *ini, bool *v, BoolDefaultCallback def, bool save = true, bool perGame = false) : iniKey_(ini), type_(TYPE_BOOL), report_(false), save_(save), perGame_(perGame) { ptr_.b = v; @@ -242,6 +266,11 @@ struct ConfigSetting { default_.u = cb_.u(); } return section->Get(iniKey_, ptr_.u, default_.u); + case TYPE_UINT64: + if (cb_.lu) { + default_.lu = cb_.lu(); + } + return section->Get(iniKey_, ptr_.lu, default_.lu); case TYPE_FLOAT: if (cb_.f) { default_.f = cb_.f(); @@ -277,6 +306,15 @@ struct ConfigSetting { } return result; } + case TYPE_CUSTOM_BUTTON: + if (cb_.customButton) { + default_.customButton = cb_.customButton(); + } + section->Get(iniKey_, &ptr_.customButton->key, default_.customButton.key); + section->Get(ini2_, &ptr_.customButton->image, default_.customButton.image); + section->Get(ini3_, &ptr_.customButton->shape, default_.customButton.shape); + section->Get(ini4_, &ptr_.customButton->toggle, default_.customButton.toggle); + return true; default: _dbg_assert_msg_(false, "Unexpected ini setting type"); return false; @@ -298,6 +336,8 @@ struct ConfigSetting { return section->Set(iniKey_, *ptr_.i); case TYPE_UINT32: return section->Set(iniKey_, *ptr_.u); + case TYPE_UINT64: + return section->Set(iniKey_, *ptr_.lu); case TYPE_FLOAT: return section->Set(iniKey_, *ptr_.f); case TYPE_STRING: @@ -312,6 +352,12 @@ struct ConfigSetting { section->Set(ini4_, ptr_.touchPos->show); } return; + case TYPE_CUSTOM_BUTTON: + section->Set(iniKey_, ptr_.customButton->key); + section->Set(ini2_, ptr_.customButton->image); + section->Set(ini3_, ptr_.customButton->shape); + section->Set(ini4_, ptr_.customButton->toggle); + return; default: _dbg_assert_msg_(false, "Unexpected ini setting type"); return; @@ -329,6 +375,8 @@ struct ConfigSetting { return data.Add(prefix + iniKey_, *ptr_.i); case TYPE_UINT32: return data.Add(prefix + iniKey_, *ptr_.u); + case TYPE_UINT64: + return data.Add(prefix + iniKey_, *ptr_.lu); case TYPE_FLOAT: return data.Add(prefix + iniKey_, *ptr_.f); case TYPE_STRING: @@ -338,6 +386,9 @@ struct ConfigSetting { case TYPE_TOUCH_POS: // Doesn't report. return; + case TYPE_CUSTOM_BUTTON: + // Doesn't report. + return; default: _dbg_assert_msg_(false, "Unexpected ini setting type"); return; @@ -490,7 +541,6 @@ static ConfigSetting generalSettings[] = { ConfigSetting("GridView1", &g_Config.bGridView1, true), ConfigSetting("GridView2", &g_Config.bGridView2, true), ConfigSetting("GridView3", &g_Config.bGridView3, false), - ConfigSetting("ComboMode", &g_Config.iComboMode, 0), ConfigSetting("RightAnalogUp", &g_Config.iRightAnalogUp, 0, true, true), ConfigSetting("RightAnalogDown", &g_Config.iRightAnalogDown, 0, true, true), ConfigSetting("RightAnalogLeft", &g_Config.iRightAnalogLeft, 0, true, true), @@ -887,17 +937,16 @@ static ConfigSetting controlSettings[] = { ConfigSetting("ShowTouchSquare", &g_Config.bShowTouchSquare, true, true, true), ConfigSetting("ShowTouchTriangle", &g_Config.bShowTouchTriangle, true, true, true), - ConfigSetting("ComboKey0Mapping", &g_Config.iCombokey0, 0, true, true), - ConfigSetting("ComboKey1Mapping", &g_Config.iCombokey1, 0, true, true), - ConfigSetting("ComboKey2Mapping", &g_Config.iCombokey2, 0, true, true), - ConfigSetting("ComboKey3Mapping", &g_Config.iCombokey3, 0, true, true), - ConfigSetting("ComboKey4Mapping", &g_Config.iCombokey4, 0, true, true), - - ConfigSetting("ComboKey0Toggle", &g_Config.bComboToggle0, false, true, true), - ConfigSetting("ComboKey1Toggle", &g_Config.bComboToggle1, false, true, true), - ConfigSetting("ComboKey2Toggle", &g_Config.bComboToggle2, false, true, true), - ConfigSetting("ComboKey3Toggle", &g_Config.bComboToggle3, false, true, true), - ConfigSetting("ComboKey4Toggle", &g_Config.bComboToggle4, false, true, true), + ConfigSetting("Custom0Mapping", "Custom0Image", "Custom0Shape", "Custom0Toggle", &g_Config.CustomKey0, {0, 0, 0, false}, true, true), + ConfigSetting("Custom1Mapping", "Custom1Image", "Custom1Shape", "Custom1Toggle", &g_Config.CustomKey1, {0, 1, 0, false}, true, true), + ConfigSetting("Custom2Mapping", "Custom2Image", "Custom2Shape", "Custom2Toggle", &g_Config.CustomKey2, {0, 2, 0, false}, true, true), + ConfigSetting("Custom3Mapping", "Custom3Image", "Custom3Shape", "Custom3Toggle", &g_Config.CustomKey3, {0, 3, 0, false}, true, true), + ConfigSetting("Custom4Mapping", "Custom4Image", "Custom4Shape", "Custom4Toggle", &g_Config.CustomKey4, {0, 4, 0, false}, true, true), + ConfigSetting("Custom5Mapping", "Custom5Image", "Custom5Shape", "Custom5Toggle", &g_Config.CustomKey5, {0, 0, 1, false}, true, true), + ConfigSetting("Custom6Mapping", "Custom6Image", "Custom6Shape", "Custom6Toggle", &g_Config.CustomKey6, {0, 1, 1, false}, true, true), + ConfigSetting("Custom7Mapping", "Custom7Image", "Custom7Shape", "Custom7Toggle", &g_Config.CustomKey7, {0, 2, 1, false}, true, true), + ConfigSetting("Custom8Mapping", "Custom8Image", "Custom8Shape", "Custom8Toggle", &g_Config.CustomKey8, {0, 3, 1, false}, true, true), + ConfigSetting("Custom9Mapping", "Custom9Image", "Custom9Shape", "Custom9Toggle", &g_Config.CustomKey9, {0, 4, 1, false}, true, true), #if defined(_WIN32) // A win32 user seeing touch controls is likely using PPSSPP on a tablet. There it makes @@ -956,11 +1005,11 @@ static ConfigSetting controlSettings[] = { ConfigSetting("fcombo2X", "fcombo2Y", "comboKeyScale2", "ShowComboKey2", &g_Config.touchCombo2, defaultTouchPosHide, true, true), ConfigSetting("fcombo3X", "fcombo3Y", "comboKeyScale3", "ShowComboKey3", &g_Config.touchCombo3, defaultTouchPosHide, true, true), ConfigSetting("fcombo4X", "fcombo4Y", "comboKeyScale4", "ShowComboKey4", &g_Config.touchCombo4, defaultTouchPosHide, true, true), - ConfigSetting("Speed1KeyX", "Speed1KeyY", "Speed1KeyScale", "ShowSpeed1Key", &g_Config.touchSpeed1Key, defaultTouchPosHide, true, true), - ConfigSetting("Speed2KeyX", "Speed2KeyY", "Speed2KeyScale", "ShowSpeed2Key", &g_Config.touchSpeed2Key, defaultTouchPosHide, true, true), - ConfigSetting("RapidFireKeyX", "RapidFireKeyY", "RapidFireKeyScale", "ShowRapidFireKey", &g_Config.touchRapidFireKey, defaultTouchPosHide, true, true), - ConfigSetting("AnalogRotationCWKeyX", "AnalogRotationKeyCWY", "AnalogRotationKeyCWScale", "ShowAnalogRotationCWKey", &g_Config.touchAnalogRotationCWKey, defaultTouchPosHide, true, true), - ConfigSetting("AnalogRotationCCWKeyX", "AnalogRotationKeyCCWY", "AnalogRotationKeyCCWScale", "ShowAnalogRotationCCWKey", &g_Config.touchAnalogRotationCCWKey, defaultTouchPosHide, true, true), + ConfigSetting("fcombo5X", "fcombo5Y", "comboKeyScale5", "ShowComboKey5", &g_Config.touchCombo5, defaultTouchPosHide, true, true), + ConfigSetting("fcombo6X", "fcombo6Y", "comboKeyScale6", "ShowComboKey6", &g_Config.touchCombo6, defaultTouchPosHide, true, true), + ConfigSetting("fcombo7X", "fcombo7Y", "comboKeyScale7", "ShowComboKey7", &g_Config.touchCombo7, defaultTouchPosHide, true, true), + ConfigSetting("fcombo8X", "fcombo8Y", "comboKeyScale8", "ShowComboKey8", &g_Config.touchCombo8, defaultTouchPosHide, true, true), + ConfigSetting("fcombo9X", "fcombo9Y", "comboKeyScale9", "ShowComboKey9", &g_Config.touchCombo9, defaultTouchPosHide, true, true), ConfigSetting("AnalogDeadzone", &g_Config.fAnalogDeadzone, 0.15f, true, true), ConfigSetting("AnalogInverseDeadzone", &g_Config.fAnalogInverseDeadzone, 0.0f, true, true), @@ -1788,11 +1837,11 @@ void Config::ResetControlLayout() { reset(g_Config.touchCombo2); reset(g_Config.touchCombo3); reset(g_Config.touchCombo4); - reset(g_Config.touchSpeed1Key); - reset(g_Config.touchSpeed2Key); - reset(g_Config.touchRapidFireKey); - reset(g_Config.touchAnalogRotationCWKey); - reset(g_Config.touchAnalogRotationCCWKey); + reset(g_Config.touchCombo5); + reset(g_Config.touchCombo6); + reset(g_Config.touchCombo7); + reset(g_Config.touchCombo8); + reset(g_Config.touchCombo9); } void Config::GetReportingInfo(UrlEncoder &data) { diff --git a/Core/Config.h b/Core/Config.h index ba6dfb2db4c8..a07a6182d8e6 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -55,6 +55,13 @@ struct ConfigTouchPos { bool show; }; +struct ConfigCustomButton { + uint64_t key; + int image; + int shape; + bool toggle; +}; + struct Config { public: Config(); @@ -299,8 +306,6 @@ struct Config { bool bGridView1; bool bGridView2; bool bGridView3; - //Combo key screen flag - int iComboMode; // Right analog binding int iRightAnalogUp; @@ -349,11 +354,11 @@ struct Config { ConfigTouchPos touchCombo2; ConfigTouchPos touchCombo3; ConfigTouchPos touchCombo4; - ConfigTouchPos touchSpeed1Key; - ConfigTouchPos touchSpeed2Key; - ConfigTouchPos touchRapidFireKey; - ConfigTouchPos touchAnalogRotationCWKey; - ConfigTouchPos touchAnalogRotationCCWKey; + ConfigTouchPos touchCombo5; + ConfigTouchPos touchCombo6; + ConfigTouchPos touchCombo7; + ConfigTouchPos touchCombo8; + ConfigTouchPos touchCombo9; // Controls Visibility bool bShowTouchControls; @@ -363,18 +368,16 @@ struct Config { bool bShowTouchTriangle; bool bShowTouchSquare; - // Combo_key mapping. These are bitfields. - int iCombokey0; - int iCombokey1; - int iCombokey2; - int iCombokey3; - int iCombokey4; - - bool bComboToggle0; - bool bComboToggle1; - bool bComboToggle2; - bool bComboToggle3; - bool bComboToggle4; + ConfigCustomButton CustomKey0; + ConfigCustomButton CustomKey1; + ConfigCustomButton CustomKey2; + ConfigCustomButton CustomKey3; + ConfigCustomButton CustomKey4; + ConfigCustomButton CustomKey5; + ConfigCustomButton CustomKey6; + ConfigCustomButton CustomKey7; + ConfigCustomButton CustomKey8; + ConfigCustomButton CustomKey9; // Ignored on iOS and other platforms that lack pause. bool bShowTouchPause; diff --git a/Core/ControlMapper.h b/Core/ControlMapper.h index 9676be212b89..cb363c7ebcc5 100644 --- a/Core/ControlMapper.h +++ b/Core/ControlMapper.h @@ -16,6 +16,7 @@ class ControlMapper { void Update(); bool Key(const KeyInput &key, bool *pauseTrigger); + void pspKey(int pspKeyCode, int flags); bool Axis(const AxisInput &axis); // Required callbacks @@ -29,7 +30,6 @@ class ControlMapper { private: void processAxis(const AxisInput &axis, int direction); - void pspKey(int pspKeyCode, int flags); void setVKeyAnalog(char axis, int stick, int virtualKeyMin, int virtualKeyMax, bool setZero = true); void SetPSPAxis(char axis, float value, int stick); diff --git a/UI/ComboKeyMappingScreen.cpp b/UI/ComboKeyMappingScreen.cpp index f1582ef9aa1d..3fd324e8459f 100644 --- a/UI/ComboKeyMappingScreen.cpp +++ b/UI/ComboKeyMappingScreen.cpp @@ -30,117 +30,167 @@ #include "Common/StringUtils.h" #include "Core/Config.h" -#include "TouchControlVisibilityScreen.h" #include "UI/ComboKeyMappingScreen.h" +class ButtonPreview : public UI::View { +public: + ButtonPreview(ImageID bgImg, ImageID img, float rotationIcon, bool flipShape, float rotationShape, int x, int y) + : View(new UI::AnchorLayoutParams(x, y, UI::NONE, UI::NONE, true)), bgImg_(bgImg), img_(img), rotI_(rotationIcon), + flipS_(flipShape), rotS_(rotationShape), x_(x), y_(y) {} + + void Draw(UIContext &dc) override { + float opacity = g_Config.iTouchButtonOpacity / 100.0f; + + uint32_t colorBg = colorAlpha(g_Config.iTouchButtonStyle != 0 ? 0xFFFFFF : 0xc0b080, opacity); + uint32_t color = colorAlpha(0xFFFFFF, opacity); + + dc.Draw()->DrawImageRotated(bgImg_, x_, y_, 1.0f, rotS_*PI/180, colorBg, flipS_); + dc.Draw()->DrawImageRotated(img_, x_, y_, 1.0f, rotI_*PI/180, color, false); + } +private: + int x_; + int y_; + float rotI_; + float rotS_; + bool flipS_; + ImageID bgImg_; + ImageID img_; +}; + void ComboKeyScreen::CreateViews() { using namespace UI; + using namespace CustomKey; auto co = GetI18NCategory("Controls"); + auto mc = GetI18NCategory("MappableControls"); root_ = new LinearLayout(ORIENT_VERTICAL); - root_->Add(new ItemHeader(co->T("Combo Key Setting"))); + root_->Add(new ItemHeader(co->T("Custom Key Setting"))); LinearLayout *root__ = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0)); root_->Add(root__); LinearLayout *leftColumn = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(120, FILL_PARENT)); auto di = GetI18NCategory("Dialog"); - static const ImageID comboKeyImages[5] = { - ImageID("I_1"), ImageID("I_2"), ImageID("I_3"), ImageID("I_4"), ImageID("I_5"), - }; - - comboselect = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(10, 10, NONE, NONE)); - comboselect->SetSpacing(10); - for (int i = 0; i < 5; i++) { - comboselect->AddChoice(comboKeyImages[i]); - } - comboselect->SetSelection(*mode, false); - comboselect->OnChoice.Handle(this, &ComboKeyScreen::onCombo); - leftColumn->Add(comboselect); - root__->Add(leftColumn); - rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, FILL_PARENT, 1.0f)); - leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f))); - leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); - root__->Add(rightScroll_); - - const int cellSize = 400; - - UI::GridLayoutSettings gridsettings(cellSize, 64, 5); - gridsettings.fillCells = true; - GridLayout *grid = rightScroll_->Add(new GridLayout(gridsettings, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); - - bool *toggle = nullptr; + ConfigCustomButton* cfg = nullptr; + bool* show = nullptr; memset(array, 0, sizeof(array)); - switch (*mode) { + switch (id_) { case 0: - toggle = &g_Config.bComboToggle0; - for (int i = 0; i < 16; i++) - array[i] = (0x01 == ((g_Config.iCombokey0 >> i) & 0x01)); + cfg = &g_Config.CustomKey0; + show = &g_Config.touchCombo0.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey0.key >> i) & 0x01)); break; case 1: - toggle = &g_Config.bComboToggle1; - for (int i = 0; i < 16; i++) - array[i] = (0x01 == ((g_Config.iCombokey1 >> i) & 0x01)); + cfg = &g_Config.CustomKey1; + show = &g_Config.touchCombo1.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey1.key >> i) & 0x01)); break; case 2: - toggle = &g_Config.bComboToggle2; - for (int i = 0; i < 16; i++) - array[i] = (0x01 == ((g_Config.iCombokey2 >> i) & 0x01)); + cfg = &g_Config.CustomKey2; + show = &g_Config.touchCombo2.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey2.key >> i) & 0x01)); break; case 3: - toggle = &g_Config.bComboToggle3; - for (int i = 0; i < 16; i++) - array[i] = (0x01 == ((g_Config.iCombokey3 >> i) & 0x01)); + cfg = &g_Config.CustomKey3; + show = &g_Config.touchCombo3.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey3.key >> i) & 0x01)); break; case 4: - toggle = &g_Config.bComboToggle4; - for (int i = 0; i < 16; i++) - array[i] = (0x01 == ((g_Config.iCombokey4 >> i) & 0x01)); + cfg = &g_Config.CustomKey4; + show = &g_Config.touchCombo4.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey4.key >> i) & 0x01)); + break; + case 5: + cfg = &g_Config.CustomKey5; + show = &g_Config.touchCombo5.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey5.key >> i) & 0x01)); + break; + case 6: + cfg = &g_Config.CustomKey6; + show = &g_Config.touchCombo6.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey6.key >> i) & 0x01)); + break; + case 7: + cfg = &g_Config.CustomKey7; + show = &g_Config.touchCombo7.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey7.key >> i) & 0x01)); + break; + case 8: + cfg = &g_Config.CustomKey8; + show = &g_Config.touchCombo8.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey8.key >> i) & 0x01)); + break; + case 9: + cfg = &g_Config.CustomKey9; + show = &g_Config.touchCombo9.show; + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) + array[i] = (0x01 == ((g_Config.CustomKey9.key >> i) & 0x01)); break; default: // This shouldn't happen, let's just not crash. - toggle = &g_Config.bComboToggle0; + cfg = &g_Config.CustomKey0; + show = &g_Config.touchCombo0.show; break; } - std::map keyImages; - keyImages["Circle"] = ImageID("I_CIRCLE"); - keyImages["Cross"] = ImageID("I_CROSS"); - keyImages["Square"] = ImageID("I_SQUARE"); - keyImages["Triangle"] = ImageID("I_TRIANGLE"); - keyImages["L"] = ImageID("I_L"); - keyImages["R"] = ImageID("I_R"); - keyImages["Start"] = ImageID("I_START"); - keyImages["Select"] = ImageID("I_SELECT"); - keyToggles["Circle"] = &array[13]; - keyToggles["Cross"] = &array[14]; - keyToggles["Square"] = &array[15]; - keyToggles["Triangle"] = &array[12]; - keyToggles["L"] = &array[8]; - keyToggles["R"] = &array[9]; - keyToggles["Left"] = &array[7]; - keyToggles["Up"] = &array[4]; - keyToggles["Right"] = &array[5]; - keyToggles["Down"] = &array[6]; - keyToggles["Start"] = &array[3]; - keyToggles["Select"] = &array[0]; - - std::map::iterator imageFinder; + leftColumn->Add(new ButtonPreview(g_Config.iTouchButtonStyle == 0 ? comboKeyShapes[cfg->shape].i : comboKeyShapes[cfg->shape].l, + comboKeyImages[cfg->image].i, comboKeyImages[cfg->image].r, comboKeyShapes[cfg->shape].f, comboKeyShapes[cfg->shape].r, 62, 82)); - auto mc = GetI18NCategory("MappableControls"); + root__->Add(leftColumn); + rightScroll_ = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT, 1.0f)); + leftColumn->Add(new Spacer(new LinearLayoutParams(1.0f))); + leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack); + root__->Add(rightScroll_); - for (auto i = keyToggles.begin(); i != keyToggles.end(); ++i) { + LinearLayout *vertLayout = new LinearLayout(ORIENT_VERTICAL); + rightScroll_->Add(vertLayout); + + vertLayout->Add(new ItemHeader(co->T("Button Style"))); + vertLayout->Add(new CheckBox(show, co->T("Visible"))); + + // All icon and name are defined in GamepadEmu.h + static const char *imageNames[ARRAY_SIZE(comboKeyImages)]; + for (int i = 0; i < ARRAY_SIZE(imageNames); ++i) { + imageNames[i] = comboKeyImages[i].n; + } + PopupMultiChoice *icon = vertLayout->Add(new PopupMultiChoice(&(cfg->image), co->T("Icon"), imageNames, 0, ARRAY_SIZE(imageNames), mc->GetName(), screenManager())); + icon->OnChoice.Handle(this, &ComboKeyScreen::onCombo); + + // All shape and name are defined in GamepadEmu.h + static const char *shapeNames[ARRAY_SIZE(comboKeyShapes)]; + for (int i = 0; i < ARRAY_SIZE(shapeNames); ++i) { + shapeNames[i] = comboKeyShapes[i].n; + } + vertLayout->Add(new PopupMultiChoice(&(cfg->shape), co->T("Shape"), shapeNames, 0, ARRAY_SIZE(shapeNames), mc->GetName(), screenManager()))->OnChoice.Handle(this, &ComboKeyScreen::onCombo); + + vertLayout->Add(new ItemHeader(co->T("Button Binding"))); + vertLayout->Add(new CheckBox(&(cfg->toggle), co->T("Toggle mode"))); + + const int cellSize = 400; + UI::GridLayoutSettings gridsettings(cellSize, 64, 5); + gridsettings.fillCells = true; + GridLayout *grid = vertLayout->Add(new GridLayout(gridsettings, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); + + // Button name, image and action are defined in GamepadEmu.h + for (int i = 0; i < ARRAY_SIZE(comboKeyList); ++i) { LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); row->SetSpacing(0); - CheckBox *checkbox = new CheckBox(i->second, "", "", new LinearLayoutParams(50, WRAP_CONTENT)); + CheckBox *checkbox = new CheckBox(&array[i], "", "", new LinearLayoutParams(50, WRAP_CONTENT)); row->Add(checkbox); - imageFinder = keyImages.find(i->first); Choice *choice; - if (imageFinder != keyImages.end()) { - choice = new Choice(keyImages[imageFinder->first], new LinearLayoutParams(1.0f)); - } - else { - choice = new Choice(mc->T(i->first.c_str()), new LinearLayoutParams(1.0f)); + if (comboKeyList[i].i.isValid()) { + choice = new Choice(comboKeyList[i].i, new LinearLayoutParams(1.0f)); + } else { + choice = new Choice(mc->T(comboKeyList[i].n), new LinearLayoutParams(1.0f)); } ChoiceEventHandler *choiceEventHandler = new ChoiceEventHandler(checkbox); @@ -150,76 +200,67 @@ void ComboKeyScreen::CreateViews() { row->Add(choice); grid->Add(row); - } - - LinearLayout *row = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)); - row->SetSpacing(0); - - CheckBox *checkbox = new CheckBox(toggle, "", "", new LinearLayoutParams(50, WRAP_CONTENT)); - row->Add(checkbox); - - Choice *choice = new Choice(mc->T("Toggle mode"), new LinearLayoutParams(1.0f)); - ChoiceEventHandler *choiceEventHandler = new ChoiceEventHandler(checkbox); - choice->OnClick.Handle(choiceEventHandler, &ChoiceEventHandler::onChoiceClick); - choice->SetCentered(true); - - row->Add(choice); - grid->Add(row); } -static int arrayToInt(bool ary[16]) { - int value = 0; - for (int i = 15; i >= 0; i--) { +static uint64_t arrayToInt(bool ary[ARRAY_SIZE(CustomKey::comboKeyList)]) { + uint64_t value = 0; + for (int i = ARRAY_SIZE(CustomKey::comboKeyList)-1; i >= 0; i--) { value |= ary[i] ? 1 : 0; - value = value << 1; + if (i > 0) { + value = value << 1; + } } - return value >> 1; + return value; } -void ComboKeyScreen::onFinish(DialogResult result) { - switch (*mode) { +void ComboKeyScreen::saveArray() { + switch (id_) { case 0: - g_Config.iCombokey0 = arrayToInt(array); + g_Config.CustomKey0.key = arrayToInt(array); break; case 1: - g_Config.iCombokey1 = arrayToInt(array); + g_Config.CustomKey1.key = arrayToInt(array); break; case 2: - g_Config.iCombokey2 = arrayToInt(array); + g_Config.CustomKey2.key = arrayToInt(array); break; case 3: - g_Config.iCombokey3 = arrayToInt(array); + g_Config.CustomKey3.key = arrayToInt(array); break; case 4: - g_Config.iCombokey4 = arrayToInt(array); + g_Config.CustomKey4.key = arrayToInt(array); + break; + case 5: + g_Config.CustomKey5.key = arrayToInt(array); + break; + case 6: + g_Config.CustomKey6.key = arrayToInt(array); + break; + case 7: + g_Config.CustomKey7.key = arrayToInt(array); + break; + case 8: + g_Config.CustomKey8.key = arrayToInt(array); + break; + case 9: + g_Config.CustomKey9.key = arrayToInt(array); break; } - g_Config.Save("ComboKeyScreen::onFInish"); +} + +void ComboKeyScreen::onFinish(DialogResult result) { + saveArray(); + g_Config.Save("ComboKeyScreen::onFinish"); } UI::EventReturn ComboKeyScreen::ChoiceEventHandler::onChoiceClick(UI::EventParams &e){ checkbox_->Toggle(); - - return UI::EVENT_DONE; }; UI::EventReturn ComboKeyScreen::onCombo(UI::EventParams &e) { - switch (*mode){ - case 0:g_Config.iCombokey0 = arrayToInt(array); - break; - case 1:g_Config.iCombokey1 = arrayToInt(array); - break; - case 2:g_Config.iCombokey2 = arrayToInt(array); - break; - case 3:g_Config.iCombokey3 = arrayToInt(array); - break; - case 4:g_Config.iCombokey4 = arrayToInt(array); - } - *mode = comboselect->GetSelection(); + saveArray(); CreateViews(); return UI::EVENT_DONE; } - - diff --git a/UI/ComboKeyMappingScreen.h b/UI/ComboKeyMappingScreen.h index bafc3a974b1d..aa4fd71a0644 100644 --- a/UI/ComboKeyMappingScreen.h +++ b/UI/ComboKeyMappingScreen.h @@ -18,6 +18,7 @@ #pragma once #include "MiscScreens.h" +#include "UI/GamepadEmu.h" #include @@ -27,15 +28,16 @@ namespace UI { class ComboKeyScreen : public UIDialogScreenWithBackground { public: - ComboKeyScreen(int *key): mode(key) {} + ComboKeyScreen(int id): id_(id) {} void CreateViews() override; void onFinish(DialogResult result) override; UI::EventReturn onCombo(UI::EventParams &e); private: - std::map keyToggles; - bool array[16]; - int *mode; + void saveArray(); + + bool array[ARRAY_SIZE(CustomKey::comboKeyList)]; + int id_; UI::ChoiceStrip *comboselect; UI::ScrollView *rightScroll_; class ChoiceEventHandler{ diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index d323aadb71a8..13ed2e5d1882 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -775,7 +775,7 @@ void EmuScreen::CreateViews() { const Bounds &bounds = screenManager()->getUIContext()->GetLayoutBounds(); InitPadLayout(bounds.w, bounds.h); - root_ = CreatePadLayout(bounds.w, bounds.h, &pauseTrigger_); + root_ = CreatePadLayout(bounds.w, bounds.h, &pauseTrigger_, &controlMapper_); if (g_Config.bShowDeveloperMenu) { root_->Add(new Button(dev->T("DevMenu")))->OnClick.Handle(this, &EmuScreen::OnDevTools); } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index d14cb76be9b9..40a215f4bc5f 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -49,7 +49,6 @@ #include "UI/TouchControlVisibilityScreen.h" #include "UI/TiltAnalogSettingsScreen.h" #include "UI/TiltEventProcessor.h" -#include "UI/ComboKeyMappingScreen.h" #include "UI/GPUDriverTestScreen.h" #include "UI/MemStickScreen.h" @@ -688,7 +687,7 @@ void GameSettingsScreen::CreateViews() { if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_TV) { controlsSettings->Add(new ItemHeader(co->T("OnScreen", "On-Screen Touch Controls"))); controlsSettings->Add(new CheckBox(&g_Config.bShowTouchControls, co->T("OnScreen", "On-Screen Touch Controls"))); - layoutEditorChoice_ = controlsSettings->Add(new Choice(co->T("Custom layout..."))); + layoutEditorChoice_ = controlsSettings->Add(new Choice(co->T("Customize Touch Controls"))); layoutEditorChoice_->OnClick.Handle(this, &GameSettingsScreen::OnTouchControlLayout); layoutEditorChoice_->SetEnabledPtr(&g_Config.bShowTouchControls); @@ -696,11 +695,6 @@ void GameSettingsScreen::CreateViews() { CheckBox *floatingAnalog = controlsSettings->Add(new CheckBox(&g_Config.bAutoCenterTouchAnalog, co->T("Auto-centering analog stick"))); floatingAnalog->SetEnabledPtr(&g_Config.bShowTouchControls); - // Combo key setup - Choice *comboKey = controlsSettings->Add(new Choice(co->T("Combo Key Setup"))); - comboKey->OnClick.Handle(this, &GameSettingsScreen::OnComboKey); - comboKey->SetEnabledPtr(&g_Config.bShowTouchControls); - // On non iOS systems, offer to let the user see this button. // Some Windows touch devices don't have a back button or other button to call up the menu. if (System_GetPropertyBool(SYSPROP_HAS_BACK_BUTTON)) { @@ -1472,11 +1466,6 @@ UI::EventReturn GameSettingsScreen::OnChangeMacAddress(UI::EventParams &e) { return UI::EVENT_DONE; } -UI::EventReturn GameSettingsScreen::OnComboKey(UI::EventParams &e) { - screenManager()->push(new ComboKeyScreen(&g_Config.iComboMode)); - return UI::EVENT_DONE; -} - UI::EventReturn GameSettingsScreen::OnLanguage(UI::EventParams &e) { auto dev = GetI18NCategory("Developer"); auto langScreen = new NewLanguageScreen(dev->T("Language")); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index b5d3c9e3e939..ebc5d59f8844 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -74,7 +74,6 @@ class GameSettingsScreen : public UIDialogScreenWithGameBackground { UI::EventReturn OnDumpNextFrameToLog(UI::EventParams &e); UI::EventReturn OnTiltTypeChange(UI::EventParams &e); UI::EventReturn OnTiltCustomize(UI::EventParams &e); - UI::EventReturn OnComboKey(UI::EventParams &e); // Global settings handlers UI::EventReturn OnLanguage(UI::EventParams &e); diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index 69359e14320d..8394a3faa249 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -31,6 +31,7 @@ #include "Core/Core.h" #include "Core/System.h" #include "Core/HLE/sceCtrl.h" +#include "Core/ControlMapper.h" #include "UI/GamepadEmu.h" static u32 GetButtonColor() { @@ -158,68 +159,6 @@ void BoolButton::Touch(const TouchInput &input) { } } -void FPSLimitButton::Touch(const TouchInput &input) { - bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); - bool down = pointerDownMask_ != 0; - - if (!down && lastDown && IsDown()) { - PSP_CoreParameter().fpsLimit = FPSLimit::NORMAL; - } else if (down && !lastDown && PSP_CoreParameter().fpsLimit == FPSLimit::NORMAL) { - int limit = limit_ == FPSLimit::CUSTOM1 ? g_Config.iFpsLimit1 : g_Config.iFpsLimit2; - // Validate it actually has a setting (may this should override visible?) - if (limit >= 0) { - PSP_CoreParameter().fpsLimit = limit_; - } - } -} - -bool FPSLimitButton::IsDown() { - return PSP_CoreParameter().fpsLimit == limit_; -} - -void RapidFireButton::Touch(const TouchInput &input) { - bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); - bool down = pointerDownMask_ != 0; - if (down && !lastDown) { - __CtrlSetRapidFire(!__CtrlGetRapidFire()); - } -} - -bool RapidFireButton::IsDown() { - return __CtrlGetRapidFire(); -} - -void AnalogRotationButton::Touch(const TouchInput &input) { - bool lastDown = pointerDownMask_ != 0; - MultiTouchButton::Touch(input); - bool down = pointerDownMask_ != 0; - if (down && !lastDown) { - autoRotating_ = true; - } else if (lastDown && !down) { - autoRotating_ = false; - __CtrlSetAnalogXY(0, 0.0f, 0.0f); - } -} - -void AnalogRotationButton::Update() { - const float now = time_now_d(); - float delta = now - lastFrameTime_; - if (delta > 0) { - secondsWithoutTouch_ += delta; - } - lastFrameTime_ = now; - - if (autoRotating_) { - float speed = clockWise_ ? -g_Config.fAnalogAutoRotSpeed : g_Config.fAnalogAutoRotSpeed; - // Clamp to a square - __CtrlSetAnalogXY(0, - std::min(1.0f, std::max(-1.0f, 1.42f*cosf(now*speed))), - std::min(1.0f, std::max(-1.0f, 1.42f*sinf(now*speed)))); - } -} - void PSPButton::Touch(const TouchInput &input) { bool lastDown = pointerDownMask_ != 0; MultiTouchButton::Touch(input); @@ -234,31 +173,30 @@ void PSPButton::Touch(const TouchInput &input) { } } +bool ComboKey::IsDown() { + return (toggle_ && on_) || (!toggle_ && pointerDownMask_ != 0); +} + void ComboKey::Touch(const TouchInput &input) { + using namespace CustomKey; bool lastDown = pointerDownMask_ != 0; MultiTouchButton::Touch(input); bool down = pointerDownMask_ != 0; - static const int combo[16] = {CTRL_SQUARE ,CTRL_TRIANGLE ,CTRL_CIRCLE ,CTRL_CROSS ,CTRL_UP ,CTRL_DOWN ,CTRL_LEFT ,CTRL_RIGHT ,CTRL_START ,CTRL_SELECT ,CTRL_LTRIGGER ,CTRL_RTRIGGER }; - if (down || lastDown) { - for (int i = 0; i < 16; i++) { - if (pspButtonBit_ & combo[i]) - { - if (down && !lastDown) { - if (g_Config.bHapticFeedback) { - Vibrate(HAPTIC_VIRTUAL_KEY); - } - if (!toggle_) { - __CtrlButtonDown(combo[i]); - } else { - if (__CtrlPeekButtons() & combo[i]) - __CtrlButtonUp(combo[i]); - else - __CtrlButtonDown(combo[i]); - } - } - else if (lastDown && !down && !toggle_) { - __CtrlButtonUp(combo[i]); - } + + if (down && !lastDown) { + if (g_Config.bHapticFeedback) + Vibrate(HAPTIC_VIRTUAL_KEY); + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { + if (pspButtonBit_ & (1UL << i)) { + controllMapper_->pspKey(comboKeyList[i].c, (on_ && toggle_) ? KEY_UP : KEY_DOWN); + } + } + if (toggle_) + on_ = !on_; + } else if (!toggle_ && lastDown && !down) { + for (int i = 0; i < ARRAY_SIZE(comboKeyList); i++) { + if (pspButtonBit_ & (1UL << i)) { + controllMapper_->pspKey(comboKeyList[i].c, KEY_UP); } } } @@ -697,12 +635,6 @@ void InitPadLayout(float xres, float yres, float globalScale) { int unthrottle_key_Y = yres - 60 * scale; initTouchPos(g_Config.touchUnthrottleKey, unthrottle_key_X, unthrottle_key_Y); - initTouchPos(g_Config.touchSpeed1Key, unthrottle_key_X, unthrottle_key_Y - 60 * scale); - initTouchPos(g_Config.touchSpeed2Key, unthrottle_key_X + bottom_key_spacing * scale, unthrottle_key_Y - 60 * scale); - initTouchPos(g_Config.touchRapidFireKey, unthrottle_key_X + 2*bottom_key_spacing * scale, unthrottle_key_Y - 60 * scale); - initTouchPos(g_Config.touchAnalogRotationCCWKey, unthrottle_key_X, unthrottle_key_Y - 120 * scale); - initTouchPos(g_Config.touchAnalogRotationCWKey, unthrottle_key_X + bottom_key_spacing * scale, unthrottle_key_Y - 120 * scale); - // L and R------------------------------------------------------------ // Put them above the analog stick / above the buttons to the right. // The corners were very hard to reach.. @@ -735,9 +667,29 @@ void InitPadLayout(float xres, float yres, float globalScale) { int combo4_key_X = halfW + bottom_key_spacing * scale * 2.2f; int combo4_key_Y = yres / 3; initTouchPos(g_Config.touchCombo4, combo4_key_X, combo4_key_Y); + + int combo5_key_X = halfW - bottom_key_spacing * scale * 1.2f; + int combo5_key_Y = yres / 2; + initTouchPos(g_Config.touchCombo5, combo5_key_X, combo5_key_Y); + + int combo6_key_X = halfW - bottom_key_spacing * scale * 2.2f; + int combo6_key_Y = yres / 2; + initTouchPos(g_Config.touchCombo6, combo6_key_X, combo6_key_Y); + + int combo7_key_X = halfW - bottom_key_spacing * scale * 3.2f; + int combo7_key_Y = yres / 2; + initTouchPos(g_Config.touchCombo7, combo7_key_X, combo7_key_Y); + + int combo8_key_X = halfW - bottom_key_spacing * scale * 1.2f; + int combo8_key_Y = yres / 3; + initTouchPos(g_Config.touchCombo8, combo8_key_X, combo8_key_Y); + + int combo9_key_X = halfW - bottom_key_spacing * scale * 2.2f; + int combo9_key_Y = yres / 3; + initTouchPos(g_Config.touchCombo9, combo9_key_X, combo9_key_Y); } -UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { +UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, ControlMapper* controllMapper) { using namespace UI; AnchorLayout *root = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT)); @@ -764,13 +716,11 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { const int halfW = xres / 2; const ImageID roundImage = g_Config.iTouchButtonStyle ? ImageID("I_ROUND_LINE") : ImageID("I_ROUND"); - const ImageID rectImage = g_Config.iTouchButtonStyle ? ImageID("I_RECT_LINE") : ImageID("I_RECT"); const ImageID shoulderImage = g_Config.iTouchButtonStyle ? ImageID("I_SHOULDER_LINE") : ImageID("I_SHOULDER"); const ImageID dirImage = g_Config.iTouchButtonStyle ? ImageID("I_DIR_LINE") : ImageID("I_DIR"); const ImageID stickImage = g_Config.iTouchButtonStyle ? ImageID("I_STICK_LINE") : ImageID("I_STICK"); const ImageID stickBg = g_Config.iTouchButtonStyle ? ImageID("I_STICK_BG_LINE") : ImageID("I_STICK_BG"); - static const ImageID comboKeyImages[5] = { ImageID("I_1"), ImageID("I_2"), ImageID("I_3"), ImageID("I_4"), ImageID("I_5") }; auto addPSPButton = [=](int buttonBit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch, ButtonOffset off = { 0, 0 }) -> PSPButton * { if (touch.show) { @@ -778,21 +728,21 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { } return nullptr; }; - auto addComboKey = [=](int buttonBit, const char *key, bool toggle, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch) -> ComboKey * { - if (touch.show) { - return root->Add(new ComboKey(buttonBit, key, toggle, bgImg, bgDownImg, img, touch.scale, buttonLayoutParams(touch))); - } - return nullptr; - }; auto addBoolButton = [=](bool *value, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch) -> BoolButton * { if (touch.show) { return root->Add(new BoolButton(value, key, bgImg, bgDownImg, img, touch.scale, buttonLayoutParams(touch))); } return nullptr; }; - auto addFPSLimitButton = [=](FPSLimit value, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, const ConfigTouchPos &touch) -> FPSLimitButton * { + auto addComboKey = [=](const ConfigCustomButton& cfg, const char *key, const ConfigTouchPos &touch) -> ComboKey * { + using namespace CustomKey; if (touch.show) { - return root->Add(new FPSLimitButton(value, key, bgImg, bgDownImg, img, touch.scale, buttonLayoutParams(touch))); + auto aux = root->Add(new ComboKey(cfg.key, key, cfg.toggle, controllMapper, + g_Config.iTouchButtonStyle == 0 ? comboKeyShapes[cfg.shape].i : comboKeyShapes[cfg.shape].l, comboKeyShapes[cfg.shape].i, + comboKeyImages[cfg.image].i, touch.scale, buttonLayoutParams(touch))); + aux->SetAngle(comboKeyImages[cfg.image].r, comboKeyShapes[cfg.shape].r); + aux->FlipImageH(comboKeyShapes[cfg.shape].f); + return aux; } return nullptr; }; @@ -825,28 +775,6 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { }); } - if (g_Config.touchRapidFireKey.show) { - auto rapidFire = root->Add(new RapidFireButton("Rapid fire button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchRapidFireKey.scale, buttonLayoutParams(g_Config.touchRapidFireKey))); - rapidFire->SetAngle(90.0f, 180.0f); - } - - if (g_Config.touchAnalogRotationCWKey.show) { - auto analogRotationCC = root->Add(new AnalogRotationButton(true, "Analog clockwise rotation button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchAnalogRotationCWKey.scale, buttonLayoutParams(g_Config.touchAnalogRotationCWKey))); - analogRotationCC->SetAngle(190.0f, 180.0f); - } - - if (g_Config.touchAnalogRotationCCWKey.show) { - auto analogRotationCCW = root->Add(new AnalogRotationButton(false, "Analog counter clockwise rotation button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchAnalogRotationCCWKey.scale, buttonLayoutParams(g_Config.touchAnalogRotationCCWKey))); - analogRotationCCW->SetAngle(350.0f, 180.0f); - } - - FPSLimitButton *speed1 = addFPSLimitButton(FPSLimit::CUSTOM1, "Alternate speed 1 button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchSpeed1Key); - if (speed1) - speed1->SetAngle(170.0f, 180.0f); - FPSLimitButton *speed2 = addFPSLimitButton(FPSLimit::CUSTOM2, "Alternate speed 2 button", rectImage, ImageID("I_RECT"), ImageID("I_ARROW"), g_Config.touchSpeed2Key); - if (speed2) - speed2->SetAngle(190.0f, 180.0f); - addPSPButton(CTRL_LTRIGGER, "Left shoulder button", shoulderImage, ImageID("I_SHOULDER"), ImageID("I_L"), g_Config.touchLKey); PSPButton *rTrigger = addPSPButton(CTRL_RTRIGGER, "Right shoulder button", shoulderImage, ImageID("I_SHOULDER"), ImageID("I_R"), g_Config.touchRKey); if (rTrigger) @@ -865,11 +793,16 @@ UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause) { root->Add(new PSPStick(stickBg, "Right analog stick", stickImage, ImageID("I_STICK"), 1, g_Config.touchRightAnalogStick.scale, buttonLayoutParams(g_Config.touchRightAnalogStick))); } - addComboKey(g_Config.iCombokey0, "Combo 1 button", g_Config.bComboToggle0, roundImage, ImageID("I_ROUND"), comboKeyImages[0], g_Config.touchCombo0); - addComboKey(g_Config.iCombokey1, "Combo 2 button", g_Config.bComboToggle1, roundImage, ImageID("I_ROUND"), comboKeyImages[1], g_Config.touchCombo1); - addComboKey(g_Config.iCombokey2, "Combo 3 button", g_Config.bComboToggle2, roundImage, ImageID("I_ROUND"), comboKeyImages[2], g_Config.touchCombo2); - addComboKey(g_Config.iCombokey3, "Combo 4 button", g_Config.bComboToggle3, roundImage, ImageID("I_ROUND"), comboKeyImages[3], g_Config.touchCombo3); - addComboKey(g_Config.iCombokey4, "Combo 5 button", g_Config.bComboToggle4, roundImage, ImageID("I_ROUND"), comboKeyImages[4], g_Config.touchCombo4); + addComboKey(g_Config.CustomKey0, "Custom 1 button", g_Config.touchCombo0); + addComboKey(g_Config.CustomKey1, "Custom 2 button", g_Config.touchCombo1); + addComboKey(g_Config.CustomKey2, "Custom 3 button", g_Config.touchCombo2); + addComboKey(g_Config.CustomKey3, "Custom 4 button", g_Config.touchCombo3); + addComboKey(g_Config.CustomKey4, "Custom 5 button", g_Config.touchCombo4); + addComboKey(g_Config.CustomKey5, "Custom 6 button", g_Config.touchCombo5); + addComboKey(g_Config.CustomKey6, "Custom 7 button", g_Config.touchCombo6); + addComboKey(g_Config.CustomKey7, "Custom 8 button", g_Config.touchCombo7); + addComboKey(g_Config.CustomKey8, "Custom 9 button", g_Config.touchCombo8); + addComboKey(g_Config.CustomKey9, "Custom 10 button", g_Config.touchCombo9); return root; } diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index d6fc612a8e41..20c1a72a2da6 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -23,6 +23,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Core/CoreParameter.h" +#include "UI/EmuScreen.h" class GamepadView : public UI::View { public: @@ -86,41 +87,6 @@ class BoolButton : public MultiTouchButton { bool *value_; }; -class FPSLimitButton : public MultiTouchButton { -public: - FPSLimitButton(FPSLimit limit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), limit_(limit) { - - } - void Touch(const TouchInput &input) override; - bool IsDown() override; - -private: - FPSLimit limit_; -}; - -class RapidFireButton : public MultiTouchButton { -public: - RapidFireButton(const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams) { - } - void Touch(const TouchInput &input) override; - bool IsDown() override; -}; - -class AnalogRotationButton : public MultiTouchButton { -public: - AnalogRotationButton(bool clockWise, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), clockWise_(clockWise) { - } - void Touch(const TouchInput &input) override; - void Update() override; - -private: - bool autoRotating_ = false; - bool clockWise_; -}; - class PSPButton : public MultiTouchButton { public: PSPButton(int pspButtonBit, const char *key, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) @@ -196,18 +162,125 @@ class PSPCustomStick : public PSPStick { //initializes the layout from Config. if a default layout does not exist, //it sets up default values void InitPadLayout(float xres, float yres, float globalScale = 1.15f); -UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause); +UI::ViewGroup *CreatePadLayout(float xres, float yres, bool *pause, ControlMapper* controllMapper); const int D_pad_Radius = 50; const int baseActionButtonSpacing = 60; class ComboKey : public MultiTouchButton { public: - ComboKey(int pspButtonBit, const char *key, bool toggle, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) - : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle) { + ComboKey(uint64_t pspButtonBit, const char *key, bool toggle, ControlMapper* controllMapper, ImageID bgImg, ImageID bgDownImg, ImageID img, float scale, UI::LayoutParams *layoutParams) + : MultiTouchButton(key, bgImg, bgDownImg, img, scale, layoutParams), pspButtonBit_(pspButtonBit), toggle_(toggle), controllMapper_(controllMapper), on_(false) { } void Touch(const TouchInput &input) override; + bool IsDown() override; private: - int pspButtonBit_; + uint64_t pspButtonBit_; bool toggle_; + ControlMapper* controllMapper_; + bool on_; +}; + +// Just edit this to add new image, shape or button function +namespace CustomKey { + // Image list + struct keyImage { + const char* n; // UI name + ImageID i; // ImageID + float r; // Rotation angle in degree + }; + static const keyImage comboKeyImages[] = { + { "1", ImageID("I_1"), 0.0f }, + { "2", ImageID("I_2"), 0.0f }, + { "3", ImageID("I_3"), 0.0f }, + { "4", ImageID("I_4"), 0.0f }, + { "5", ImageID("I_5"), 0.0f }, + { "6", ImageID("I_6"), 0.0f }, + { "A", ImageID("I_A"), 0.0f }, + { "B", ImageID("I_B"), 0.0f }, + { "C", ImageID("I_C"), 0.0f }, + { "D", ImageID("I_D"), 0.0f }, + { "E", ImageID("I_E"), 0.0f }, + { "F", ImageID("I_F"), 0.0f }, + { "Circle", ImageID("I_CIRCLE"), 0.0f }, + { "Cross", ImageID("I_CROSS"), 0.0f }, + { "Square", ImageID("I_SQUARE"), 0.0f }, + { "Triangle", ImageID("I_TRIANGLE"), 0.0f }, + { "L", ImageID("I_L"), 0.0f }, + { "R", ImageID("I_R"), 0.0f }, + { "Start", ImageID("I_START"), 0.0f }, + { "Select", ImageID("I_SELECT"), 0.0f }, + { "Plus", ImageID("I_CROSS"), 45.0f }, + { "Rhombus", ImageID("I_SQUARE"), 45.0f }, + { "Down Triangle", ImageID("I_TRIANGLE"), 180.0f }, + { "Arrow up", ImageID("I_ARROW"), 90.0f}, + { "Arrow down", ImageID("I_ARROW"), 270.0f}, + { "Arrow left", ImageID("I_ARROW"), 0.0f}, + { "Arrow right", ImageID("I_ARROW"), 180.0f}, + { "Gear", ImageID("I_GEAR"), 0.0f}, + }; + + // Shape list + struct keyShape { + const char* n; // UI name + ImageID i; // ImageID + ImageID l; // ImageID line version + float r; // Rotation angle in dregree + bool f; // Flip Horizontally + }; + static const keyShape comboKeyShapes[] = { + { "Circle", ImageID("I_ROUND"), ImageID("I_ROUND_LINE"), 0.0f, false }, + { "Rectangle", ImageID("I_RECT"), ImageID("I_RECT_LINE"), 0.0f, false }, + { "Vertical Rectangle", ImageID("I_RECT"), ImageID("I_RECT_LINE"), 90.0f, false }, + { "L button", ImageID("I_SHOULDER"), ImageID("I_SHOULDER_LINE"), 0.0f, false }, + { "R button", ImageID("I_SHOULDER"), ImageID("I_SHOULDER_LINE"), 0.0f, true }, + { "Arrow up", ImageID("I_DIR"), ImageID("I_DIR_LINE"), 270.0f, false }, + { "Arrow down", ImageID("I_DIR"), ImageID("I_DIR_LINE"), 90.0f, false }, + { "Arrow left", ImageID("I_DIR"), ImageID("I_DIR_LINE"), 180.0f, false }, + { "Arrow right", ImageID("I_DIR"), ImageID("I_DIR_LINE"), 0.0f, false }, + }; + + // Button list + struct keyList { + const char* n; // UI name + ImageID i; // UI ImageID + uint32_t c; // Key code + }; + static const keyList comboKeyList[] = { + { "Square", ImageID("I_SQUARE"), CTRL_SQUARE }, + { "Triangle", ImageID("I_TRIANGLE"), CTRL_TRIANGLE }, + { "Circle", ImageID("I_CIRCLE"), CTRL_CIRCLE }, + { "Cross", ImageID("I_CROSS"), CTRL_CROSS }, + { "Up", ImageID::invalid(), CTRL_UP }, + { "Down", ImageID::invalid(), CTRL_DOWN }, + { "Left", ImageID::invalid(), CTRL_LEFT }, + { "Right", ImageID::invalid(), CTRL_RIGHT }, + { "Start", ImageID("I_START"), CTRL_START }, + { "Select", ImageID("I_SELECT"), CTRL_SELECT }, + { "L", ImageID("I_L"), CTRL_LTRIGGER }, + { "R", ImageID("I_R"), CTRL_RTRIGGER }, + { "RapidFire", ImageID::invalid(), VIRTKEY_RAPID_FIRE }, + { "Unthrottle", ImageID::invalid(), VIRTKEY_UNTHROTTLE }, + { "SpeedToggle", ImageID::invalid(), VIRTKEY_SPEED_TOGGLE }, + { "Rewind", ImageID::invalid(), VIRTKEY_REWIND }, + { "Save State", ImageID::invalid(), VIRTKEY_SAVE_STATE }, + { "Load State", ImageID::invalid(), VIRTKEY_LOAD_STATE }, + { "Next Slot", ImageID::invalid(), VIRTKEY_NEXT_SLOT }, + { "Toggle Fullscreen", ImageID::invalid(), VIRTKEY_TOGGLE_FULLSCREEN }, + { "Alt speed 1", ImageID::invalid(), VIRTKEY_SPEED_CUSTOM1 }, + { "Alt speed 2", ImageID::invalid(), VIRTKEY_SPEED_CUSTOM2 }, + { "Texture Dumping", ImageID::invalid(), VIRTKEY_TEXTURE_DUMP }, + { "Texture Replacement", ImageID::invalid(), VIRTKEY_TEXTURE_REPLACE }, + { "Screenshot", ImageID::invalid(), VIRTKEY_SCREENSHOT }, + { "Mute toggle", ImageID::invalid(), VIRTKEY_MUTE_TOGGLE }, + { "OpenChat", ImageID::invalid(), VIRTKEY_OPENCHAT }, + { "Auto Analog Rotation (CW)", ImageID::invalid(), VIRTKEY_ANALOG_ROTATE_CW }, + { "Auto Analog Rotation (CCW)", ImageID::invalid(), VIRTKEY_ANALOG_ROTATE_CCW }, + { "Pause", ImageID::invalid(), VIRTKEY_PAUSE }, + { "DevMenu", ImageID::invalid(), VIRTKEY_DEVMENU }, +#ifndef MOBILE_DEVICE + { "Record", ImageID::invalid(), VIRTKEY_RECORD }, +#endif + }; + static_assert(ARRAY_SIZE(comboKeyList) <= 64, "Too many key for a uint64_t bit mask"); }; diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 25a5a07df020..3f040f5ae33f 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -333,6 +333,7 @@ void ControlLayoutView::Touch(const TouchInput &touch) { } void ControlLayoutView::CreateViews() { + using namespace CustomKey; const Bounds &bounds = GetBounds(); if (bounds.w == 0.0f || bounds.h == 0.0f) { // Layout hasn't happened yet, return. @@ -356,8 +357,6 @@ void ControlLayoutView::CreateViews() { ImageID stickBg = g_Config.iTouchButtonStyle ? ImageID("I_STICK_BG_LINE") : ImageID("I_STICK_BG"); ImageID roundImage = g_Config.iTouchButtonStyle ? ImageID("I_ROUND_LINE") : ImageID("I_ROUND"); - const ImageID comboKeyImages[5] = { ImageID("I_1"), ImageID("I_2"), ImageID("I_3"), ImageID("I_4"), ImageID("I_5") }; - auto addDragDropButton = [&](ConfigTouchPos &pos, const char *key, ImageID bgImg, ImageID img) { DragDropButton *b = nullptr; if (pos.show) { @@ -377,22 +376,6 @@ void ControlLayoutView::CreateViews() { if (auto *unthrottle = addDragDropButton(g_Config.touchUnthrottleKey, "Unthrottle button", rectImage, ImageID("I_ARROW"))) { unthrottle->SetAngle(180.0f); } - if (auto *speed1 = addDragDropButton(g_Config.touchSpeed1Key, "Alternate speed 1 button", rectImage, ImageID("I_ARROW"))) { - speed1->SetAngle(170.0f, 180.0f); - } - if (auto *speed2 = addDragDropButton(g_Config.touchSpeed2Key, "Alternate speed 2 button", rectImage, ImageID("I_ARROW"))) { - speed2->SetAngle(190.0f, 180.0f); - } - if (auto *rapidFire = addDragDropButton(g_Config.touchRapidFireKey, "Rapid fire button", rectImage, ImageID("I_ARROW"))) { - rapidFire->SetAngle(90.0f, 180.0f); - } - if (auto *analogRotationCW = addDragDropButton(g_Config.touchAnalogRotationCWKey, "Analog clockwise rotation button", rectImage, ImageID("I_ARROW"))) { - analogRotationCW->SetAngle(190.0f, 180.0f); - } - if (auto *analogRotationCCW = addDragDropButton(g_Config.touchAnalogRotationCCWKey, "Analog counter clockwise rotation button", rectImage, ImageID("I_ARROW"))) { - analogRotationCCW->SetAngle(350.0f, 180.0f); - } - addDragDropButton(g_Config.touchLKey, "Left shoulder button", shoulderImage, ImageID("I_L")); if (auto *rbutton = addDragDropButton(g_Config.touchRKey, "Right shoulder button", shoulderImage, ImageID("I_R"))) { rbutton->FlipImageH(true); @@ -400,11 +383,27 @@ void ControlLayoutView::CreateViews() { addDragDropButton(g_Config.touchAnalogStick, "Left analog stick", stickBg, stickImage); addDragDropButton(g_Config.touchRightAnalogStick, "Right analog stick", stickBg, stickImage); - addDragDropButton(g_Config.touchCombo0, "Combo 1 button", roundImage, comboKeyImages[0]); - addDragDropButton(g_Config.touchCombo1, "Combo 2 button", roundImage, comboKeyImages[1]); - addDragDropButton(g_Config.touchCombo2, "Combo 3 button", roundImage, comboKeyImages[2]); - addDragDropButton(g_Config.touchCombo3, "Combo 4 button", roundImage, comboKeyImages[3]); - addDragDropButton(g_Config.touchCombo4, "Combo 5 button", roundImage, comboKeyImages[4]); + + auto addDragComboKey = [&](ConfigTouchPos &pos, const char *key, const ConfigCustomButton& cfg) { + DragDropButton *b = nullptr; + if (pos.show) { + b = new DragDropButton(pos, key, g_Config.iTouchButtonStyle == 0 ? comboKeyShapes[cfg.shape].i : comboKeyShapes[cfg.shape].l, comboKeyImages[cfg.image].i, bounds); + b->FlipImageH(comboKeyShapes[cfg.shape].f); + b->SetAngle(comboKeyImages[cfg.image].r, comboKeyShapes[cfg.shape].r); + controls_.push_back(b); + } + return b; + }; + addDragComboKey(g_Config.touchCombo0, "Custom 1 button", g_Config.CustomKey0); + addDragComboKey(g_Config.touchCombo1, "Custom 2 button", g_Config.CustomKey1); + addDragComboKey(g_Config.touchCombo2, "Custom 3 button", g_Config.CustomKey2); + addDragComboKey(g_Config.touchCombo3, "Custom 4 button", g_Config.CustomKey3); + addDragComboKey(g_Config.touchCombo4, "Custom 5 button", g_Config.CustomKey4); + addDragComboKey(g_Config.touchCombo5, "Custom 6 button", g_Config.CustomKey5); + addDragComboKey(g_Config.touchCombo6, "Custom 7 button", g_Config.CustomKey6); + addDragComboKey(g_Config.touchCombo7, "Custom 8 button", g_Config.CustomKey7); + addDragComboKey(g_Config.touchCombo8, "Custom 9 button", g_Config.CustomKey8); + addDragComboKey(g_Config.touchCombo9, "Custom 10 button", g_Config.CustomKey9); for (size_t i = 0; i < controls_.size(); i++) { Add(controls_[i]); @@ -500,7 +499,7 @@ void TouchControlLayoutScreen::CreateViews() { Choice *reset = new Choice(di->T("Reset"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 84)); Choice *back = new Choice(di->T("Back"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 10)); - Choice *visibility = new Choice(co->T("Visibility"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 298)); + Choice *visibility = new Choice(co->T("Customize"), "", false, new AnchorLayoutParams(leftColumnWidth, WRAP_CONTENT, 10, NONE, NONE, 298)); // controlsSettings->Add(new PopupSliderChoiceFloat(&g_Config.fButtonScale, 0.80, 2.0, co->T("Button Scaling"), screenManager())) // ->OnChange.Handle(this, &GameSettingsScreen::OnChangeControlScaling); diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index 9a6bf19a4942..af88eb93e3bb 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -20,6 +20,7 @@ #include "TouchControlVisibilityScreen.h" #include "Core/Config.h" #include "Common/Data/Text/I18n.h" +#include "ComboKeyMappingScreen.h" static const int leftColumnWidth = 140; @@ -42,6 +43,7 @@ class CheckBoxChoice : public UI::Choice { void TouchControlVisibilityScreen::CreateViews() { using namespace UI; + using namespace CustomKey; auto di = GetI18NCategory("Dialog"); auto co = GetI18NCategory("Controls"); @@ -70,30 +72,62 @@ void TouchControlVisibilityScreen::CreateViews() { gridsettings.fillCells = true; GridLayout *grid = vert->Add(new GridLayoutList(gridsettings, new LayoutParams(FILL_PARENT, WRAP_CONTENT))); - static const char* rightAnalogKey = "Right Analog Stick (tap to customize)"; toggles_.clear(); - toggles_.push_back({ "Circle", &g_Config.bShowTouchCircle, ImageID("I_CIRCLE") }); - toggles_.push_back({ "Cross", &g_Config.bShowTouchCross, ImageID("I_CROSS") }); - toggles_.push_back({ "Square", &g_Config.bShowTouchSquare, ImageID("I_SQUARE") }); - toggles_.push_back({ "Triangle", &g_Config.bShowTouchTriangle, ImageID("I_TRIANGLE") }); - toggles_.push_back({ "L", &g_Config.touchLKey.show, ImageID("I_L") }); - toggles_.push_back({ "R", &g_Config.touchRKey.show, ImageID("I_R") }); - toggles_.push_back({ "Start", &g_Config.touchStartKey.show, ImageID("I_START") }); - toggles_.push_back({ "Select", &g_Config.touchSelectKey.show, ImageID("I_SELECT") }); - toggles_.push_back({ "Dpad", &g_Config.touchDpad.show, ImageID::invalid() }); - toggles_.push_back({ "Analog Stick", &g_Config.touchAnalogStick.show, ImageID::invalid() }); - toggles_.push_back({ rightAnalogKey, &g_Config.touchRightAnalogStick.show, ImageID::invalid() }); - toggles_.push_back({ "Unthrottle", &g_Config.touchUnthrottleKey.show, ImageID::invalid() }); - toggles_.push_back({ "Combo0", &g_Config.touchCombo0.show, ImageID("I_1") }); - toggles_.push_back({ "Combo1", &g_Config.touchCombo1.show, ImageID("I_2") }); - toggles_.push_back({ "Combo2", &g_Config.touchCombo2.show, ImageID("I_3") }); - toggles_.push_back({ "Combo3", &g_Config.touchCombo3.show, ImageID("I_4") }); - toggles_.push_back({ "Combo4", &g_Config.touchCombo4.show, ImageID("I_5") }); - toggles_.push_back({ "Alt speed 1", &g_Config.touchSpeed1Key.show, ImageID::invalid() }); - toggles_.push_back({ "Alt speed 2", &g_Config.touchSpeed2Key.show, ImageID::invalid() }); - toggles_.push_back({ "RapidFire", &g_Config.touchRapidFireKey.show, ImageID::invalid() }); - toggles_.push_back({ "Auto Analog Rotation (CW)", &g_Config.touchAnalogRotationCWKey.show, ImageID::invalid() }); - toggles_.push_back({ "Auto Analog Rotation (CCW)", &g_Config.touchAnalogRotationCCWKey.show, ImageID::invalid() }); + toggles_.push_back({ "Circle", &g_Config.bShowTouchCircle, ImageID("I_CIRCLE"), nullptr }); + toggles_.push_back({ "Cross", &g_Config.bShowTouchCross, ImageID("I_CROSS"), nullptr }); + toggles_.push_back({ "Square", &g_Config.bShowTouchSquare, ImageID("I_SQUARE"), nullptr }); + toggles_.push_back({ "Triangle", &g_Config.bShowTouchTriangle, ImageID("I_TRIANGLE"), nullptr }); + toggles_.push_back({ "L", &g_Config.touchLKey.show, ImageID("I_L"), nullptr }); + toggles_.push_back({ "R", &g_Config.touchRKey.show, ImageID("I_R"), nullptr }); + toggles_.push_back({ "Start", &g_Config.touchStartKey.show, ImageID("I_START"), nullptr }); + toggles_.push_back({ "Select", &g_Config.touchSelectKey.show, ImageID("I_SELECT"), nullptr }); + toggles_.push_back({ "Dpad", &g_Config.touchDpad.show, ImageID::invalid(), nullptr }); + toggles_.push_back({ "Analog Stick", &g_Config.touchAnalogStick.show, ImageID::invalid(), nullptr }); + toggles_.push_back({ "Right Analog Stick", &g_Config.touchRightAnalogStick.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new RightAnalogMappingScreen()); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Unthrottle", &g_Config.touchUnthrottleKey.show, ImageID::invalid(), nullptr }); + toggles_.push_back({ "Custom 1", &g_Config.touchCombo0.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(0)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 2", &g_Config.touchCombo1.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(1)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 3", &g_Config.touchCombo2.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(2)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 4", &g_Config.touchCombo3.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(3)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 5", &g_Config.touchCombo4.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(4)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 6", &g_Config.touchCombo5.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(5)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 7", &g_Config.touchCombo6.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(6)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 8", &g_Config.touchCombo7.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(7)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 9", &g_Config.touchCombo8.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(8)); + return UI::EVENT_DONE; + }}); + toggles_.push_back({ "Custom 10", &g_Config.touchCombo9.show, ImageID::invalid(), [=](EventParams &e) { + screenManager()->push(new ComboKeyScreen(9)); + return UI::EVENT_DONE; + }}); auto mc = GetI18NCategory("MappableControls"); for (auto toggle : toggles_) { @@ -102,21 +136,17 @@ void TouchControlVisibilityScreen::CreateViews() { CheckBox *checkbox = new CheckBox(toggle.show, "", "", new LinearLayoutParams(50, WRAP_CONTENT)); row->Add(checkbox); - - if (toggle.key == rightAnalogKey) { - Choice *rightAnalog = new Choice(mc->T(rightAnalogKey), "", false, new LinearLayoutParams(1.0f)); - rightAnalog->SetCentered(true); - row->Add(rightAnalog)->OnClick.Handle(this, &TouchControlVisibilityScreen::RightAnalogBindScreen); + Choice *choice; + if (toggle.handle) { + choice = new Choice(std::string(mc->T(toggle.key))+mc->T(" (tap to customize)"), "", false, new LinearLayoutParams(1.0f)); + choice->OnClick.Add(toggle.handle); + } else if (toggle.img.isValid()) { + choice = new CheckBoxChoice(toggle.img, checkbox, new LinearLayoutParams(1.0f)); } else { - Choice *choice; - if (toggle.img.isValid()) { - choice = new CheckBoxChoice(toggle.img, checkbox, new LinearLayoutParams(1.0f)); - } else { - choice = new CheckBoxChoice(mc->T(toggle.key), checkbox, new LinearLayoutParams(1.0f)); - } - choice->SetCentered(true); - row->Add(choice); + choice = new CheckBoxChoice(mc->T(toggle.key), checkbox, new LinearLayoutParams(1.0f)); } + choice->SetCentered(true); + row->Add(choice); grid->Add(row); } } @@ -143,14 +173,14 @@ void RightAnalogMappingScreen::CreateViews() { vert->SetSpacing(0); static const char *rightAnalogButton[] = {"None", "L", "R", "Square", "Triangle", "Circle", "Cross", "D-pad up", "D-pad down", "D-pad left", "D-pad right", "Start", "Select"}; - + + vert->Add(new CheckBox(&g_Config.touchRightAnalogStick.show, co->T("Visible"))); vert->Add(new CheckBox(&g_Config.bRightAnalogCustom, co->T("Use custom right analog"))); PopupMultiChoice *rightAnalogUp = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogUp, mc->T("RightAn.Up"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); PopupMultiChoice *rightAnalogDown = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogDown, mc->T("RightAn.Down"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); PopupMultiChoice *rightAnalogLeft = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogLeft, mc->T("RightAn.Left"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); PopupMultiChoice *rightAnalogRight = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogRight, mc->T("RightAn.Right"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); PopupMultiChoice *rightAnalogPress = vert->Add(new PopupMultiChoice(&g_Config.iRightAnalogPress, co->T("Keep this button pressed when right analog is pressed"), rightAnalogButton, 0, ARRAY_SIZE(rightAnalogButton), mc->GetName(), screenManager())); - vert->Add(new CheckBox(&g_Config.touchRightAnalogStick.show, co->T("Show right analog"))); rightAnalogUp->SetEnabledPtr(&g_Config.bRightAnalogCustom); rightAnalogDown->SetEnabledPtr(&g_Config.bRightAnalogCustom); rightAnalogLeft->SetEnabledPtr(&g_Config.bRightAnalogCustom); diff --git a/UI/TouchControlVisibilityScreen.h b/UI/TouchControlVisibilityScreen.h index 04be4a1872cb..c3a7df1613d8 100644 --- a/UI/TouchControlVisibilityScreen.h +++ b/UI/TouchControlVisibilityScreen.h @@ -28,6 +28,7 @@ struct TouchButtonToggle { const char *key; bool *show; ImageID img; + std::function handle; }; class TouchControlVisibilityScreen : public UIDialogScreenWithBackground { diff --git a/atlasscript.txt b/atlasscript.txt index 3aa700a8b2fb..96aef8345753 100644 --- a/atlasscript.txt +++ b/atlasscript.txt @@ -51,4 +51,10 @@ image I_FLAG_KO source_assets/image/flag_ko.png copy image I_FULLSCREEN source_assets/image/fullscreen.png copy image I_RESTORE source_assets/image/restore.png copy image I_SDCARD source_assets/image/sdcard.png copy -image I_HOME source_assets/image/home.png copy \ No newline at end of file +image I_HOME source_assets/image/home.png copy +image I_A source_assets/image/a.png copy +image I_B source_assets/image/b.png copy +image I_C source_assets/image/c.png copy +image I_D source_assets/image/d.png copy +image I_E source_assets/image/e.png copy +image I_F source_assets/image/f.png copy diff --git a/source_assets/image/a.png b/source_assets/image/a.png new file mode 100644 index 0000000000000000000000000000000000000000..524904f29243db4c6664bbd3d77c7d2916deaa5c GIT binary patch literal 941 zcmV;e15*5nP); z%_+d6?(d8az?(=Uera}ka&q!3;H7<(|APi}4Gj%_TrQUjA|l0N@m~><%gf7Gqobpr z0A1?ctziLrc6N3`iePPJWo5NitJOqAc6WEb1A3_E{MN7mgV}8MZxNAPE|&lTxm+$G zB9hH!p8|t`y%nSD&;a|)%*=Z}pYI{S(b3WG!1H)Kz6;><`5rDVE{-Utw@QH(=#NID zKZ=M{tJTWnu@+eQ17p>y&k>>bZ%{J1-iSt2LYnd=x=}y7=XUNzrO?EcDo1G*Vn%QI@_hd z2E3b0Cig@{%H{I8&*%Gydihv@E|14Etn2zq5s}l=(>=ha>{^EI^!xn}DwRq}MC9=B z@Mqwj3f-aPU@R8>O)3rID`6d=sh?% z_}=gL&xnYG!{Lx=nmL=zW?pAt7>3m}&Hi98_=Ck_vBqMt?Xj`3$G|_Rk*EQk9*<|Z zR4TntZF#72*rOP@n~n!~3mD2|GEYTBbX|Yh*Vi|KDlbdJ>Bh#!S1y;UAK>`-cn>(I zK8$tXzow%r{kdvioK9!&+S=NeG}UYe;7zB~Peepa(=?{0rapgDnJ9hN`1tq(!!RyH zMAGT>A2iKb+uYpTuxXkXD)hh9Wy^wY`iFNinM_2Hxm;de9sz6}K<(`8?8U;u!l%Vz z(Voxe&w&E%caRCZnw_1U_j&Bn#R?Qsd05Eo$jHH*VdAAhZZ{ zG0PT#khaLhB!~;MpjC@R29im$X_$}Zy*KZ@+roRrQL{R5c<&zW{c}G4=P!T&5L92m zNt4Qb<@yYO0ffiL$D0CyfN9&dar|{Imvd67R35N^GVlwiC@=t`nM`Iyo?(?rrIg8J z-Y+jNKLuhyt;!gHrgS>}?ks?#mQJVNHa0e12hIV)0EF-R0-#td{umhgu}O*VlJ@aB%Q(Lqo&0mX?;G#l^)Z@p$~1Duw3l?d?@5r7RQ*d%#Vg9yqVO z9%!1Fn7HpaPFYGRcXxL`0?mMNSOtir~|Mlu$QbpRJMnGON+`TTd_9&iI_1KJ~z z$gRoA$;A5l`ho`A+S+=p#uz@02O2%Byau=kw63kKE$D3K=jR^+^{4T`1)L*pD=uVL zR#x8VyFEQUaUfg;@CVbYTv=UR{i=g%AB@w8B&a459I!4tG&Izz1D@wu9Or=|Qiy|1 z3#xEHoi8O4i7|b5XJ_XV;2h5&(BI$RZklE^6biXgN)e02>bkqTI|c>@9&~ng4g-|S z<^7qNnU@^&=l}G;vaIaf+}t?OsI&a5B6*(YX0zEZo12?2Mn^~Q0H!Kc2%zRHO{`QZ t-qO-ij)ReEO>_Vckb-|#<>Sf>z;8rQ`Zjn3;939x002ovPDHLkV1iHEc546t literal 0 HcmV?d00001 diff --git a/source_assets/image/buttons.svg b/source_assets/image/buttons.svg index 61aa45225834..644c2bc86b82 100644 --- a/source_assets/image/buttons.svg +++ b/source_assets/image/buttons.svg @@ -12,7 +12,7 @@ height="1052.3622047" id="svg2" version="1.1" - inkscape:version="1.0beta2 (5ba348d, 2020-03-28)" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" sodipodi:docname="buttons.svg"> @@ -1388,6 +1388,198 @@ in2="offset" id="feComposite5130-3" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A + B + C + D + F + E diff --git a/source_assets/image/c.png b/source_assets/image/c.png new file mode 100644 index 0000000000000000000000000000000000000000..bcb7f503d5deec5ae799f10594d418d7aa13fff9 GIT binary patch literal 749 zcmV3wub3I(RUbaia}JP0{&b+Rod-_l?oE+Jzo?XNKpU_dDPBdA{Fw0@RLx zZv^FCg^ImDmD^pWb4}ew$ z6au2UuJ<{PvmxK}48vHMn3#Cf-`{@=xYE*pemMIpCuN}u(7ea{T<>gnh1O$MV zbUJ-)YisM15JFU|)&0rINgcQZ#AUrSpjmGHY$}zyv9hxAwp1!T2cnA2>G}EjXNvON z+}umx0?;Dok9RRF=h{X_MlJ#;keANg-QBN32w_>4nMfqAOBTTzT|M3$^&ujh0~lsS<`^ya&E>D7c1zLeXgSj7n50l`p^#Y6$ILKmkqDA}X=7 zvtu_3qJV_!x{gZ3VzHAP^;X?LRm-wARHD7T{XB<-ZU`(0925$LcPi1<)z!_R`2N=V zn(^Os^qaEt`F!2V9vvO+kYtW{tyHhq(&=A=*Y$gj<7_JTudS^Wvf1q8 zOeS+1>HhKY@%zPM@r^nq{O(t*!a#g@c=)bqnjh;qk1WgjoXh1h_|79g*sl|Eb#-;t zwr$h%ysBF4IL>CdT+UBVPd`Z}lb7YT!nL%birFj++6;sT2M6Pei;I?F7%s36xN;l- f;!mP$_%HGkR4STa=S&Wg00000NkvXXu0mjfqqJaj literal 0 HcmV?d00001 diff --git a/source_assets/image/d.png b/source_assets/image/d.png new file mode 100644 index 0000000000000000000000000000000000000000..9ff0eb4a7df0fea45bedd729f6506a5ae3ee37d2 GIT binary patch literal 809 zcmV+^1J?YBP)A`f`00009a7bBm000fw z000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10=7v+ zK~y-6os~UETTv9pf6qMA*XEh{m8LWw6cGv5R1kD1j$$Znr>=I9K!*;Zi^VPur4Ve% z=H}oev|Bp}E)|ohg(n*7)*-PCRbra&CTa3shrAbznp$(<@b0-9dgSS)t8+da9uy86-M@jP8#UXB1c zy%hBA?CiWXe!H-+@CfJyuIp|Ax`A5`hhs!hlnrBTE|>c;K0ba|Ung{&Euh(KuIhz0 zid_VUT3vxaz|#(_0Zb$k`+6))O-=a#u^pHORMYA7Ph-Mn zv-P%{8Gx40=Zi)lNs`P(xA~tYbai#fMo=gea)8zjOaMfi&E_yB^7(uUsI>z#0g}_{ zyr;+7=H});P`xV51W41<({7K)GXapvWWKMjuO9+6vBf5VW;HN0PXhWwq0kFa6eWOY zH2MxGaM3XM;o-*s*=+W3ZfSC$E74=M2RW%-uf0~(@xldis8UiT- zRaurxttzf*TCG$nrBkWYx8vjE{f&){_bV$aUx5sDRjC`s3H>0yvpWa5ax00000NkvXXu0mjfbkTHN literal 0 HcmV?d00001 diff --git a/source_assets/image/e.png b/source_assets/image/e.png new file mode 100644 index 0000000000000000000000000000000000000000..0d53463ba6e22fdb7813f4b4a52b8102f3736f11 GIT binary patch literal 512 zcmV+b0{{JqP)}1lSqrGcdBTS}kD}#m*dcFS9Y&Jgt-_yGCP@bIlMc%43>I2n2@3K?WZI==c`HVUALlugY zh3X;6P&i>Hz-dKR%2UlQPp)-3op)gvUX;D6APAf>CLWDOUjZ(c%jNAcLlVdF4e-VQ ze|_I~2kI-WdEM{#yZXu<76gG))t|sdIDUKXm%%@eBqGlT{gw3q0000)_ zHi;9v0|bIdC~H5-ie!I}U;BNn2tWdQ_Z3u^11ykgpwa8~I$;<#jWMc<@H{UIf?zWq zk6!_9k|bHV3o1#H6>u$qnse^lu}(?@GKUt6#q(e=cxboVUrH&PH%Td-Qpz@)%@7E6 zaR(v9W;&g|0PjFrB9i4s6d?yBKvV$%I9)O+3gf7`c&CGQmPw!i1SLu-U`~!#uh*|e zqtSg31V38qy%9nP*J`z*$z<|4o6VL0ohXXdm*g}Y4sQYfNXc58rfC`%OrfZzlrkrG zn$PD?-EOxJe6qE7zaJ0-Yaly!Jh0000< KMNUMnLSTYw=ec?S literal 0 HcmV?d00001