From b3adb3f69d0a7f1d9e00dcc087388d4df80b14fa Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 24 Feb 2025 04:37:34 +0000 Subject: [PATCH] Ctrl+Q Shortcut and confirm on quit if search/scratchpad active --- CHANGELOG.md | 3 ++- src/gui/backend.c | 19 ++++++++++++++++++- src/gui/gui.h | 1 + src/gui/window.c | 31 ++++++++++++++++++++++++++----- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9eb9fb3..024c6eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### Added: - Drag click to select items in address list and scratchpad -- Confirm dialog box when detaching process with an active search or addresses in scratchpad +- Confirm dialog box when detaching process / closing MemSed with an active search or addresses in scratchpad - Close popups with X buttons, pressing Escape, and clicking outside th popup - Good amount of keyboard shortcuts allowing for almost keyboard-only usage, for example: - Ctrl+O to open process select @@ -11,6 +11,7 @@ - Ctrl+Enter to search - Ctrl+Space to stop Search, Ctrl+Z to undo/reset search - Ctrl+D to Detach process + - Ctrl+Q to Quit MemSed ### Updated: - Use custom `thread_cancel()` implementation that is more portable and works with `-fexceptions` diff --git a/src/gui/backend.c b/src/gui/backend.c index 1302a2c..83f25c4 100644 --- a/src/gui/backend.c +++ b/src/gui/backend.c @@ -75,6 +75,7 @@ bool gui_backend_init(Gui* gui, const char* title, uint32_t width, uint32_t heig void gui_backend_process_events(Gui* gui) { SDL_Event event; + bool requested_close = false; while(SDL_PollEvent(&event)) { if(event.type == SDL_EVENT_MOUSE_WHEEL && event.window.windowID == SDL_GetWindowID(gui->window)) { @@ -94,12 +95,28 @@ void gui_backend_process_events(Gui* gui) { ImGui_ImplSDL3_ProcessEvent(&event); } + // QUIT is sent after WINDOW_CLOSE_REQUESTED for window closing + // Only QUIT is sent when trying to terminate the process + // For terminating process, close right away + // For window close, register request and handle later if(event.type == SDL_EVENT_QUIT) { - gui->should_close = true; + if(!requested_close) { + gui->should_close = true; + } } if(event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(gui->window)) { + requested_close = true; + } + } + + // If window close was requested, save it and handle in draw in case confirmation is needed + // If requested a second time, just close anyway + if(requested_close) { + if(gui->requested_close) { gui->should_close = true; + } else { + gui->requested_close = true; } } } diff --git a/src/gui/gui.h b/src/gui/gui.h index 7065a95..bee45c0 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -19,6 +19,7 @@ typedef struct { } fonts; ImVec2 prev_size; ImVec2 scroll_energy; + bool requested_close; bool should_close; MemorySearch* memory_search; diff --git a/src/gui/window.c b/src/gui/window.c index 40fa50e..ffe5321 100644 --- a/src/gui/window.c +++ b/src/gui/window.c @@ -5,6 +5,7 @@ const char* ok = mdi_check " Ok"; const char* cancel = mdi_cancel " Cancel"; const char* attach_process = mdi_application_import " Attach Process"; const char* detach_process = mdi_exit_run " Detach Process"; +const char* quit_memsed = mdi_exit_run " Quit Memsed"; const char* add_to_scratchpad = mdi_plus_box_multiple " Add to Scratchpad"; const char* remove_from_scratchpad = mdi_minus_box_multiple " Remove from Scratchpad"; const char* first_search = mdi_magnify_plus " First Search"; @@ -163,7 +164,7 @@ static void gui_window_draw_attach_process_popup(Gui* gui) { } } -static void gui_window_draw_detach_process_popup(Gui* gui) { +static void gui_window_draw_detach_process_popup(Gui* gui, const char* type) { ImVec2 display = gui->io->DisplaySize; ImGui_SetNextWindowPosEx( (ImVec2){display.x / 2.0f, display.y / 2.0f}, @@ -171,11 +172,13 @@ static void gui_window_draw_detach_process_popup(Gui* gui) { (ImVec2){0.5f, 0.5f}); bool popup_still_open = true; if(ImGui_BeginPopupModal( - detach_process, + type, &popup_still_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize)) { - ImGui_TextUnformatted("Are you sure you want to detach from the process?"); + ImGui_Text( + "Are you sure you want to %s?", + type == quit_memsed ? "quit MemSed" : "detach from the process"); bool has_active_search = memory_search_get_results(gui->memory_search)->batches_count > 0; bool has_scratchpad_items = memory_search_get_scratchpad(gui->memory_search)->items_count > 0; @@ -190,12 +193,19 @@ static void gui_window_draw_detach_process_popup(Gui* gui) { ImGui_SetKeyboardFocusHere(); } if(ImGui_Button(ok)) { - memory_search_process_detach(gui->memory_search); + if(type == quit_memsed) { + gui->should_close = true; + } else { + memory_search_process_detach(gui->memory_search); + } ImGui_CloseCurrentPopup(); } ImGui_SameLine(); if(ImGui_Button(cancel) || !popup_still_open || imgui_should_close_weak_modal()) { + if(type == quit_memsed) { + gui->requested_close = false; + } ImGui_CloseCurrentPopup(); } @@ -217,7 +227,7 @@ static void gui_window_draw_toolbar(Gui* gui) { memory_search_process_detach(gui->memory_search); } } - gui_window_draw_detach_process_popup(gui); + gui_window_draw_detach_process_popup(gui, detach_process); } else { flt32_t width = ImGui_CalcTextSize(detach_process).x + gui->style->FramePadding.x * 2; ImGui_SetNextItemShortcut( @@ -1184,6 +1194,17 @@ void gui_window_draw(Gui* gui) { ImGuiWindowFlags_NoScrollWithMouse); ImGui_PopStyleVar(); + if(ImGui_Shortcut(ImGuiMod_Ctrl | ImGuiKey_Q, ImGuiInputFlags_RouteGlobal) || + gui->requested_close) { + if(memory_search_get_results(gui->memory_search)->batches_count > 0 || + memory_search_get_scratchpad(gui->memory_search)->items_count > 0) { + ImGui_OpenPopup(quit_memsed, ImGuiPopupFlags_None); + } else { + gui->should_close = true; + } + } + gui_window_draw_detach_process_popup(gui, quit_memsed); + // Toolbar gui_window_draw_toolbar(gui);