diff --git a/include/views/view.hpp b/include/views/view.hpp index ed52e20c4..7037782c5 100644 --- a/include/views/view.hpp +++ b/include/views/view.hpp @@ -6,6 +6,10 @@ #include "event.hpp" +#include +#include + + namespace hex { class View { @@ -17,6 +21,10 @@ namespace hex { virtual void createMenu() { } virtual bool handleShortcut(int key, int mods) { return false; } + static std::vector>& getDeferedCalls() { + return View::s_deferedCalls; + } + protected: void subscribeEvent(Events eventType, std::function callback) { View::s_eventManager.subscribe(eventType, this, callback); @@ -30,8 +38,13 @@ namespace hex { View::s_eventManager.post(eventType, userData); } + void doLater(std::function &&function) { + View::s_deferedCalls.push_back(function); + } + private: static inline EventManager s_eventManager; + static inline std::vector> s_deferedCalls; }; } \ No newline at end of file diff --git a/include/views/view_hexeditor.hpp b/include/views/view_hexeditor.hpp index 80908e488..aaa07b7fd 100644 --- a/include/views/view_hexeditor.hpp +++ b/include/views/view_hexeditor.hpp @@ -51,6 +51,9 @@ namespace hex { void drawSearchPopup(); void drawGotoPopup(); + void copyBytes(); + void copyString(); + }; } \ No newline at end of file diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index a8d6d48f6..28ba45fb8 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -83,14 +83,60 @@ namespace hex { } + void ViewHexEditor::copyBytes() { + size_t copySize = (this->m_memoryEditor.DataPreviewAddrEnd - this->m_memoryEditor.DataPreviewAddr) + 1; + + std::vector buffer(copySize, 0x00); + this->m_dataProvider->read(this->m_memoryEditor.DataPreviewAddr, buffer.data(), buffer.size()); + + std::string str; + for (const auto &byte : buffer) + str += hex::format("%x ", byte); + str.pop_back(); + + ImGui::SetClipboardText(str.c_str()); + } + + void ViewHexEditor::copyString() { + size_t copySize = (this->m_memoryEditor.DataPreviewAddrEnd - this->m_memoryEditor.DataPreviewAddr) + 1; + + std::string buffer; + buffer.reserve(copySize + 1); + this->m_dataProvider->read(this->m_memoryEditor.DataPreviewAddr, buffer.data(), copySize); + + ImGui::SetClipboardText(buffer.c_str()); + } + void ViewHexEditor::createMenu() { if (ImGui::BeginMenu("File")) { - if (ImGui::MenuItem("Open File...")) { + if (ImGui::MenuItem("Open File...", "CTRL + O")) { this->m_fileBrowser.SetTitle("Open File"); this->m_fileBrowser.Open(); } + ImGui::Separator(); + + if (ImGui::MenuItem("Search", "CTRL + F")) { + View::doLater([]{ ImGui::OpenPopup("Search"); }); + } + + if (ImGui::MenuItem("Goto", "CTRL + G")) { + View::doLater([]{ ImGui::OpenPopup("Goto"); }); + } + + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Edit")) { + if (ImGui::MenuItem("Copy bytes", "CTRL + ALT + C")) { + this->copyBytes(); + } + + if (ImGui::MenuItem("Copy string", "CTRL + SHIFT + C")) { + this->copyString(); + } + ImGui::EndMenu(); } @@ -101,12 +147,22 @@ namespace hex { } bool ViewHexEditor::handleShortcut(int key, int mods) { - if (mods & GLFW_MOD_CONTROL && key == GLFW_KEY_F) { + if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_F) { ImGui::OpenPopup("Search"); return true; - } else if (mods & GLFW_MOD_CONTROL && key == GLFW_KEY_G) { + } else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_G) { ImGui::OpenPopup("Goto"); return true; + } else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_O) { + this->m_fileBrowser.SetTitle("Open File"); + this->m_fileBrowser.Open(); + return true; + } else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_ALT) && key == GLFW_KEY_C) { + this->copyBytes(); + return true; + } else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == GLFW_KEY_C) { + this->copyString(); + return true; } return false; diff --git a/source/window.cpp b/source/window.cpp index b51ba23f2..127f405d1 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -67,6 +67,10 @@ namespace hex { while (!glfwWindowShouldClose(this->m_window)) { this->frameBegin(); + for (const auto &call : View::getDeferedCalls()) + call(); + View::getDeferedCalls().clear(); + for (auto &view : this->m_views) { view->createView(); }