2020-09-15 19:12:32 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
2020-09-15 19:12:32 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-21 12:25:28 +00:00
|
|
|
// UIModeController.cpp
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Handling of application user interface modes (full, kiosk and kid).
|
|
|
|
// This includes switching the mode when the UI mode passkey is used.
|
2020-06-06 14:48:05 +00:00
|
|
|
//
|
|
|
|
|
2017-11-18 22:23:56 +00:00
|
|
|
#include "UIModeController.h"
|
|
|
|
|
|
|
|
#include "utils/StringUtil.h"
|
|
|
|
#include "views/ViewController.h"
|
2021-01-05 09:45:32 +00:00
|
|
|
#include "FileFilterIndex.h"
|
2017-11-18 22:23:56 +00:00
|
|
|
#include "Log.h"
|
2021-01-05 09:45:32 +00:00
|
|
|
#include "SystemData.h"
|
2017-11-18 22:23:56 +00:00
|
|
|
#include "Window.h"
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
UIModeController* UIModeController::sInstance = nullptr;
|
2017-11-18 22:23:56 +00:00
|
|
|
|
2020-07-14 17:16:21 +00:00
|
|
|
UIModeController* UIModeController::getInstance()
|
2017-11-18 22:23:56 +00:00
|
|
|
{
|
2020-06-23 18:07:00 +00:00
|
|
|
if (sInstance == nullptr)
|
2020-06-21 12:25:28 +00:00
|
|
|
sInstance = new UIModeController();
|
2017-11-18 22:23:56 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return sInstance;
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2021-03-19 17:34:10 +00:00
|
|
|
void UIModeController::deinit()
|
|
|
|
{
|
|
|
|
if (sInstance) {
|
|
|
|
delete sInstance;
|
|
|
|
sInstance = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
UIModeController::UIModeController() : mPassKeyCounter(0)
|
2017-11-18 22:23:56 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
|
|
|
|
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UIModeController::monitorUIMode()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::string uimode = Settings::getInstance()->getString("UIMode");
|
|
|
|
// UI mode was changed.
|
2021-01-05 09:45:32 +00:00
|
|
|
if (uimode != mCurrentUIMode && !ViewController::get()->isCameraMoving()) {
|
2020-06-21 12:25:28 +00:00
|
|
|
mCurrentUIMode = uimode;
|
2021-01-05 09:45:32 +00:00
|
|
|
// Reset filters and sort gamelists (which will update the game counter).
|
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); it !=
|
|
|
|
SystemData::sSystemVector.cend(); it++) {
|
|
|
|
(*it)->sortSystem(true);
|
|
|
|
(*it)->getIndex()->resetFilters();
|
|
|
|
if ((*it)->getThemeFolder() == "custom-collections") {
|
|
|
|
for (FileData* customSystem :
|
|
|
|
(*it)->getRootFolder()->getChildrenListToDisplay())
|
|
|
|
customSystem->getSystem()->getIndex()->resetFilters();
|
|
|
|
}
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
ViewController::get()->ReloadAndGoToStart();
|
|
|
|
}
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:16:21 +00:00
|
|
|
bool UIModeController::listen(InputConfig* config, Input input)
|
2017-11-18 22:23:56 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Reads the current input to listen for the passkey sequence to unlock
|
|
|
|
// the UI mode. The progress is saved in mPassKeyCounter.
|
2020-07-27 10:11:30 +00:00
|
|
|
if ((Settings::getInstance()->getString("UIMode") == "full") || !isValidInput(config, input))
|
2020-06-21 12:25:28 +00:00
|
|
|
return false; // Already unlocked, or invalid input, nothing to do here.
|
|
|
|
|
|
|
|
if (!inputIsMatch(config, input))
|
|
|
|
mPassKeyCounter = 0; // Current input is incorrect, reset counter.
|
|
|
|
|
2020-11-17 22:06:54 +00:00
|
|
|
if (mPassKeyCounter == static_cast<int>(mPassKeySequence.length())) {
|
2020-06-21 12:25:28 +00:00
|
|
|
unlockUIMode();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:16:21 +00:00
|
|
|
bool UIModeController::inputIsMatch(InputConfig* config, Input input)
|
2017-11-18 22:23:56 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto valstring : mInputVals) {
|
|
|
|
if (config->isMappedLike(valstring, input) &&
|
|
|
|
(mPassKeySequence[mPassKeyCounter] == valstring[0])) {
|
|
|
|
mPassKeyCounter++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2020-06-06 14:48:05 +00:00
|
|
|
// When we have reached the end of the list, trigger UI_mode unlock.
|
2017-11-18 22:23:56 +00:00
|
|
|
void UIModeController::unlockUIMode()
|
|
|
|
{
|
2020-12-23 21:30:53 +00:00
|
|
|
LOG(LogInfo) << "Passkey sequence completed, switching UI mode to Full";
|
2020-07-27 10:11:30 +00:00
|
|
|
Settings::getInstance()->setString("UIMode", "full");
|
2020-06-21 12:25:28 +00:00
|
|
|
Settings::getInstance()->saveFile();
|
|
|
|
mPassKeyCounter = 0;
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UIModeController::isUIModeFull()
|
|
|
|
{
|
2020-12-17 22:45:29 +00:00
|
|
|
return ((mCurrentUIMode == "full" || (isUIModeKid() &&
|
|
|
|
Settings::getInstance()->getBool("EnableMenuKidMode")))
|
|
|
|
&& !Settings::getInstance()->getBool("ForceKiosk"));
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool UIModeController::isUIModeKid()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
return (Settings::getInstance()->getBool("ForceKid") ||
|
2020-07-27 10:11:30 +00:00
|
|
|
((mCurrentUIMode == "kid") && !Settings::getInstance()->getBool("ForceKiosk")));
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2019-01-19 08:11:19 +00:00
|
|
|
bool UIModeController::isUIModeKiosk()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
return (Settings::getInstance()->getBool("ForceKiosk") ||
|
2020-07-27 10:11:30 +00:00
|
|
|
((mCurrentUIMode == "kiosk") && !Settings::getInstance()->getBool("ForceKid")));
|
2019-01-19 08:11:19 +00:00
|
|
|
}
|
|
|
|
|
2017-11-18 22:23:56 +00:00
|
|
|
std::string UIModeController::getFormattedPassKeyStr()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Supported sequence-inputs: u (up), d (down), l (left), r (right), a, b, x, y.
|
|
|
|
|
|
|
|
std::string out = "";
|
|
|
|
for (auto c : mPassKeySequence) {
|
2021-07-01 15:48:14 +00:00
|
|
|
out += (out == "") ? "" : " , "; // Add commas between the entries.
|
|
|
|
|
|
|
|
std::string controllerType = Settings::getInstance()->getString("InputControllerType");
|
|
|
|
std::string symbolA;
|
|
|
|
std::string symbolB;
|
|
|
|
std::string symbolX;
|
|
|
|
std::string symbolY;
|
|
|
|
|
|
|
|
if (controllerType == "snes") {
|
|
|
|
symbolA = "B";
|
|
|
|
symbolB = "A";
|
|
|
|
symbolX = "Y";
|
|
|
|
symbolY = "X";
|
|
|
|
}
|
|
|
|
else if (controllerType == "ps4" || controllerType == "ps5") {
|
|
|
|
// These symbols are far from perfect but you can at least understand what
|
|
|
|
// they are supposed to depict.
|
2021-07-02 16:56:52 +00:00
|
|
|
#if defined(_MSC_VER) // MSVC compiler.
|
|
|
|
symbolA = Utils::String::wideStringToString(L"\uF00D"); // Cross.
|
|
|
|
symbolB = Utils::String::wideStringToString(L"\uF111"); // Circle
|
|
|
|
symbolX = Utils::String::wideStringToString(L"\uF04D"); // Square.
|
|
|
|
symbolY = Utils::String::wideStringToString(L"\uF0D8"); // Triangle.
|
|
|
|
#else
|
2021-07-01 15:48:14 +00:00
|
|
|
symbolA = "\uF00D"; // Cross.
|
|
|
|
symbolB = "\uF111"; // Circle
|
|
|
|
symbolX = "\uF04D"; // Square.
|
|
|
|
symbolY = "\uF0D8"; // Triangle.
|
2021-07-02 16:56:52 +00:00
|
|
|
#endif
|
2021-07-01 15:48:14 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Xbox controller.
|
|
|
|
symbolA = "A";
|
|
|
|
symbolB = "B";
|
|
|
|
symbolX = "X";
|
|
|
|
symbolY = "Y";
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
switch (c) {
|
2020-07-14 17:16:21 +00:00
|
|
|
case 'u':
|
|
|
|
out += Utils::String::unicode2Chars(0x2191); // Arrow pointing up.
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
out += Utils::String::unicode2Chars(0x2193); // Arrow pointing down.
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
out += Utils::String::unicode2Chars(0x2190); // Arrow pointing left.
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
out += Utils::String::unicode2Chars(0x2192); // Arrow pointing right.
|
|
|
|
break;
|
|
|
|
case 'a':
|
2021-07-01 15:48:14 +00:00
|
|
|
out += symbolA;
|
2020-07-14 17:16:21 +00:00
|
|
|
break;
|
|
|
|
case 'b':
|
2021-07-01 15:48:14 +00:00
|
|
|
out += symbolB;
|
2020-07-14 17:16:21 +00:00
|
|
|
break;
|
|
|
|
case 'x':
|
2021-07-01 15:48:14 +00:00
|
|
|
out += symbolX;
|
2020-07-14 17:16:21 +00:00
|
|
|
break;
|
|
|
|
case 'y':
|
2021-07-01 15:48:14 +00:00
|
|
|
out += symbolY;
|
2020-07-14 17:16:21 +00:00
|
|
|
break;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return out;
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2020-07-14 17:16:21 +00:00
|
|
|
bool UIModeController::isValidInput(InputConfig* config, Input input)
|
2017-11-18 22:23:56 +00:00
|
|
|
{
|
2020-12-23 21:30:53 +00:00
|
|
|
if ((config->getMappedTo(input).size() == 0) || // Not a mapped input, so ignore it.
|
2020-06-21 12:25:28 +00:00
|
|
|
(!input.value)) // Not a key-down event.
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
2020-06-06 14:48:05 +00:00
|
|
|
}
|