2018-05-09 09:25:01 +00:00
|
|
|
/*
|
|
|
|
* This file is part of Checkpoint
|
2019-03-07 20:15:24 +00:00
|
|
|
* Copyright (C) 2017-2019 Bernardo Giordano, FlagBrew
|
2018-05-09 09:25:01 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
|
|
|
* * Requiring preservation of specified reasonable legal notices or
|
|
|
|
* author attributions in that material or in the Appropriate Legal
|
|
|
|
* Notices displayed by works containing it.
|
|
|
|
* * Prohibiting misrepresentation of the origin of that material,
|
|
|
|
* or requiring that modified versions of such material be marked in
|
|
|
|
* reasonable ways as different from the original version.
|
|
|
|
*/
|
|
|
|
|
2018-06-17 08:22:37 +00:00
|
|
|
#include "KeyboardManager.hpp"
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2018-06-17 08:22:37 +00:00
|
|
|
void KeyboardManager::hid(size_t& currentEntry)
|
2018-05-12 10:33:04 +00:00
|
|
|
{
|
|
|
|
static const size_t columns = 11;
|
|
|
|
|
2018-05-14 18:02:40 +00:00
|
|
|
u64 kHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
|
2018-10-10 21:20:05 +00:00
|
|
|
|
|
|
|
currentTime = armGetSystemTick();
|
|
|
|
if ((currentTime > lastTime + DELAY_TICKS))
|
|
|
|
{
|
|
|
|
lastTime = currentTime;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
kHeld &= 0;
|
|
|
|
}
|
2018-05-14 18:02:40 +00:00
|
|
|
|
|
|
|
if (kHeld & KEY_LEFT)
|
2018-05-12 10:33:04 +00:00
|
|
|
{
|
|
|
|
switch (currentEntry)
|
|
|
|
{
|
|
|
|
case 0: // 1
|
|
|
|
case columns: // q
|
|
|
|
case columns*2: // a
|
|
|
|
case columns*3: // z
|
|
|
|
case INDEX_CAPS:
|
|
|
|
break;
|
|
|
|
case INDEX_BACK: // back -> @
|
|
|
|
currentEntry = columns-1;
|
|
|
|
break;
|
|
|
|
case INDEX_RETURN: // return -> +
|
|
|
|
currentEntry = columns*2-1;
|
|
|
|
break;
|
|
|
|
case INDEX_OK: // OK -> space
|
|
|
|
currentEntry = INDEX_SPACE;
|
|
|
|
break;
|
|
|
|
case INDEX_SPACE: // space -> caps
|
|
|
|
currentEntry = INDEX_CAPS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentEntry--;
|
|
|
|
}
|
|
|
|
}
|
2018-05-14 18:02:40 +00:00
|
|
|
else if (kHeld & KEY_RIGHT)
|
2018-05-12 10:33:04 +00:00
|
|
|
{
|
|
|
|
switch (currentEntry)
|
|
|
|
{
|
|
|
|
case 10: // @ -> back
|
|
|
|
currentEntry = INDEX_BACK;
|
|
|
|
break;
|
|
|
|
case 21: // + -> return
|
|
|
|
case 32: // : -> return
|
|
|
|
currentEntry = INDEX_RETURN;
|
|
|
|
break;
|
|
|
|
case 43: // /-> OK
|
|
|
|
case INDEX_SPACE: // space -> OK
|
|
|
|
currentEntry = INDEX_OK;
|
|
|
|
break;
|
|
|
|
case INDEX_CAPS: // caps -> space
|
|
|
|
currentEntry = INDEX_SPACE;
|
|
|
|
break;
|
|
|
|
case INDEX_BACK:
|
|
|
|
case INDEX_RETURN:
|
|
|
|
case INDEX_OK:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentEntry++;
|
|
|
|
}
|
|
|
|
}
|
2018-05-14 18:02:40 +00:00
|
|
|
else if (kHeld & KEY_UP)
|
2018-05-12 10:33:04 +00:00
|
|
|
{
|
|
|
|
switch (currentEntry)
|
|
|
|
{
|
|
|
|
case 0 ... 10: // 1 to @
|
|
|
|
case INDEX_BACK:
|
|
|
|
break;
|
|
|
|
case INDEX_CAPS: // caps -> x
|
|
|
|
currentEntry = 34;
|
|
|
|
break;
|
|
|
|
case INDEX_SPACE: // space -> .
|
|
|
|
currentEntry = 41;
|
|
|
|
break;
|
|
|
|
case INDEX_RETURN: // return -> back
|
|
|
|
currentEntry = INDEX_BACK;
|
|
|
|
break;
|
|
|
|
case INDEX_OK: // OK -> return
|
|
|
|
currentEntry = INDEX_RETURN;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentEntry -= 11;
|
|
|
|
}
|
|
|
|
}
|
2018-05-14 18:02:40 +00:00
|
|
|
else if (kHeld & KEY_DOWN)
|
2018-05-12 10:33:04 +00:00
|
|
|
{
|
|
|
|
switch (currentEntry)
|
|
|
|
{
|
|
|
|
case INDEX_CAPS:
|
|
|
|
case INDEX_SPACE:
|
|
|
|
case INDEX_OK:
|
|
|
|
break;
|
|
|
|
case 33 ... 35: // z x c -> caps
|
|
|
|
currentEntry = INDEX_CAPS;
|
|
|
|
break;
|
|
|
|
case 36 ... 43: // v b n m , . - / -> space
|
|
|
|
currentEntry = INDEX_SPACE;
|
|
|
|
break;
|
|
|
|
case INDEX_BACK: // back -> return
|
|
|
|
currentEntry = INDEX_RETURN;
|
|
|
|
break;
|
|
|
|
case INDEX_RETURN: // return -> OK
|
|
|
|
currentEntry = INDEX_OK;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
currentEntry += 11;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-17 08:22:37 +00:00
|
|
|
KeyboardManager::KeyboardManager(void)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
|
|
|
buttons.clear();
|
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
SwkbdConfig kbd;
|
|
|
|
Result res = swkbdCreate(&kbd, 0);
|
|
|
|
if (R_SUCCEEDED(res))
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
isSystemKeyboardAvailable = true;
|
|
|
|
swkbdClose(&kbd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// fallback to custom keyboard
|
|
|
|
isSystemKeyboardAvailable = false;
|
|
|
|
// fill with the above characters
|
|
|
|
for (size_t i = 0; i < 4; i++)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
for (size_t j = 0; j < 11; j++)
|
|
|
|
{
|
|
|
|
HbkbdButton* button = new HbkbdButton(
|
|
|
|
marginlr + (buttonSpacing + normalWidth) * j,
|
|
|
|
starty + (buttonSpacing + height) * i,
|
|
|
|
normalWidth,
|
|
|
|
height,
|
|
|
|
dtheme().c3,
|
|
|
|
dtheme().c6,
|
|
|
|
letters.substr(i*11+j, 1),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(button);
|
|
|
|
}
|
2018-05-09 09:25:01 +00:00
|
|
|
}
|
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
HbkbdButton* backspace = new HbkbdButton(
|
|
|
|
marginlr + (buttonSpacing + normalWidth) * 11,
|
|
|
|
starty,
|
|
|
|
bigWidth,
|
|
|
|
height,
|
|
|
|
dtheme().c6,
|
|
|
|
dtheme().c0,
|
|
|
|
"back",
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(backspace);
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
HbkbdButton* returnb = new HbkbdButton(
|
|
|
|
marginlr + (buttonSpacing + normalWidth) * 11,
|
|
|
|
starty + height + 4,
|
|
|
|
bigWidth,
|
|
|
|
height * 2 + 4,
|
|
|
|
dtheme().c4,
|
|
|
|
dtheme().c5,
|
|
|
|
"return",
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(returnb);
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
HbkbdButton* ok = new HbkbdButton(
|
|
|
|
marginlr + (buttonSpacing + normalWidth) * 11,
|
|
|
|
starty + height*3 + 4*3,
|
|
|
|
bigWidth,
|
|
|
|
height * 2 + 4,
|
|
|
|
COLOR_GREEN,
|
|
|
|
dtheme().c0,
|
|
|
|
"OK",
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(ok);
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
HbkbdButton* caps = new HbkbdButton(
|
|
|
|
marginlr + buttonSpacing + normalWidth,
|
|
|
|
starty + height*4 + 4*4,
|
|
|
|
normalWidth,
|
|
|
|
height,
|
|
|
|
dtheme().c4,
|
|
|
|
dtheme().c6,
|
|
|
|
"caps",
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(caps);
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
HbkbdButton* spacebar = new HbkbdButton(
|
|
|
|
marginlr + (buttonSpacing + normalWidth) * 3,
|
|
|
|
starty + height*4 + 4*4,
|
|
|
|
normalWidth*8 + buttonSpacing*7,
|
|
|
|
height,
|
|
|
|
dtheme().c4,
|
|
|
|
dtheme().c6,
|
|
|
|
"space",
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buttons.push_back(spacebar);
|
2018-05-12 08:04:39 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
// set OK button as selected
|
|
|
|
buttons.at(INDEX_OK)->selected(true);
|
|
|
|
buttons.at(INDEX_OK)->invertColors();
|
|
|
|
prevSelectedButtonIndex = INDEX_OK;
|
|
|
|
}
|
2018-05-09 09:25:01 +00:00
|
|
|
}
|
|
|
|
|
2018-06-17 08:22:37 +00:00
|
|
|
KeyboardManager::~KeyboardManager(void)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
if (!isSystemKeyboardAvailable)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
for (size_t i = 0; i < buttons.size(); i++)
|
|
|
|
{
|
|
|
|
delete buttons[i];
|
|
|
|
}
|
2018-05-09 09:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-17 08:22:37 +00:00
|
|
|
bool KeyboardManager::logic(std::string& str, size_t i)
|
2018-05-12 08:04:39 +00:00
|
|
|
{
|
|
|
|
if (buttons.at(i)->text().compare("caps") == 0)
|
|
|
|
{
|
|
|
|
std::locale loc;
|
|
|
|
bool islower = std::islower(buttons.at(11)->text()[0], loc);
|
|
|
|
for (size_t t = 0; t < letters.length(); t++)
|
|
|
|
{
|
|
|
|
std::string l = islower ? std::string(1, std::toupper(letters[t], loc)) : std::string(1, std::tolower(letters[t], loc));
|
|
|
|
buttons.at(t)->text(l);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (buttons.at(i)->text().compare("back") == 0)
|
|
|
|
{
|
|
|
|
if (!str.empty())
|
|
|
|
{
|
|
|
|
str.erase(str.length() - 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (buttons.at(i)->text().compare("space") == 0)
|
|
|
|
{
|
|
|
|
if (str.length() < CUSTOM_PATH_LEN)
|
|
|
|
{
|
|
|
|
str.append(" ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (buttons.at(i)->text().compare("return") == 0)
|
|
|
|
{
|
|
|
|
//str.append("\n");
|
|
|
|
}
|
|
|
|
else if (buttons.at(i)->text().compare("OK") == 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (str.length() < CUSTOM_PATH_LEN)
|
|
|
|
{
|
|
|
|
str.append(buttons.at(i)->text());
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-05 14:44:55 +00:00
|
|
|
std::pair<bool, std::string> KeyboardManager::keyboard(const std::string& suggestion)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
if (isSystemKeyboardAvailable)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
char tmpoutstr[CUSTOM_PATH_LEN] = {0};
|
|
|
|
SwkbdConfig kbd;
|
|
|
|
if (R_SUCCEEDED(swkbdCreate(&kbd, 0)))
|
2018-05-12 08:04:39 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
swkbdConfigMakePresetDefault(&kbd);
|
|
|
|
swkbdConfigSetInitialText(&kbd, suggestion.c_str());
|
|
|
|
Result res = swkbdShow(&kbd, tmpoutstr, CUSTOM_PATH_LEN);
|
|
|
|
swkbdClose(&kbd);
|
|
|
|
if (R_SUCCEEDED(res))
|
2018-05-12 08:04:39 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
return std::make_pair(true, std::string(tmpoutstr));
|
2018-05-12 08:04:39 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-09 23:24:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t index;
|
|
|
|
std::string str;
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
while (appletMainLoop() && !(hidKeysDown(CONTROLLER_P1_AUTO) & KEY_B))
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
hidScanInput();
|
|
|
|
index = prevSelectedButtonIndex;
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
// handle keys
|
|
|
|
hid(index);
|
|
|
|
if (index != prevSelectedButtonIndex)
|
|
|
|
{
|
|
|
|
buttons.at(prevSelectedButtonIndex)->selected(false);
|
|
|
|
buttons.at(prevSelectedButtonIndex)->invertColors();
|
|
|
|
prevSelectedButtonIndex = index;
|
|
|
|
buttons.at(index)->selected(true);
|
|
|
|
buttons.at(prevSelectedButtonIndex)->invertColors();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hidKeysDown(CONTROLLER_P1_AUTO) & KEY_A)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
bool ret = logic(str, index);
|
2018-05-12 08:04:39 +00:00
|
|
|
if (ret)
|
2018-05-09 09:25:01 +00:00
|
|
|
{
|
2018-08-05 14:44:55 +00:00
|
|
|
return str.empty() ? std::make_pair(true, suggestion) : std::make_pair(true, str);
|
2018-05-09 09:25:01 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-12 08:04:39 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
SDLH_ClearScreen(dtheme().c1);
|
|
|
|
|
|
|
|
SDLH_DrawRect(marginlr, 140, 1280 - marginlr*2, 84, dtheme().c4);
|
|
|
|
SDLH_DrawRect(0, starty - margintb, 1280, 356, dtheme().c2);
|
|
|
|
|
|
|
|
u32 texth, counter_width;
|
|
|
|
std::string counter = StringUtils::format("Custom name length: %d/%d", str.empty() ? suggestion.length() : str.length(), CUSTOM_PATH_LEN);
|
|
|
|
SDLH_GetTextDimensions(30, " ", NULL, &texth);
|
|
|
|
SDLH_GetTextDimensions(20, counter.c_str(), &counter_width, NULL);
|
|
|
|
SDLH_DrawText(20, 1280 - marginlr - counter_width, 236, dtheme().c6, counter.c_str());
|
|
|
|
if (str.empty())
|
2018-05-12 08:04:39 +00:00
|
|
|
{
|
2019-03-09 23:24:02 +00:00
|
|
|
SDLH_DrawTextBox(30, marginlr*2, 140 + (84 - texth) / 2, dtheme().c5, 1280 - marginlr*2, suggestion.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SDLH_DrawTextBox(30, marginlr*2, 140 + (84 - texth) / 2, dtheme().c6, 1280 - marginlr*2, str.c_str());
|
2018-05-12 08:04:39 +00:00
|
|
|
}
|
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
for (size_t i = 0, sz = buttons.size(); i < sz; i++)
|
|
|
|
{
|
|
|
|
if (buttons.at(i)->released())
|
|
|
|
{
|
|
|
|
bool ret = logic(str, i);
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
return str.empty() ? std::make_pair(true, suggestion) : std::make_pair(true, str);
|
|
|
|
}
|
|
|
|
}
|
2018-05-09 09:25:01 +00:00
|
|
|
|
2019-03-09 23:24:02 +00:00
|
|
|
// selection logic
|
|
|
|
if (buttons.at(i)->held() && i != prevSelectedButtonIndex)
|
|
|
|
{
|
|
|
|
buttons.at(prevSelectedButtonIndex)->selected(false);
|
|
|
|
buttons.at(prevSelectedButtonIndex)->invertColors();
|
|
|
|
prevSelectedButtonIndex = i;
|
|
|
|
buttons.at(i)->selected(true);
|
|
|
|
buttons.at(i)->invertColors();
|
|
|
|
}
|
|
|
|
|
|
|
|
buttons.at(i)->draw();
|
|
|
|
}
|
|
|
|
|
|
|
|
SDLH_Render();
|
|
|
|
}
|
2018-05-09 09:25:01 +00:00
|
|
|
}
|
|
|
|
|
2018-08-05 14:44:55 +00:00
|
|
|
return std::make_pair(false, suggestion);
|
2018-09-03 19:13:42 +00:00
|
|
|
}
|