Improved the behavior and consistency for the virtual keyboard when using non-standard keyboard mappings.

This commit is contained in:
Leon Styhre 2022-06-10 19:28:01 +02:00
parent de747a932d
commit cfc9d54068
4 changed files with 83 additions and 73 deletions

View file

@ -22,6 +22,7 @@ TextEditComponent::TextEditComponent()
: mRenderer {Renderer::getInstance()}
, mFocused {false}
, mEditing {false}
, mMaskInput {true}
, mCursor {0}
, mBlinkTime {0}
, mCursorRepeatDir {0}
@ -66,6 +67,9 @@ void TextEditComponent::setValue(const std::string& val)
void TextEditComponent::textInput(const std::string& text)
{
if (mMaskInput)
return;
if (mEditing) {
mBlinkTime = 0;
mCursorRepeatDir = 0;
@ -114,38 +118,33 @@ void TextEditComponent::stopEditing()
{
SDL_StopTextInput();
mEditing = false;
mMaskInput = false;
mCursorRepeatDir = 0;
updateHelpPrompts();
}
bool TextEditComponent::input(InputConfig* config, Input input)
{
bool const cursor_left =
(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("left", input)) ||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_LEFT);
bool const cursor_right =
(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("right", input)) ||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RIGHT);
bool const cursor_up =
(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("up", input)) ||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_UP);
bool const cursor_down =
(config->getDeviceId() != DEVICE_KEYBOARD && config->isMappedLike("down", input)) ||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_DOWN);
bool const shoulder_left = (config->isMappedLike("leftshoulder", input));
bool const shoulder_right = (config->isMappedLike("rightshoulder", input));
bool const trigger_left = (config->isMappedLike("lefttrigger", input));
bool const trigger_right = (config->isMappedLike("righttrigger", input));
bool const cursorLeft {config->isMappedLike("left", input)};
bool const cursorRight {config->isMappedLike("right", input)};
bool const cursorUp {config->isMappedLike("up", input)};
bool const cursorDown {config->isMappedLike("down", input)};
bool const shoulderLeft {config->isMappedLike("leftshoulder", input)};
bool const shoulderRight {config->isMappedLike("rightshoulder", input)};
bool const triggerLeft {config->isMappedLike("lefttrigger", input)};
bool const triggerRight {config->isMappedLike("righttrigger", input)};
if (input.value == 0) {
if (cursor_left || cursor_right || cursor_up || cursor_down || shoulder_left ||
shoulder_right | trigger_left || trigger_right) {
mMaskInput = true;
if (cursorLeft || cursorRight || cursorUp || cursorDown || shoulderLeft ||
shoulderRight | triggerLeft || triggerRight) {
if (input.value == 0)
mCursorRepeatDir = 0;
}
return false;
}
if (input.value == 0)
return false;
if ((config->isMappedTo("a", input) ||
(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN)) &&
mFocused && !mEditing) {
@ -154,63 +153,64 @@ bool TextEditComponent::input(InputConfig* config, Input input)
}
if (mEditing) {
if (config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_RETURN) {
if (isMultiline())
textInput("\n");
else
stopEditing();
if (config->getDeviceId() == DEVICE_KEYBOARD) {
// Special handling for keyboard input as the "A" and "B" buttons are overridden.
if (input.id == SDLK_RETURN) {
if (isMultiline())
textInput("\n");
else
stopEditing();
return true;
return true;
}
else if (input.id == SDLK_DELETE) {
if (mCursor < static_cast<int>(mText.length())) {
// Fake as Backspace one char to the right.
mMaskInput = false;
moveCursor(1);
textInput("\b");
}
return true;
}
else if (input.id == SDLK_BACKSPACE) {
mMaskInput = false;
textInput("\b");
return true;
}
}
if (cursor_left || cursor_right) {
if (cursorLeft || cursorRight) {
mBlinkTime = 0;
mCursorRepeatDir = cursor_left ? -1 : 1;
mCursorRepeatDir = cursorLeft ? -1 : 1;
mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED);
moveCursor(mCursorRepeatDir);
return false;
}
// Stop editing and let the button down event be captured by the parent component.
else if (cursor_down) {
else if (cursorDown) {
// Stop editing and let the button down event be captured by the parent component.
stopEditing();
return false;
}
else if (shoulder_left || shoulder_right) {
mBlinkTime = 0;
mCursorRepeatDir = shoulder_left ? -10 : 10;
mCursorRepeatTimer = -(CURSOR_REPEAT_START_DELAY - CURSOR_REPEAT_SPEED);
moveCursor(mCursorRepeatDir);
else if (shoulderLeft) {
mMaskInput = false;
textInput("\b");
return true;
}
// Jump to beginning of text.
else if (trigger_left) {
else if (triggerLeft) {
// Jump to beginning of text.
mBlinkTime = 0;
setCursor(0);
return true;
}
// Jump to end of text.
else if (trigger_right) {
else if (triggerRight) {
// Jump to end of text.
mBlinkTime = 0;
setCursor(mText.length());
return true;
}
else if (config->getDeviceId() == DEVICE_KEYBOARD) {
switch (input.id) {
case SDLK_HOME: {
setCursor(0);
break;
}
case SDLK_END: {
setCursor(std::string::npos);
break;
}
case SDLK_DELETE: {
if (mCursor < static_cast<int>(mText.length())) {
// Fake as Backspace one char to the right.
moveCursor(1);
textInput("\b");
}
break;
}
}
}
// Consume all input when editing text.
mMaskInput = false;
return true;
}

View file

@ -42,6 +42,7 @@ public:
std::shared_ptr<Font> getFont() const override { return mFont; }
void setCursor(size_t pos);
void setMaskInput(bool state) { mMaskInput = state; }
std::vector<HelpPrompt> getHelpPrompts() override;
@ -61,6 +62,7 @@ private:
std::string mTextOrig;
bool mFocused;
bool mEditing;
bool mMaskInput;
int mCursor; // Cursor position in characters.
int mBlinkTime;

View file

@ -340,15 +340,13 @@ bool GuiTextEditKeyboardPopup::input(InputConfig* config, Input input)
mNavigationRepeatDirY = 0;
}
// If the keyboard has been configured with backspace as the back button (which is the default
// configuration) then ignore this key if we're currently editing or otherwise it would be
// impossible to erase characters using this key.
bool keyboardBackspace = (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
input.id == SDLK_BACKSPACE);
// Ignore whatever key is mapped to the back button so it can be used for text input.
bool keyboardBack {config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
config->isMappedLike("b", input)};
// Pressing back (or the escape key if using keyboard input) closes us.
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_ESCAPE) ||
(!keyboardBackspace && input.value && config->isMappedTo("b", input))) {
(!keyboardBack && input.value && config->isMappedTo("b", input))) {
if (mText->getValue() != mInitValue) {
// Changes were made, ask if the user wants to save them.
mWindow->pushGui(new GuiMsgBox(
@ -393,7 +391,9 @@ bool GuiTextEditKeyboardPopup::input(InputConfig* config, Input input)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput("\b");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();
@ -410,7 +410,9 @@ bool GuiTextEditKeyboardPopup::input(InputConfig* config, Input input)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput(" ");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();
@ -523,7 +525,9 @@ void GuiTextEditKeyboardPopup::updateDeleteRepeat(int deltaTime)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput("\b");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();

View file

@ -165,15 +165,13 @@ bool GuiTextEditPopup::input(InputConfig* config, Input input)
return true;
}
// If the keyboard has been configured with backspace as the back button (which is the default
// configuration) then ignore this key if we're currently editing or otherwise it would be
// impossible to erase characters using this key.
bool keyboardBackspace = (config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
input.id == SDLK_BACKSPACE);
// Ignore whatever key is mapped to the back button so it can be used for text input.
bool keyboardBack {config->getDeviceId() == DEVICE_KEYBOARD && mText->isEditing() &&
config->isMappedLike("b", input)};
// Pressing back (or the escape key if using keyboard input) closes us.
if ((config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_ESCAPE) ||
(!keyboardBackspace && input.value && config->isMappedTo("b", input))) {
(!keyboardBack && input.value && config->isMappedTo("b", input))) {
if (mText->getValue() != mInitValue) {
// Changes were made, ask if the user wants to save them.
mWindow->pushGui(new GuiMsgBox(
@ -210,7 +208,9 @@ bool GuiTextEditPopup::input(InputConfig* config, Input input)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput("\b");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();
@ -227,7 +227,9 @@ bool GuiTextEditPopup::input(InputConfig* config, Input input)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput(" ");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();
@ -272,7 +274,9 @@ void GuiTextEditPopup::updateDeleteRepeat(int deltaTime)
if (!editing)
mText->startEditing();
mText->setMaskInput(false);
mText->textInput("\b");
mText->setMaskInput(true);
if (!editing)
mText->stopEditing();