From 175c249d29cc62675a0b5da85e14da295c77cea7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 2 Jul 2023 18:04:06 -0700 Subject: [PATCH] support copy/paste from system clipboard --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 14 +++++++++++ library/LuaApi.cpp | 6 +++++ library/include/modules/DFSDL.h | 8 +++++++ library/lua/gui/widgets.lua | 10 ++++++++ library/modules/DFSDL.cpp | 41 +++++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index d10407621..c30d313d5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index d07cb045e..ffd43aea1 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2815,6 +2815,14 @@ and are only documented here for completeness: Returns 0 if the address is not found. Requires a heap snapshot. +* ``dfhack.internal.getClipboardText()`` + + Gets the system clipboard text (converted to CP437 encoding). + +* ``dfhack.internal.setClipboardText(text)`` + + Converts the given text from CP437 to UTF-8 and sets the system clipboard + text. .. _lua-core-context: @@ -4688,6 +4696,12 @@ following keyboard hotkeys: - Ctrl-B/Ctrl-F: move the cursor one word back or forward. - Ctrl-A/Ctrl-E: move the cursor to the beginning/end of the text. +The widget also supports integration with the system clipboard: + +- Ctrl-C: copy current text to the system clipboard +- Ctrl-X: copy current text to the system clipboard and clear text in widget +- Ctrl-V: paste text from the system clipboard (text is converted to cp437) + The ``EditField`` class also provides the following functions: * ``editfield:setCursor([cursor_pos])`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d2c32cf63..13eb01c65 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -47,6 +47,7 @@ distribution. #include "modules/Burrows.h" #include "modules/Constructions.h" #include "modules/Designations.h" +#include "modules/DFSDL.h" #include "modules/Filesystem.h" #include "modules/Gui.h" #include "modules/Items.h" @@ -2999,6 +3000,9 @@ static int msize_address(uintptr_t ptr) return -1; } +static std::string getClipboardText() { return DFSDL::DFSDL_GetClipboardTextCp437(); } +static void setClipboardText(std::string s) { DFSDL::DFSDL_SetClipboardTextCp437(s); } + static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAP(getImageBase), WRAP(getRebaseDelta), @@ -3013,6 +3017,8 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAPN(getAddressSizeInHeap, get_address_size_in_heap), WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object), WRAPN(msizeAddress, msize_address), + WRAP(getClipboardText), + WRAP(setClipboardText), { NULL, NULL } }; diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 626224d60..88dd08f05 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -48,6 +48,14 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); +// System clipboard +DFHACK_EXPORT std::string DFSDL_GetClipboardTextUtf8(); +DFHACK_EXPORT std::string DFSDL_GetClipboardTextCp437(); +DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const char *text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const std::string &text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const char *text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const std::string &text); + } } diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index a58ac228c..8759f97bf 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -772,6 +772,16 @@ function EditField:onInput(keys) elseif keys.CUSTOM_CTRL_E then -- end self:setCursor() return true + elseif keys.CUSTOM_CTRL_C then + dfhack.internal.setClipboardText(self.text) + return true + elseif keys.CUSTOM_CTRL_X then + dfhack.internal.setClipboardText(self.text) + self:setText('') + return true + elseif keys.CUSTOM_CTRL_V then + self:insert(dfhack.internal.getClipboardText()) + return true end -- if we're modal, then unconditionally eat all the input diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 7aa7f36d5..4ed4bc5e8 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -3,8 +3,11 @@ #include "modules/DFSDL.h" #include "Debug.h" +#include "MiscUtils.h" #include "PluginManager.h" +#include + namespace DFHack { DBG_DECLARE(core, dfsdl, DebugCategory::LINFO); } @@ -35,6 +38,10 @@ void (*g_SDL_FreeSurface)(SDL_Surface *) = nullptr; // int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr; // int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr; int (*g_SDL_PushEvent)(SDL_Event *) = nullptr; +SDL_bool (*g_SDL_HasClipboardText)(); +int (*g_SDL_SetClipboardText)(const char *text); +char * (*g_SDL_GetClipboardText)(); +void (*g_SDL_free)(void *); bool DFSDL::init(color_ostream &out) { for (auto &lib_str : SDL_LIBS) { @@ -71,6 +78,10 @@ bool DFSDL::init(color_ostream &out) { // bind(g_sdl_handle, SDL_SemWait); // bind(g_sdl_handle, SDL_SemPost); bind(g_sdl_handle, SDL_PushEvent); + bind(g_sdl_handle, SDL_HasClipboardText); + bind(g_sdl_handle, SDL_SetClipboardText); + bind(g_sdl_handle, SDL_GetClipboardText); + bind(g_sdl_handle, SDL_free); #undef bind DEBUG(dfsdl,out).print("sdl successfully loaded\n"); @@ -124,3 +135,33 @@ void DFSDL::DFSDL_FreeSurface(SDL_Surface *surface) { int DFSDL::DFSDL_PushEvent(SDL_Event *event) { return g_SDL_PushEvent(event); } + +std::string DFSDL::DFSDL_GetClipboardTextUtf8() { + if (g_SDL_HasClipboardText() != SDL_TRUE) + return ""; + char *text = g_SDL_GetClipboardText(); + std::string ret = text; + g_SDL_free(text); + return ret; +} + +std::string DFSDL::DFSDL_GetClipboardTextCp437() { + std::string utf8text = DFSDL_GetClipboardTextUtf8(); + return UTF2DF(utf8text); +} + +bool DFSDL::DFSDL_SetClipboardTextUtf8(const char *text) { + return g_SDL_SetClipboardText(text) == 0; +} + +bool DFSDL::DFSDL_SetClipboardTextUtf8(const std::string &text) { + return DFSDL_SetClipboardTextUtf8(text.c_str()); +} + +bool DFSDL::DFSDL_SetClipboardTextCp437(const char *text) { + return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); +} + +bool DFSDL::DFSDL_SetClipboardTextCp437(const std::string &text) { + return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); +}