From 96ef758bbd31c36e4546e30720b6ad1b4b2c415c Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 29 May 2025 19:56:46 +0200 Subject: [PATCH] impr: Added clip library to improve clipboard situation --- .gitmodules | 3 + cmake/build_helpers.cmake | 9 ++ lib/libimhex/CMakeLists.txt | 4 +- .../include/hex/helpers/clipboard.hpp | 16 ++++ lib/libimhex/source/helpers/clipboard.cpp | 91 +++++++++++++++++++ lib/third_party/clip | 1 + main/gui/source/window/win_window.cpp | 5 +- .../content/views/view_data_inspector.cpp | 9 +- .../source/content/views/view_find.cpp | 5 +- .../source/content/views/view_hex_editor.cpp | 36 ++------ .../source/content/views/view_yara.cpp | 3 +- 11 files changed, 146 insertions(+), 36 deletions(-) create mode 100644 lib/libimhex/include/hex/helpers/clipboard.hpp create mode 100644 lib/libimhex/source/helpers/clipboard.cpp create mode 160000 lib/third_party/clip diff --git a/.gitmodules b/.gitmodules index 0b72b16ad..810777a5a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,3 +47,6 @@ [submodule "lib/external/disassembler"] path = lib/external/disassembler url = https://github.com/WerWolv/Disassembler +[submodule "lib/third_party/clip"] + path = lib/third_party/clip + url = https://github.com/dacap/clip diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index f3f88ca6b..2a9dbabd5 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -761,6 +761,15 @@ macro(addBundledLibraries) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL) + set(CLIP_ENABLE_IMAGE OFF CACHE BOOL "") + set(CLIP_EXAMPLES OFF CACHE BOOL "") + set(CLIP_TESTS OFF CACHE BOOL "") + set(CLIP_INSTALL OFF CACHE BOOL "") + set(CLIP_X11_WITH_PNG OFF CACHE BOOL "") + set(CLIP_SUPPORT_WINXP OFF CACHE BOOL "") + add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/clip EXCLUDE_FROM_ALL) + target_include_directories(clip INTERFACE $) + add_subdirectory(${EXTERNAL_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL) set(XDGPP_INCLUDE_DIRS "${THIRD_PARTY_LIBS_FOLDER}/xdgpp") diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 0168a9d79..00d7347b1 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -42,6 +42,7 @@ set(LIBIMHEX_SOURCES source/helpers/keys.cpp source/helpers/freetype.cpp source/helpers/udp_server.cpp + source/helpers/clipboard.cpp source/test/tests.cpp @@ -160,8 +161,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD) endif() if (NOT EMSCRIPTEN) - # curl is only used in non-emscripten builds - target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl) + target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl clip) endif() target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_INCLUDE_DIR} ${LIBBACKTRACE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS}) diff --git a/lib/libimhex/include/hex/helpers/clipboard.hpp b/lib/libimhex/include/hex/helpers/clipboard.hpp new file mode 100644 index 000000000..8f8c3db28 --- /dev/null +++ b/lib/libimhex/include/hex/helpers/clipboard.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include +#include + +namespace hex::clipboard { + + void init(); + void setBinaryData(std::span data); + [[nodiscard]] std::vector getBinaryData(); + void setTextData(const std::string &string); + [[nodiscard]] std::string getTextData(); + +} diff --git a/lib/libimhex/source/helpers/clipboard.cpp b/lib/libimhex/source/helpers/clipboard.cpp new file mode 100644 index 000000000..7b522333c --- /dev/null +++ b/lib/libimhex/source/helpers/clipboard.cpp @@ -0,0 +1,91 @@ +#include + +#if __has_include() + #define CLIP_LIBRARY +#endif + +#if defined(CLIP_LIBRARY) + #include +#else + #include + #include + #include +#endif + +namespace hex::clipboard { + +#if defined(CLIP_LIBRARY) + + static clip::format s_binaryFormat; + static clip::format s_textFormat; + + void init() { + s_binaryFormat = clip::register_format("net.werwolv.imhex.binary"); + s_textFormat = clip::text_format(); + } + + void setBinaryData(std::span data) { + clip::lock l; + l.set_data(s_binaryFormat, reinterpret_cast(data.data()), data.size()); + } + + std::vector getBinaryData() { + clip::lock l; + + const auto size = l.get_data_length(s_binaryFormat); + std::vector data(size); + l.get_data(s_binaryFormat, reinterpret_cast(data.data()), size); + + return data; + } + + void setTextData(const std::string &string) { + clip::lock l; + l.set_data(s_textFormat, string.data(), string.size()); + } + + std::string getTextData() { + clip::lock l; + + const auto size = l.get_data_length(s_binaryFormat); + std::string data(size, 0x00); + l.get_data(s_textFormat, data.data(), size); + + return data; + } + +#else + + void init() {} + + void setBinaryData(std::span data) { + constexpr static auto Format = "{0:02X} "; + std::string result; + result.reserve(fmt::format(Format, 0x00).size() * data.size_bytes()); + + for (const auto &byte : data) + result += fmt::format(Format, byte); + result.pop_back(); + + ImGui::SetClipboardText(result.c_str()); + } + + std::vector getBinaryData() { + auto clipboard = ImGui::GetClipboardText(); + if (clipboard == nullptr) + return {}; + + return parseHexString(clipboard); + } + + void setTextData(const std::string &string) { + ImGui::SetClipboardText(string.c_str()); + } + + std::string getTextData() { + return ImGui::GetClipboardText(); + } + +#endif + +} diff --git a/lib/third_party/clip b/lib/third_party/clip new file mode 160000 index 000000000..7a60eabaa --- /dev/null +++ b/lib/third_party/clip @@ -0,0 +1 @@ +Subproject commit 7a60eabaad167d9dc91eae439cb2c1ab9d49c6ba diff --git a/main/gui/source/window/win_window.cpp b/main/gui/source/window/win_window.cpp index 0f91ed815..4d4d1ff4c 100644 --- a/main/gui/source/window/win_window.cpp +++ b/main/gui/source/window/win_window.cpp @@ -35,8 +35,9 @@ #include #include #include +#include - #if !defined(STDIN_FILENO) +#if !defined(STDIN_FILENO) #define STDIN_FILENO 0 #endif @@ -422,6 +423,8 @@ namespace hex { } enumerateFonts(); + + clipboard::init(); } class DropManager : public IDropTarget { diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index e5f9746c6..bf24cb6e0 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -17,6 +17,7 @@ #include #include +#include namespace hex::plugin::builtin { @@ -279,7 +280,7 @@ namespace hex::plugin::builtin { const auto providerSize = m_selectedProvider->getActualSize(); const auto providerEndAddress = baseAddress + providerSize; - ImGui::BeginDisabled(providerSize < requiredSize || selection->getStartAddress() < baseAddress + requiredSize); + ImGui::BeginDisabled(providerSize < requiredSize || (selection.has_value() && selection->getStartAddress() < baseAddress + requiredSize)); if (ImGuiExt::DimmedIconButton(ICON_VS_ARROW_LEFT, ImGui::GetStyleColorVec4(ImGuiCol_Text), buttonSize)) { ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress() - requiredSize, requiredSize }); } @@ -287,7 +288,7 @@ namespace hex::plugin::builtin { ImGui::SameLine(); - ImGui::BeginDisabled(providerSize < requiredSize || selection->getEndAddress() > providerEndAddress - requiredSize); + ImGui::BeginDisabled(providerSize < requiredSize || (selection.has_value() && selection->getEndAddress() > providerEndAddress - requiredSize)); if (ImGuiExt::DimmedIconButton(ICON_VS_ARROW_RIGHT, ImGui::GetStyleColorVec4(ImGuiCol_Text), buttonSize)) { ImHexApi::HexEditor::setSelection(Region { selection->getStartAddress() + requiredSize, requiredSize }); } @@ -436,7 +437,7 @@ namespace hex::plugin::builtin { if (ImGui::BeginPopup("##DataInspectorRowContextMenu")) { if (ImGui::MenuItemEx("hex.builtin.view.data_inspector.menu.copy"_lang, ICON_VS_COPY)) { - ImGui::SetClipboardText(copyValue.c_str()); + clipboard::setTextData(copyValue); } if (ImGui::MenuItemEx("hex.builtin.view.data_inspector.menu.edit"_lang, ICON_VS_EDIT, nullptr, false, editable)) { entry.editing = true; @@ -593,4 +594,4 @@ namespace hex::plugin::builtin { } -} \ No newline at end of file +} diff --git a/plugins/builtin/source/content/views/view_find.cpp b/plugins/builtin/source/content/views/view_find.cpp index 324ff8735..f83c47b3f 100644 --- a/plugins/builtin/source/content/views/view_find.cpp +++ b/plugins/builtin/source/content/views/view_find.cpp @@ -15,6 +15,7 @@ #include #include +#include namespace hex::plugin::builtin { @@ -648,9 +649,9 @@ namespace hex::plugin::builtin { if (ImGui::BeginPopup("FindContextMenu")) { if (ImGui::MenuItemEx("hex.builtin.view.find.context.copy"_lang, ICON_VS_COPY)) - ImGui::SetClipboardText(value.c_str()); + clipboard::setTextData(value); if (ImGui::MenuItemEx("hex.builtin.view.find.context.copy_demangle"_lang, ICON_VS_FILES)) - ImGui::SetClipboardText(hex::plugin::builtin::demangle(value).c_str()); + clipboard::setTextData(hex::plugin::builtin::demangle(value)); if (ImGui::BeginMenuEx("hex.builtin.view.find.context.replace"_lang, ICON_VS_REPLACE)) { if (ImGui::BeginTabBar("##replace_tabs")) { if (ImGui::BeginTabItem("hex.builtin.view.find.context.replace.hex"_lang)) { diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index 73232a0f8..0944085fe 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -744,7 +745,7 @@ namespace hex::plugin::builtin { } static void copyBytes(const Region &selection) { - constexpr static auto Format = "{0:02X} "; + //constexpr static auto Format = "{0:02X} "; auto provider = ImHexApi::Provider::get(); if (provider == nullptr) @@ -754,33 +755,16 @@ namespace hex::plugin::builtin { reader.seek(selection.getStartAddress()); reader.setEndAddress(selection.getEndAddress()); - std::string result; - result.reserve(fmt::format(Format, 0x00).size() * selection.getSize()); - - for (const auto &byte : reader) - result += fmt::format(Format, byte); - result.pop_back(); - - ImGui::SetClipboardText(result.c_str()); + auto bytes = std::vector(reader.begin(), reader.end()); + clipboard::setBinaryData(bytes); } - static void pasteBytes(const Region &selection, bool selectionCheck, bool asPlainText) { + static void pasteBytes(const Region &selection, bool selectionCheck, bool) { auto provider = ImHexApi::Provider::get(); if (provider == nullptr) return; - auto clipboard = ImGui::GetClipboardText(); - if (clipboard == nullptr) - return; - - std::vector buffer; - if (asPlainText) { - // Directly reinterpret clipboard as an array of bytes - std::string cp = clipboard; - buffer = std::vector(cp.begin(), cp.end()); - } - else - buffer = parseHexString(clipboard); + auto buffer = clipboard::getBinaryData(); if (!selectionCheck) { if (selection.getStartAddress() + buffer.size() >= provider->getActualSize()) @@ -831,7 +815,7 @@ namespace hex::plugin::builtin { buffer.reserve(selection.size); provider->read(selection.getStartAddress(), buffer.data(), selection.size); - ImGui::SetClipboardText(buffer.c_str()); + clipboard::setTextData(buffer); } static void copyCustomEncoding(const EncodingFile &customEncoding, const Region &selection) { @@ -851,7 +835,7 @@ namespace hex::plugin::builtin { offset += size; } - ImGui::SetClipboardText(string.c_str()); + clipboard::setTextData(string); } void ViewHexEditor::registerShortcuts() { @@ -1264,7 +1248,7 @@ namespace hex::plugin::builtin { [] { auto selection = ImHexApi::HexEditor::getSelection(); if (selection.has_value() && selection != Region::Invalid()) - ImGui::SetClipboardText(hex::format("0x{:08X}", selection->getStartAddress()).c_str()); + clipboard::setTextData(hex::format("0x{:08X}", selection->getStartAddress())); }, ImHexApi::HexEditor::isSelectionValid); @@ -1291,7 +1275,7 @@ namespace hex::plugin::builtin { bool enabled = ImHexApi::HexEditor::isSelectionValid(); for (const auto &[unlocalizedName, callback] : ContentRegistry::DataFormatter::impl::getExportMenuEntries()) { if (menu::menuItem(Lang(unlocalizedName), Shortcut::None, false, enabled)) { - ImGui::SetClipboardText( + clipboard::setTextData( callback( provider, selection->getStartAddress(), diff --git a/plugins/yara_rules/source/content/views/view_yara.cpp b/plugins/yara_rules/source/content/views/view_yara.cpp index 94c9446f1..de1f843ef 100644 --- a/plugins/yara_rules/source/content/views/view_yara.cpp +++ b/plugins/yara_rules/source/content/views/view_yara.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -231,7 +232,7 @@ namespace hex::plugin::yara { const auto &message = m_consoleMessages->at(i); if (ImGui::Selectable(message.c_str())) - ImGui::SetClipboardText(message.c_str()); + clipboard::setTextData(message); } } }