Customizable touch control (rebased with label)

This commit is contained in:
iota97 2021-03-04 10:37:35 +01:00 committed by Henrik Rydgård
parent 4423e44b24
commit 498878267a
25 changed files with 873 additions and 426 deletions

View File

@ -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);

View File

@ -35,6 +35,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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<std::string>& values);

View File

@ -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;

View File

@ -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 <typename N>
static bool TryParse(const std::string &str, N *const output) {

View File

@ -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) {

View File

@ -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 @@ public:
bool bGridView1;
bool bGridView2;
bool bGridView3;
//Combo key screen flag
int iComboMode;
// Right analog binding
int iRightAnalogUp;
@ -349,11 +354,11 @@ public:
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 @@ public:
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;

View File

@ -16,6 +16,7 @@ public:
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 @@ public:
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);

View File

@ -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<UIScreen>(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<std::string, ImageID> 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];
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));
std::map<std::string, ImageID>::iterator imageFinder;
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<UIScreen>(this, &UIScreen::OnBack);
root__->Add(rightScroll_);
auto mc = GetI18NCategory("MappableControls");
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")));
for (auto i = keyToggles.begin(); i != keyToggles.end(); ++i) {
// 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;
}
void ComboKeyScreen::saveArray() {
switch (id_) {
case 0:
g_Config.CustomKey0.key = arrayToInt(array);
break;
case 1:
g_Config.CustomKey1.key = arrayToInt(array);
break;
case 2:
g_Config.CustomKey2.key = arrayToInt(array);
break;
case 3:
g_Config.CustomKey3.key = arrayToInt(array);
break;
case 4:
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;
}
return value >> 1;
}
void ComboKeyScreen::onFinish(DialogResult result) {
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);
break;
}
g_Config.Save("ComboKeyScreen::onFInish");
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;
}

View File

@ -18,6 +18,7 @@
#pragma once
#include "MiscScreens.h"
#include "UI/GamepadEmu.h"
#include <map>
@ -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<std::string, bool*> keyToggles;
bool array[16];
int *mode;
void saveArray();
bool array[ARRAY_SIZE(CustomKey::comboKeyList)];
int id_;
UI::ChoiceStrip *comboselect;
UI::ScrollView *rightScroll_;
class ChoiceEventHandler{

View File

@ -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);
}

View File

@ -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"));

View File

@ -74,7 +74,6 @@ private:
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);

View File

@ -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;
}

View File

@ -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 @@ private:
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 @@ private:
//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");
};

View File

@ -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);

View File

@ -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 @@ private:
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);

View File

@ -28,6 +28,7 @@ struct TouchButtonToggle {
const char *key;
bool *show;
ImageID img;
std::function<UI::EventReturn(UI::EventParams&)> handle;
};
class TouchControlVisibilityScreen : public UIDialogScreenWithBackground {

View File

@ -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
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

BIN
source_assets/image/a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

BIN
source_assets/image/b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

View File

@ -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">
<defs
id="defs4">
@ -1388,6 +1388,198 @@
in2="offset"
id="feComposite5130-3" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3-9">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6-1" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7-2" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5-7" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3-0" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5-9" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3-0">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6-6" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7-26" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5-1" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3-8" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5-7" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3-02">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6-3" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7-7" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5-5" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3-9" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5-2" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3-97">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6-36" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7-1" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5-2" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3-93" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5-1" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
inkscape:label="Drop Shadow"
id="filter4775-3-8">
<feFlood
flood-opacity="0.498039"
flood-color="rgb(0,0,0)"
result="flood"
id="feFlood4777-6-4" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="in"
result="composite1"
id="feComposite4779-7-5" />
<feGaussianBlur
in="composite1"
stdDeviation="1"
result="blur"
id="feGaussianBlur4781-5-0" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset4783-3-3" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
result="composite2"
id="feComposite4785-5-6" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -1396,16 +1588,16 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="207.38755"
inkscape:cy="188.37622"
inkscape:zoom="3.959798"
inkscape:cx="287.37168"
inkscape:cy="17.065748"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1537"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-width="1920"
inkscape:window-height="1027"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:document-rotation="0">
<inkscape:grid
@ -2103,5 +2295,83 @@
d="m 188.91385,48.29099 v 19.545807 h 19.28584 V 48.29099 Z m 2.49666,2.529991 h 14.295 v 14.485834 h -14.295 z"
style="fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter5216)" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3)"
x="287.70575"
y="30.76185"
id="text3635-6"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2"
x="287.70575"
y="30.76185"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">A</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3-9)"
x="309.8139"
y="31.120909"
id="text3635-6-3"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2-6"
x="309.8139"
y="31.120909"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">B</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3-0)"
x="331.02643"
y="31.334555"
id="text3635-6-9"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2-2"
x="331.02643"
y="31.334555"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">C</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3-02)"
x="351.77972"
y="31.095232"
id="text3635-6-2"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2-8"
x="351.77972"
y="31.095232"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">D</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3-97)"
x="350.99432"
y="56.332092"
id="text3635-6-94"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2-7"
x="350.99432"
y="56.332092"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">F</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4775-3-8)"
x="373.82898"
y="31.423817"
id="text3635-6-1"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"><tspan
sodipodi:role="line"
id="tspan3637-2-0"
x="373.82898"
y="31.423817"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:27.5px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1">E</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 89 KiB

BIN
source_assets/image/c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

BIN
source_assets/image/d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

BIN
source_assets/image/e.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

BIN
source_assets/image/f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B