From bd591a74cb8a1452476cbb4605390e6716a3c757 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Thu, 20 Jul 2023 16:01:24 +0200 Subject: [PATCH] Added support for pasting text into the application when a text input field is focused --- es-core/src/GuiComponent.cpp | 4 ++-- es-core/src/GuiComponent.h | 2 +- es-core/src/InputManager.cpp | 22 ++++++++++++++++++-- es-core/src/Window.cpp | 4 ++-- es-core/src/Window.h | 2 +- es-core/src/components/ComponentGrid.cpp | 4 ++-- es-core/src/components/ComponentGrid.h | 2 +- es-core/src/components/ComponentList.cpp | 4 ++-- es-core/src/components/ComponentList.h | 2 +- es-core/src/components/TextEditComponent.cpp | 8 +++++-- es-core/src/components/TextEditComponent.h | 2 +- 11 files changed, 39 insertions(+), 17 deletions(-) diff --git a/es-core/src/GuiComponent.cpp b/es-core/src/GuiComponent.cpp index 122e2d304..84d532ac2 100644 --- a/es-core/src/GuiComponent.cpp +++ b/es-core/src/GuiComponent.cpp @@ -62,10 +62,10 @@ GuiComponent::~GuiComponent() getChild(i)->setParent(nullptr); } -void GuiComponent::textInput(const std::string& text) +void GuiComponent::textInput(const std::string& text, const bool pasting) { for (auto it = mChildren.cbegin(); it != mChildren.cend(); ++it) - (*it)->textInput(text); + (*it)->textInput(text, pasting); } bool GuiComponent::input(InputConfig* config, Input input) diff --git a/es-core/src/GuiComponent.h b/es-core/src/GuiComponent.h index c89e19eb9..d5366d7a0 100644 --- a/es-core/src/GuiComponent.h +++ b/es-core/src/GuiComponent.h @@ -63,7 +63,7 @@ public: GuiComponent(); virtual ~GuiComponent(); - virtual void textInput(const std::string& text); + virtual void textInput(const std::string& text, const bool pasting = false); // Called when input is received. // Return true if the input is consumed, false if it should continue to be passed diff --git a/es-core/src/InputManager.cpp b/es-core/src/InputManager.cpp index 1fbda5b75..d232c7815 100644 --- a/es-core/src/InputManager.cpp +++ b/es-core/src/InputManager.cpp @@ -417,8 +417,26 @@ bool InputManager::parseEvent(const SDL_Event& event) return true; } case SDL_KEYDOWN: { - if (event.key.keysym.sym == SDLK_BACKSPACE && SDL_IsTextInputActive()) - mWindow->textInput("\b"); + if (SDL_IsTextInputActive()) { + // Paste from clipboard. +#if defined(__APPLE__) + if (event.key.keysym.mod & KMOD_GUI && event.key.keysym.sym == SDLK_v) { +#else + if ((event.key.keysym.mod & KMOD_CTRL && event.key.keysym.sym == SDLK_v) || + (event.key.keysym.mod & KMOD_SHIFT && event.key.keysym.sym == SDLK_INSERT)) { +#endif + if (SDL_HasClipboardText()) { + char* clipboardText {SDL_GetClipboardText()}; + mWindow->textInput(clipboardText, true); + SDL_free(clipboardText); + return true; + } + } + + // Handle backspace presses. + if (event.key.keysym.sym == SDLK_BACKSPACE) + mWindow->textInput("\b"); + } if (event.key.repeat) return false; diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index ad0400a4e..98c25afea 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -373,10 +373,10 @@ void Window::input(InputConfig* config, Input input) } } -void Window::textInput(const std::string& text) +void Window::textInput(const std::string& text, const bool pasting) { if (peekGui()) - peekGui()->textInput(text); + peekGui()->textInput(text, pasting); } void Window::logInput(InputConfig* config, Input input) diff --git a/es-core/src/Window.h b/es-core/src/Window.h index 0a495f242..f031de275 100644 --- a/es-core/src/Window.h +++ b/es-core/src/Window.h @@ -110,7 +110,7 @@ public: void deinit(); void input(InputConfig* config, Input input); - void textInput(const std::string& text); + void textInput(const std::string& text, const bool pasting = false); void logInput(InputConfig* config, Input input); void update(int deltaTime); void render(); diff --git a/es-core/src/components/ComponentGrid.cpp b/es-core/src/components/ComponentGrid.cpp index d6010473e..98de624d6 100644 --- a/es-core/src/components/ComponentGrid.cpp +++ b/es-core/src/components/ComponentGrid.cpp @@ -436,11 +436,11 @@ void ComponentGrid::render(const glm::mat4& parentTrans) } } -void ComponentGrid::textInput(const std::string& text) +void ComponentGrid::textInput(const std::string& text, const bool pasting) { const GridEntry* selectedEntry {getCellAt(mCursor)}; if (selectedEntry != nullptr && selectedEntry->canFocus) - selectedEntry->component->textInput(text); + selectedEntry->component->textInput(text, pasting); } void ComponentGrid::onCursorMoved(glm::ivec2 from, glm::ivec2 to) diff --git a/es-core/src/components/ComponentGrid.h b/es-core/src/components/ComponentGrid.h index aafcd4e57..0de281bee 100644 --- a/es-core/src/components/ComponentGrid.h +++ b/es-core/src/components/ComponentGrid.h @@ -51,7 +51,7 @@ public: mPastBoundaryCallback = func; } - void textInput(const std::string& text) override; + void textInput(const std::string& text, const bool pasting = false) override; bool input(InputConfig* config, Input input) override; void update(int deltaTime) override; void render(const glm::mat4& parentTrans) override; diff --git a/es-core/src/components/ComponentList.cpp b/es-core/src/components/ComponentList.cpp index c37fb1fb7..9e0983de1 100644 --- a/es-core/src/components/ComponentList.cpp +++ b/es-core/src/components/ComponentList.cpp @@ -490,12 +490,12 @@ void ComponentList::updateElementSize(const ComponentListRow& row) (*it)->setSize(width, (*it)->getSize().y); } -void ComponentList::textInput(const std::string& text) +void ComponentList::textInput(const std::string& text, const bool pasting) { if (!size()) return; - mEntries.at(mCursor).data.elements.back().component->textInput(text); + mEntries.at(mCursor).data.elements.back().component->textInput(text, pasting); } std::vector ComponentList::getHelpPrompts() diff --git a/es-core/src/components/ComponentList.h b/es-core/src/components/ComponentList.h index cd9f044d1..ce7826bc3 100644 --- a/es-core/src/components/ComponentList.h +++ b/es-core/src/components/ComponentList.h @@ -70,7 +70,7 @@ public: void addRow(const ComponentListRow& row, bool setCursorHere = false); - void textInput(const std::string& text) override; + void textInput(const std::string& text, const bool pasting = false) override; bool input(InputConfig* config, Input input) override; void update(int deltaTime) override; void render(const glm::mat4& parentTrans) override; diff --git a/es-core/src/components/TextEditComponent.cpp b/es-core/src/components/TextEditComponent.cpp index 6c904a0a0..009bb2931 100644 --- a/es-core/src/components/TextEditComponent.cpp +++ b/es-core/src/components/TextEditComponent.cpp @@ -71,9 +71,13 @@ void TextEditComponent::setValue(const std::string& val) onCursorChanged(); } -void TextEditComponent::textInput(const std::string& text) +void TextEditComponent::textInput(const std::string& text, const bool pasting) { - if (mMaskInput) + if (mMaskInput && !pasting) + return; + + // Allow pasting up to a reasonable max clipboard size. + if (pasting && text.length() > (isMultiline() ? 16384 : 300)) return; if (mEditing) { diff --git a/es-core/src/components/TextEditComponent.h b/es-core/src/components/TextEditComponent.h index 36cb9f44e..f6daf22c6 100644 --- a/es-core/src/components/TextEditComponent.h +++ b/es-core/src/components/TextEditComponent.h @@ -22,7 +22,7 @@ class TextEditComponent : public GuiComponent public: TextEditComponent(); - void textInput(const std::string& text) override; + void textInput(const std::string& text, const bool pasting = false) override; bool input(InputConfig* config, Input input) override; void update(int deltaTime) override; void render(const glm::mat4& parentTrans) override;