Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -249,4 +253,4 @@
</tbody></table>
#+END_HTML

**** /More in-depth performance and precision analysis can be found [[Performance.md][here]]/.
**** /More in-depth performance and precision analysis can be found [[Performance.md][here]]/.
29 changes: 27 additions & 2 deletions gui/ConfigHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
#include <fstream>
#include <optional>
#include <unistd.h>
#include <filesystem>
#include <cstdio>

namespace {
std::string repo_root;
}

char *OpenFile() {
char *filename = new char[512];
Expand All @@ -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);
Expand All @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions gui/ConfigHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GUI_CONFIGHELPER_H

#include "DriverHelper.h"
#include <string>

namespace ConfigHelper {
std::string ExportPlainText(Parameters params, bool save_to_file);
Expand All @@ -11,6 +12,8 @@ namespace ConfigHelper {
bool ImportFile(char *lut_data, Parameters &params);

bool ImportClipboard(char *lut_data, const char *clipboard, Parameters &params);

void SetRepoRoot(const std::string &root_path);
} // ConfigHelper

#endif //GUI_CONFIGHELPER_H
150 changes: 150 additions & 0 deletions gui/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
#include <chrono>
#include <vector>
#include <unistd.h>
#include <atomic>
#include <thread>
#include <mutex>
#include <filesystem>
#include <sstream>
#include <cstdlib>
#include <sys/wait.h>

#include "External/ImGui/imgui_internal.h"
#include "External/ImGui/implot_internal.h"
Expand Down Expand Up @@ -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<ReinstallState> 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<std::mutex> lock(reinstall_mutex);
reinstall_message = message;
}

std::string ReadReinstallMessage() {
std::lock_guard<std::mutex> 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;

Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();

Expand Down