diff --git a/sdk/include/mods/svc/ui.h b/sdk/include/mods/svc/ui.h index 5dd9066421..4549aa53fc 100644 --- a/sdk/include/mods/svc/ui.h +++ b/sdk/include/mods/svc/ui.h @@ -9,7 +9,7 @@ #define UI_SERVICE_ID "dev.twilitrealm.dusklight.ui" #define UI_SERVICE_MAJOR 1u -#define UI_SERVICE_MINOR 1u +#define UI_SERVICE_MINOR 2u /* * UI primitives: a panel inside the host Mods window, mod-owned windows, dialogs, toasts, @@ -291,6 +291,10 @@ typedef struct UiService { /* Enqueue a toast notification. */ ModResult (*push_toast)(ModContext* ctx, const UiToastDesc* desc); + + /* Minor version 2 */ + ModResult (*get_clipboard_text)(ModContext* ctx, char* out_text, size_t max_length); + ModResult (*set_clipboard_text)(ModContext* ctx, const char* text); } UiService; MOD_DECLARE_SERVICE(UiService, svc_ui, UI_SERVICE_ID, UI_SERVICE_MAJOR, UI_SERVICE_MINOR); diff --git a/src/dusk/mods/svc/ui.cpp b/src/dusk/mods/svc/ui.cpp index b47959a930..41a70100e7 100644 --- a/src/dusk/mods/svc/ui.cpp +++ b/src/dusk/mods/svc/ui.cpp @@ -29,6 +29,8 @@ #include #include +#include "SDL3/SDL_clipboard.h" + namespace dusk::mods::svc::ui_impl { namespace { @@ -1037,6 +1039,31 @@ void ui_remove_mod(LoadedMod& mod) { } } +ModResult ui_get_clipboard_text(LoadedMod& mod, char* out_text, size_t max_length) { + if (SDL_HasClipboardText()) { + std::string text = SDL_GetClipboardText(); + if (text.empty()) { + return MOD_ERROR; + } + + if (text.size() > max_length - 1) { + text.resize(max_length - 1); + } + + memcpy(out_text, text.c_str(), text.size()); + out_text[text.size()] = '\0'; + } + + return MOD_OK; +} + +ModResult ui_set_clipboard_text(LoadedMod& mod, const char* text) { + if (!SDL_SetClipboardText(text)) { + return MOD_ERROR; + } + return MOD_OK; +} + } // namespace dusk::mods::svc::ui_impl namespace dusk::mods::svc { @@ -1368,6 +1395,23 @@ ModResult ui_dialog_add_action( return ui_impl::ui_dialog_add_action(*mod, dialog, *action); } +ModResult ui_get_clipboard_text(ModContext* ctx, char* out_text, size_t max_length) { + auto* mod = mod_from_context(ctx); + if (mod == nullptr || out_text == nullptr || max_length == 0) { + return MOD_INVALID_ARGUMENT; + } + + return ui_impl::ui_get_clipboard_text(*mod, out_text, max_length); +} + +ModResult ui_set_clipboard_text(ModContext* ctx, const char* text) { + auto* mod = mod_from_context(ctx); + if (mod == nullptr || text == nullptr) { + return MOD_INVALID_ARGUMENT; + } + return ui_impl::ui_set_clipboard_text(*mod, text); +} + constexpr UiService s_uiService{ .header = SERVICE_HEADER(UiService, UI_SERVICE_MAJOR, UI_SERVICE_MINOR), .register_mods_panel = ui_register_mods_panel, @@ -1394,6 +1438,8 @@ constexpr UiService s_uiService{ .register_menu_tab = ui_register_menu_tab, .unregister_menu_tab = ui_unregister_menu_tab, .push_toast = ui_push_toast, + .get_clipboard_text = ui_get_clipboard_text, + .set_clipboard_text = ui_set_clipboard_text, }; } // namespace