From 978ffc19a8d67db7e8be59e1850b7fe980504762 Mon Sep 17 00:00:00 2001 From: juststeak Date: Sun, 19 Oct 2025 00:26:59 +0300 Subject: [PATCH 1/2] change save folder to driver dir and add reinstall function --- gui/ConfigHelper.cpp | 29 ++++++++- gui/ConfigHelper.h | 3 + gui/main.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) diff --git a/gui/ConfigHelper.cpp b/gui/ConfigHelper.cpp index 52c21d8..1354d7d 100644 --- a/gui/ConfigHelper.cpp +++ b/gui/ConfigHelper.cpp @@ -2,6 +2,12 @@ #include #include #include +#include +#include + +namespace { + std::string repo_root; +} char *OpenFile() { char *filename = new char[512]; @@ -26,12 +32,27 @@ char *OpenFile() { } char *SaveFile() { + static const std::string kDefaultFilename = "config.h"; char *filename = new char[512]; char cwd[1024]; char command[2048] = R"(zenity --save --file-selection --title="Save Config" 2> /dev/null)"; FILE *f = nullptr; - if (getcwd(cwd, sizeof(cwd)) != nullptr) - sprintf(command, R"(zenity --save --file-selection --title="Save Config" --filename="%s/" 2> /dev/null)", cwd); + namespace fs = std::filesystem; + + std::string default_path; + if (!repo_root.empty()) { + fs::path driver_dir = fs::path(repo_root) / "driver"; + if (fs::exists(driver_dir)) + default_path = (driver_dir / kDefaultFilename).string(); + else + default_path = repo_root; + } else if (getcwd(cwd, sizeof(cwd)) != nullptr) + default_path = std::string(cwd) + "/"; + + if (!default_path.empty()) + snprintf(command, sizeof(command), + R"(zenity --save --file-selection --title="Save Config" --confirm-overwrite --filename="%s" 2> /dev/null)", + default_path.c_str()); f = popen(command, "r"); auto res = fgets(filename, 512, f); @@ -47,6 +68,10 @@ char *SaveFile() { } namespace ConfigHelper { + void SetRepoRoot(const std::string &root_path) { + repo_root = root_path; + } + std::string ExportPlainText(Parameters params, bool save_to_file) { std::stringstream res_ss; diff --git a/gui/ConfigHelper.h b/gui/ConfigHelper.h index f838f6a..0a0b705 100644 --- a/gui/ConfigHelper.h +++ b/gui/ConfigHelper.h @@ -2,6 +2,7 @@ #define GUI_CONFIGHELPER_H #include "DriverHelper.h" +#include namespace ConfigHelper { std::string ExportPlainText(Parameters params, bool save_to_file); @@ -11,6 +12,8 @@ namespace ConfigHelper { bool ImportFile(char *lut_data, Parameters ¶ms); bool ImportClipboard(char *lut_data, const char *clipboard, Parameters ¶ms); + + void SetRepoRoot(const std::string &root_path); } // ConfigHelper #endif //GUI_CONFIGHELPER_H diff --git a/gui/main.cpp b/gui/main.cpp index 6b8498a..99c86ed 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -9,6 +9,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "External/ImGui/imgui_internal.h" #include "External/ImGui/implot_internal.h" @@ -41,11 +48,123 @@ bool has_privilege = false; static char LUT_user_data[4096]; void ResetParameters(); +void StartReinstall(); #define RefreshDevices() {devices = DriverHelper::DiscoverDevices(); \ if(selected_device >= devices.size()) \ selected_device = devices.size() - 1;} +enum class ReinstallState { + Idle, + Running, + Succeeded, + Failed +}; + +std::atomic reinstall_state{ReinstallState::Idle}; +std::mutex reinstall_mutex; +std::string reinstall_message; + +std::filesystem::path project_root; + +namespace { + void SetReinstallMessage(const std::string &message) { + std::lock_guard lock(reinstall_mutex); + reinstall_message = message; + } + + std::string ReadReinstallMessage() { + std::lock_guard lock(reinstall_mutex); + return reinstall_message; + } + + std::filesystem::path LocateProjectRoot() { + namespace fs = std::filesystem; + fs::path current = fs::current_path(); + for (int i = 0; i < 6 && !current.empty(); i++) { + if (fs::exists(current / "install.sh") && fs::exists(current / "uninstall.sh")) + return current; + auto parent = current.parent_path(); + if (parent == current) + break; + current = parent; + } + return {}; + } +} // namespace + +void StartReinstall() { + if (reinstall_state.load() == ReinstallState::Running) + return; + + reinstall_state = ReinstallState::Running; + SetReinstallMessage("Starting reinstall..."); + + std::thread([] { + namespace fs = std::filesystem; + try { + fs::path root = project_root.empty() ? LocateProjectRoot() : project_root; + if (root.empty()) { + SetReinstallMessage("Failed to locate install scripts."); + reinstall_state = ReinstallState::Failed; + return; + } + if (project_root.empty()) { + project_root = root; + ConfigHelper::SetRepoRoot(project_root.string()); + } + + auto run_script = [&](const char *script_name) -> bool { + std::ostringstream status; + status << "Running " << script_name << "..."; + SetReinstallMessage(status.str()); + + std::ostringstream command; + command << "cd \"" << root.string() << "\" && sudo ./" << script_name; + int result = std::system(command.str().c_str()); + if (result == -1) { + std::ostringstream error; + error << script_name << " failed to start."; + SetReinstallMessage(error.str()); + return false; + } + + int exit_code = result; + if (WIFEXITED(result)) + exit_code = WEXITSTATUS(result); + else if (WIFSIGNALED(result)) + exit_code = 128 + WTERMSIG(result); + + if (exit_code != 0) { + std::ostringstream error; + error << script_name << " failed (exit code " << exit_code << ")"; + SetReinstallMessage(error.str()); + return false; + } + return true; + }; + + if (!run_script("uninstall.sh")) { + reinstall_state = ReinstallState::Failed; + return; + } + + if (!run_script("install.sh")) { + reinstall_state = ReinstallState::Failed; + return; + } + + SetReinstallMessage("Reinstall completed successfully."); + reinstall_state = ReinstallState::Succeeded; + } catch (const std::exception &ex) { + std::ostringstream oss; + oss << "Reinstall error: " << ex.what(); + SetReinstallMessage(oss.str()); + reinstall_state = ReinstallState::Failed; + } + }).detach(); +} + int OnGui() { using namespace std::chrono; @@ -129,6 +248,20 @@ int OnGui() { } ImGui::EndMenu(); } + if (ImGui::BeginMenu("More")) { + auto current_state = reinstall_state.load(); + bool disable_menu_item = !has_privilege || current_state == ReinstallState::Running; + ImGui::BeginDisabled(disable_menu_item); + if (ImGui::MenuItem("Reinstall driver")) { + StartReinstall(); + } + ImGui::EndDisabled(); + if (!has_privilege) + ImGui::SetItemTooltip("Requires root privileges"); + else if (current_state == ReinstallState::Running) + ImGui::SetItemTooltip("Reinstall already in progress"); + ImGui::EndMenu(); + } ImGui::EndMainMenuBar(); } @@ -934,6 +1067,19 @@ int OnGui() { ImGui::SetItemTooltip("Invalid parameters"); } + auto reinstall_status = reinstall_state.load(); + auto reinstall_text = ReadReinstallMessage(); + if (!reinstall_text.empty() && reinstall_status != ReinstallState::Idle) { + ImVec4 color(0.8f, 0.8f, 0.2f, 1.f); + if (reinstall_status == ReinstallState::Succeeded) + color = ImVec4(0.2f, 0.8f, 0.2f, 1.f); + else if (reinstall_status == ReinstallState::Failed) + color = ImVec4(0.8f, 0.2f, 0.2f, 1.f); + + ImGui::Spacing(); + ImGui::TextColored(color, "%s", reinstall_text.c_str()); + } + ImGui::SetWindowFontScale(1.f); } else ImGui::PopStyleColor(); @@ -1005,6 +1151,10 @@ void ResetParameters(void) { } int main() { + project_root = LocateProjectRoot(); + if (!project_root.empty()) + ConfigHelper::SetRepoRoot(project_root.string()); + GUI::Setup(OnGui); ImPlot::CreateContext(); From 04796c63021fb5a0f62b26df919aa074c937249e Mon Sep 17 00:00:00 2001 From: juststeak Date: Sun, 19 Oct 2025 00:32:38 +0300 Subject: [PATCH 2/2] readme update --- README.org | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index dce6718..14148c2 100644 --- a/README.org +++ b/README.org @@ -27,6 +27,10 @@ Keep in mind that the program needs to be *run with sudo privileges*. To run, simply use =sudo -E ./YeetMouseGui= +*** In-app usage tips + + Use =File -> Export -> Config.h format= to save the currently loaded parameters; the save dialog now opens directly in =driver/= with =config.h= pre-selected. + + When you need to refresh the driver after changing the config, pick =More -> Reinstall driver= to run =uninstall.sh= followed by =install.sh= from the repository. + ** Arch/Manjaro For Arch and Manjaro, a =PKGBUILD= has been written for seamless integration into pacman. @@ -249,4 +253,4 @@ #+END_HTML -**** /More in-depth performance and precision analysis can be found [[Performance.md][here]]/. \ No newline at end of file +**** /More in-depth performance and precision analysis can be found [[Performance.md][here]]/.