Merge pull request #3524 from myk002/myk_copypaste

support copy/paste from system clipboard
develop
Myk 2023-07-05 23:09:08 -07:00 committed by GitHub
commit 79dbcf0461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 7 deletions

@ -39,6 +39,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing
## Misc Improvements ## Misc Improvements
- ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V
## Documentation ## Documentation

@ -2832,6 +2832,13 @@ and are only documented here for completeness:
Returns 0 if the address is not found. Returns 0 if the address is not found.
Requires a heap snapshot. Requires a heap snapshot.
* ``dfhack.internal.getClipboardTextCp437()``
Gets the system clipboard text (and converts text to CP437 encoding).
* ``dfhack.internal.setClipboardTextCp437(text)``
Sets the system clipboard text from a CP437 string.
.. _lua-core-context: .. _lua-core-context:
@ -4705,6 +4712,12 @@ following keyboard hotkeys:
- Ctrl-B/Ctrl-F: move the cursor one word back or forward. - 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. - 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: The ``EditField`` class also provides the following functions:
* ``editfield:setCursor([cursor_pos])`` * ``editfield:setCursor([cursor_pos])``

@ -3039,6 +3039,8 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = {
WRAPN(getAddressSizeInHeap, get_address_size_in_heap), WRAPN(getAddressSizeInHeap, get_address_size_in_heap),
WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object), WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object),
WRAPN(msizeAddress, msize_address), WRAPN(msizeAddress, msize_address),
WRAP(getClipboardTextCp437),
WRAP(setClipboardTextCp437),
{ NULL, NULL } { NULL, NULL }
}; };

@ -27,6 +27,8 @@ distribution.
#include "MiscUtils.h" #include "MiscUtils.h"
#include "ColorText.h" #include "ColorText.h"
#include "modules/DFSDL.h"
#ifndef LINUX_BUILD #ifndef LINUX_BUILD
// We don't want min and max macros // We don't want min and max macros
#define NOMINMAX #define NOMINMAX

@ -47,7 +47,17 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface);
// DFHACK_EXPORT int DFSDL_SemWait(SDL_sem *sem); // DFHACK_EXPORT int DFSDL_SemWait(SDL_sem *sem);
// DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem);
DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event);
DFHACK_EXPORT void DFSDL_free(void *ptr);
// submitted and returned text is UTF-8
// see wrapper functions below for cp-437 variants
DFHACK_EXPORT char * DFSDL_GetClipboardText();
DFHACK_EXPORT int DFSDL_SetClipboardText(const char *text);
} }
// System clipboard -- submitted and returned text must be in CP437
DFHACK_EXPORT std::string getClipboardTextCp437();
DFHACK_EXPORT bool setClipboardTextCp437(std::string text);
} }

@ -640,8 +640,12 @@ function EditField:setCursor(cursor)
end end
function EditField:setText(text, cursor) function EditField:setText(text, cursor)
local old = self.text
self.text = text self.text = text
self:setCursor(cursor) self:setCursor(cursor)
if self.on_change and text ~= old then
self.on_change(self.text, old)
end
end end
function EditField:postUpdateLayout() function EditField:postUpdateLayout()
@ -699,11 +703,7 @@ function EditField:onInput(keys)
end end
if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then
local old = self.text
self:setText(self.saved_text) self:setText(self.saved_text)
if self.on_change and old ~= self.saved_text then
self.on_change(self.text, old)
end
self:setFocus(false) self:setFocus(false)
return true return true
end end
@ -747,9 +747,6 @@ function EditField:onInput(keys)
return self.modal return self.modal
end end
end end
if self.on_change and self.text ~= old then
self.on_change(self.text, old)
end
return true return true
elseif keys.KEYBOARD_CURSOR_LEFT then elseif keys.KEYBOARD_CURSOR_LEFT then
self:setCursor(self.cursor - 1) self:setCursor(self.cursor - 1)
@ -772,6 +769,16 @@ function EditField:onInput(keys)
elseif keys.CUSTOM_CTRL_E then -- end elseif keys.CUSTOM_CTRL_E then -- end
self:setCursor() self:setCursor()
return true return true
elseif keys.CUSTOM_CTRL_C then
dfhack.internal.setClipboardTextCp437(self.text)
return true
elseif keys.CUSTOM_CTRL_X then
dfhack.internal.setClipboardTextCp437(self.text)
self:setText('')
return true
elseif keys.CUSTOM_CTRL_V then
self:insert(dfhack.internal.getClipboardTextCp437())
return true
end end
-- if we're modal, then unconditionally eat all the input -- if we're modal, then unconditionally eat all the input

@ -5,6 +5,8 @@
#include "Debug.h" #include "Debug.h"
#include "PluginManager.h" #include "PluginManager.h"
#include <SDL_stdinc.h>
namespace DFHack { namespace DFHack {
DBG_DECLARE(core, dfsdl, DebugCategory::LINFO); DBG_DECLARE(core, dfsdl, DebugCategory::LINFO);
} }
@ -35,6 +37,10 @@ void (*g_SDL_FreeSurface)(SDL_Surface *) = nullptr;
// int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr; // int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr;
// int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr; // int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr;
int (*g_SDL_PushEvent)(SDL_Event *) = 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) { bool DFSDL::init(color_ostream &out) {
for (auto &lib_str : SDL_LIBS) { for (auto &lib_str : SDL_LIBS) {
@ -71,6 +77,10 @@ bool DFSDL::init(color_ostream &out) {
// bind(g_sdl_handle, SDL_SemWait); // bind(g_sdl_handle, SDL_SemWait);
// bind(g_sdl_handle, SDL_SemPost); // bind(g_sdl_handle, SDL_SemPost);
bind(g_sdl_handle, SDL_PushEvent); 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 #undef bind
DEBUG(dfsdl,out).print("sdl successfully loaded\n"); DEBUG(dfsdl,out).print("sdl successfully loaded\n");
@ -124,3 +134,30 @@ void DFSDL::DFSDL_FreeSurface(SDL_Surface *surface) {
int DFSDL::DFSDL_PushEvent(SDL_Event *event) { int DFSDL::DFSDL_PushEvent(SDL_Event *event) {
return g_SDL_PushEvent(event); return g_SDL_PushEvent(event);
} }
void DFSDL::DFSDL_free(void *ptr) {
g_SDL_free(ptr);
}
char * DFSDL::DFSDL_GetClipboardText() {
return g_SDL_GetClipboardText();
}
int DFSDL::DFSDL_SetClipboardText(const char *text) {
return g_SDL_SetClipboardText(text);
}
DFHACK_EXPORT std::string DFHack::getClipboardTextCp437() {
if (!g_sdl_handle || g_SDL_HasClipboardText() != SDL_TRUE)
return "";
char *text = g_SDL_GetClipboardText();
std::string textcp437 = UTF2DF(text);
DFHack::DFSDL::DFSDL_free(text);
return textcp437;
}
DFHACK_EXPORT bool DFHack::setClipboardTextCp437(std::string text) {
if (!g_sdl_handle)
return false;
return 0 == DFHack::DFSDL::DFSDL_SetClipboardText(DF2UTF(text).c_str());
}