From c8779838934fed294e84ab19977cdcc5106bbcf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 5 Jun 2025 20:40:05 +0200 Subject: [PATCH] Platform: add clipboard handling to Sdl2 and GlfwApplication. Text only, SDL3 has support for arbitrary mime types so the API is named clipboardText() and not just clipboar(). Wanted to add this for Emscripten as well, but after looking around a bit, I don't think I want to deal with that until someone actually wants clipboard support somewhere. --- doc/changelog.dox | 3 +++ src/Magnum/Platform/EmscriptenApplication.h | 6 +++++ src/Magnum/Platform/GlfwApplication.cpp | 8 +++++++ src/Magnum/Platform/GlfwApplication.h | 23 ++++++++++++++++++ src/Magnum/Platform/Sdl2Application.cpp | 12 ++++++++++ src/Magnum/Platform/Sdl2Application.h | 24 +++++++++++++++++++ .../Platform/Test/GlfwApplicationTest.cpp | 7 +++++- .../Platform/Test/Sdl2ApplicationTest.cpp | 7 +++++- 8 files changed, 88 insertions(+), 2 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 624e1fb99..b7f865a69 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -382,6 +382,9 @@ See also: @relativeref{Platform::Sdl2Application,blurEvent()} to @ref Platform::Sdl2Application, @ref Platform::GlfwApplication, @ref Platform::EmscriptenApplication and @ref Platform::AndroidApplication +- Added @relativeref{Platform::Sdl2Application,clipboardText()} and + @relativeref{Platform::Sdl2Application,setClipboardText()} to + @ref Platform::Sdl2Application and @ref Platform::GlfwApplication @subsubsection changelog-latest-new-scenegraph SceneGraph library diff --git a/src/Magnum/Platform/EmscriptenApplication.h b/src/Magnum/Platform/EmscriptenApplication.h index f47af5ac1..ae618c8cc 100644 --- a/src/Magnum/Platform/EmscriptenApplication.h +++ b/src/Magnum/Platform/EmscriptenApplication.h @@ -1103,6 +1103,12 @@ class EmscriptenApplication { */ void setTextInputRect(const Range2Di& rect); + /* Unlike Sdl2Application and GlfwApplication, here's no clipboard + support, because due to security reasons, the browser API is + extremely convoluted: + https://github.com/pthom/hello_imgui/issues/3 + https://github.com/emscripten-core/emscripten/pull/19510 */ + private: /** * @brief Text input event diff --git a/src/Magnum/Platform/GlfwApplication.cpp b/src/Magnum/Platform/GlfwApplication.cpp index afb17e413..9b0357f9d 100644 --- a/src/Magnum/Platform/GlfwApplication.cpp +++ b/src/Magnum/Platform/GlfwApplication.cpp @@ -1122,6 +1122,14 @@ void GlfwApplication::stopTextInput() { _flags &= ~Flag::TextInputActive; } +Containers::StringView GlfwApplication::clipboardText() { + return glfwGetClipboardString(_window); +} + +void GlfwApplication::setClipboardText(const Containers::StringView text) { + glfwSetClipboardString(_window, Containers::String::nullTerminatedView(text).data()); +} + #ifdef MAGNUM_TARGET_GL GlfwApplication::GLConfiguration::GLConfiguration(): _colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0}, diff --git a/src/Magnum/Platform/GlfwApplication.h b/src/Magnum/Platform/GlfwApplication.h index 256d1fa6d..9fb49d95d 100644 --- a/src/Magnum/Platform/GlfwApplication.h +++ b/src/Magnum/Platform/GlfwApplication.h @@ -925,6 +925,29 @@ class GlfwApplication { */ void stopTextInput(); + /** + * @brief Current clipboard text + * @m_since_latest + * + * The returned view is in UTF-8, is always + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated} and + * is only guaranteed to be valid until the next call to + * @ref clipboardText() or @ref setClipboardText(). If the clipboard is + * empty or contains non-text data (such as an image), the returned + * view is empty. + */ + Containers::StringView clipboardText(); + + /** + * @brief Set current clipboard text + * @m_since_latest + * + * The @p text is expected to be in UTF-8. If it's not + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}, a + * null-terminated copy is made before passing it to GLFW. + */ + void setClipboardText(Containers::StringView text); + private: /** * @brief Text input event diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index 7c4214de3..be7d1f11e 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -1454,6 +1454,18 @@ void Sdl2Application::setTextInputRect(const Range2Di& rect) { SDL_SetTextInputRect(&r); } +#ifndef CORRADE_TARGET_EMSCRIPTEN +Containers::String Sdl2Application::clipboardText() { + return Containers::String{SDL_GetClipboardText(), [](char* const data, std::size_t) { + SDL_free(data); + }}; +} + +void Sdl2Application::setClipboardText(const Containers::StringView text) { + SDL_SetClipboardText(Containers::String::nullTerminatedView(text).data()); +} +#endif + void Sdl2Application::exitEvent(ExitEvent& event) { event.setAccepted(); } diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index 87276554c..394804960 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -1466,6 +1466,30 @@ class Sdl2Application { */ void setTextInputRect(const Range2Di& rect); + #ifndef CORRADE_TARGET_EMSCRIPTEN + /** + * @brief Current clipboard text + * @m_since_latest + * + * The returned string is in UTF-8. If the clipboard is empty or + * contains non-text data (such as an image), the returned string is + * empty. + * @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + */ + Containers::String clipboardText(); + + /** + * @brief Set current clipboard text + * @m_since_latest + * + * The @p text is expected to be in UTF-8. If it's not + * @relativeref{Corrade,Containers::StringViewFlag::NullTerminated}, a + * null-terminated copy is made before passing it to SDL. + * @note Not available on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten". + */ + void setClipboardText(Containers::StringView text); + #endif + private: /** * @brief Text input event diff --git a/src/Magnum/Platform/Test/GlfwApplicationTest.cpp b/src/Magnum/Platform/Test/GlfwApplicationTest.cpp index b78ae7bc7..c04ce9def 100644 --- a/src/Magnum/Platform/Test/GlfwApplicationTest.cpp +++ b/src/Magnum/Platform/Test/GlfwApplicationTest.cpp @@ -323,10 +323,15 @@ struct GlfwApplicationTest: Platform::Application { _redraw = !_redraw; Debug{} << "redrawing" << (_redraw ? "enabled" : "disabled"); if(_redraw) redraw(); - } else if(event.key() == Key::V) { + } else if(event.key() == Key::V && !event.modifiers()) { _vsync = !_vsync; Debug{} << "vsync" << (_vsync? "on" : "off"); setSwapInterval(_vsync ? 1 : 0); + } else if(event.key() == Key::C && event.modifiers() == Modifier::Ctrl) { + Debug{} << "Setting clipboard contents"; + setClipboardText("this text shouldn't have an exclamation at the end!!"_s.exceptSuffix(2)); + } else if(event.key() == Key::V && event.modifiers() == Modifier::Ctrl) { + Debug{} << "Clipboard contents:" << clipboardText(); } else if(event.key() == Key::Esc) { Debug{} << "stopping text input"; stopTextInput(); diff --git a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp index abe3aefd4..3ea758f74 100644 --- a/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp +++ b/src/Magnum/Platform/Test/Sdl2ApplicationTest.cpp @@ -408,10 +408,15 @@ struct Sdl2ApplicationTest: Platform::Application { if(_redraw) redraw(); } #ifndef CORRADE_TARGET_EMSCRIPTEN - else if(event.key() == Key::V) { + else if(event.key() == Key::V && !(event.modifiers() & ~(Modifier::CapsLock|Modifier::NumLock))) { _vsync = !_vsync; Debug{} << "vsync" << (_vsync? "on" : "off"); setSwapInterval(_vsync ? 1 : 0); + } else if(event.key() == Key::C && (event.modifiers() & ~(Modifier::CapsLock|Modifier::NumLock)) == Modifier::Ctrl) { + Debug{} << "Setting clipboard contents"; + setClipboardText("this text shouldn't have an exclamation at the end!!"_s.exceptSuffix(2)); + } else if(event.key() == Key::V && (event.modifiers() & ~(Modifier::CapsLock|Modifier::NumLock)) == Modifier::Ctrl) { + Debug{} << "Clipboard contents:" << clipboardText(); } #endif else if(event.key() == Key::Esc) {