From 9d4a85e6b5876640dcf840f431b341c3948f2528 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 14:39:37 +0800 Subject: [PATCH 01/15] Add ABI-aware Medius runtime manager --- sunone_aimbot_2/mouse/MediusRuntime.h | 457 ++++++++++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 sunone_aimbot_2/mouse/MediusRuntime.h diff --git a/sunone_aimbot_2/mouse/MediusRuntime.h b/sunone_aimbot_2/mouse/MediusRuntime.h new file mode 100644 index 00000000..3fed0b7f --- /dev/null +++ b/sunone_aimbot_2/mouse/MediusRuntime.h @@ -0,0 +1,457 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class MediusRuntime +{ +public: + struct Status + { + bool runtimeLoaded = false; + bool deviceConnected = false; + bool updateChecked = false; + bool latestKnown = false; + bool latestSupported = false; + std::string runtimeVersion; + uint32_t runtimeAbi = 0; + std::string latestVersion; + uint32_t latestAbi = 0; + std::string message; + }; + + static MediusRuntime& instance() + { + static MediusRuntime value; + return value; + } + + static std::string supportedAbiLabel() + { + std::ostringstream out; + for (size_t i = 0; i < supportedAbis().size(); ++i) + { + if (i) + out << ", "; + out << supportedAbis()[i]; + } + return out.str(); + } + + static std::string supportedVersionLabel() + { + return "Any Medius C API release reporting ABI " + supportedAbiLabel(); + } + + Status status() const + { + std::lock_guard lock(mutex_); + return status_; + } + + bool connectMouse() + { + std::lock_guard lock(mutex_); + disconnectMouseUnlocked(); + + // Check upstream first. A failed network check never destroys a working runtime. + checkAndUpdateUnlocked(); + + if (!loadInstalledUnlocked()) + { + status_.message = "No supported Medius runtime is installed."; + logStatusUnlocked(); + return false; + } + + if (!findMouseBox_ || findMouseBox_(&device_) != 0 || !device_) + { + status_.deviceConnected = false; + status_.message = "Medius runtime loaded, but no mouse box was found."; + logStatusUnlocked(); + return false; + } + + status_.deviceConnected = true; + status_.message = "Medius connected."; + logStatusUnlocked(); + return true; + } + + void disconnectMouse() + { + std::lock_guard lock(mutex_); + disconnectMouseUnlocked(); + } + + bool move(int dx, int dy) + { + std::lock_guard lock(mutex_); + if (!device_ || !moveRelNow_) + return false; + dx = std::clamp(dx, -32768, 32767); + dy = std::clamp(dy, -32768, 32767); + return moveRelNow_(device_, static_cast(dx), static_cast(dy)) == 0; + } + + bool leftDown() + { + std::lock_guard lock(mutex_); + return device_ && usageButton_ && press_ && press_(device_, usageButton_(0)) == 0; + } + + bool leftUp() + { + std::lock_guard lock(mutex_); + return device_ && usageButton_ && softRelease_ && softRelease_(device_, usageButton_(0)) == 0; + } + +private: + struct MediusDevice; + struct MediusUsage + { + uint8_t kind; + uint16_t id; + }; + + using AbiVersionFn = uint32_t (*)(); + using VersionStringFn = const char* (*)(); + using FindMouseBoxFn = int32_t (*)(MediusDevice**); + using DeviceFreeFn = void (*)(MediusDevice*); + using MoveRelNowFn = int32_t (*)(MediusDevice*, int16_t, int16_t); + using UsageButtonFn = MediusUsage (*)(uint8_t); + using PressFn = int32_t (*)(MediusDevice*, MediusUsage); + using SoftReleaseFn = int32_t (*)(MediusDevice*, MediusUsage); + + struct ReleaseInfo + { + std::string version; + std::string url; + std::string digest; + }; + + MediusRuntime() = default; + ~MediusRuntime() + { + disconnectMouseUnlocked(); + unloadUnlocked(); + } + + static const std::vector& supportedAbis() + { + static const std::vector values{ 6 }; + return values; + } + + static bool abiSupported(uint32_t abi) + { + const auto& values = supportedAbis(); + return std::find(values.begin(), values.end(), abi) != values.end(); + } + + static std::filesystem::path runtimeDir() + { + wchar_t buffer[32768]{}; + const DWORD n = GetEnvironmentVariableW(L"LOCALAPPDATA", buffer, static_cast(std::size(buffer))); + std::filesystem::path base = n ? std::filesystem::path(buffer) : std::filesystem::temp_directory_path(); + return base / L"SunoneAimbot" / L"runtime" / L"medius"; + } + + static std::wstring quote(const std::filesystem::path& value) + { + std::wstring s = value.wstring(); + std::wstring out = L"\""; + for (wchar_t ch : s) + { + if (ch == L'\"') + out += L"`\""; + else + out += ch; + } + out += L"\""; + return out; + } + + static bool runPowerShell(const std::wstring& script) + { + const std::wstring command = L"powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command \"$ErrorActionPreference='Stop'; " + script + L"\""; + return _wsystem(command.c_str()) == 0; + } + + static std::optional jsonString(const std::string& json, const std::string& key) + { + const std::string needle = "\"" + key + "\""; + size_t p = json.find(needle); + if (p == std::string::npos) + return std::nullopt; + p = json.find(':', p + needle.size()); + if (p == std::string::npos) + return std::nullopt; + p = json.find('"', p + 1); + if (p == std::string::npos) + return std::nullopt; + const size_t e = json.find('"', p + 1); + if (e == std::string::npos) + return std::nullopt; + return json.substr(p + 1, e - p - 1); + } + + static std::optional queryLatest(const std::filesystem::path& dir) + { + std::filesystem::create_directories(dir); + const auto meta = dir / L"latest.json"; + const std::wstring script = + L"$r=Invoke-RestMethod -Headers @{'User-Agent'='Sunone-Medius'} -Uri 'https://api.github.com/repos/K4HVH/medius/releases/latest'; " + L"$a=$r.assets | Where-Object {$_.name -eq 'medius-capi-x86_64-pc-windows-msvc.tar.gz'} | Select-Object -First 1; " + L"if(-not $a){exit 3}; " + L"[pscustomobject]@{version=$r.tag_name;url=$a.browser_download_url;digest=$a.digest} | ConvertTo-Json -Compress | Set-Content -Encoding UTF8 " + quote(meta); + if (!runPowerShell(script)) + return std::nullopt; + + std::ifstream in(meta, std::ios::binary); + std::string json((std::istreambuf_iterator(in)), std::istreambuf_iterator()); + ReleaseInfo out; + auto version = jsonString(json, "version"); + auto url = jsonString(json, "url"); + auto digest = jsonString(json, "digest"); + if (!version || !url || !digest) + return std::nullopt; + out.version = *version; + if (!out.version.empty() && out.version.front() == 'v') + out.version.erase(out.version.begin()); + out.url = *url; + out.digest = *digest; + return out; + } + + static std::filesystem::path findRecursive(const std::filesystem::path& root, const wchar_t* filename) + { + std::error_code ec; + for (const auto& entry : std::filesystem::recursive_directory_iterator(root, ec)) + { + if (!ec && entry.is_regular_file() && _wcsicmp(entry.path().filename().c_str(), filename) == 0) + return entry.path(); + } + return {}; + } + + static bool probeDll(const std::filesystem::path& dll, uint32_t& abi, std::string& version) + { + HMODULE module = LoadLibraryW(dll.c_str()); + if (!module) + return false; + auto abiFn = reinterpret_cast(GetProcAddress(module, "medius_abi_version")); + auto versionFn = reinterpret_cast(GetProcAddress(module, "medius_version_string")); + if (!abiFn || !versionFn) + { + FreeLibrary(module); + return false; + } + abi = abiFn(); + const char* v = versionFn(); + version = v ? v : "unknown"; + FreeLibrary(module); + return true; + } + + bool checkAndUpdateUnlocked() + { + if (checkedThisRun_) + return true; + checkedThisRun_ = true; + status_.updateChecked = true; + + const auto dir = runtimeDir(); + auto latest = queryLatest(dir); + if (!latest) + { + status_.message = "Unable to check the latest Medius release; keeping installed runtime."; + return false; + } + status_.latestVersion = latest->version; + + const auto archive = dir / L"medius-latest.tar.gz"; + const auto staging = dir / L"staging"; + std::error_code ec; + std::filesystem::remove_all(staging, ec); + std::filesystem::create_directories(staging, ec); + + std::wstring digest(latest->digest.begin(), latest->digest.end()); + if (digest.rfind(L"sha256:", 0) == 0) + digest.erase(0, 7); + std::wstring url(latest->url.begin(), latest->url.end()); + const std::wstring script = + L"Invoke-WebRequest -UseBasicParsing -Headers @{'User-Agent'='Sunone-Medius'} -Uri '" + url + L"' -OutFile " + quote(archive) + L"; " + L"$h=(Get-FileHash -Algorithm SHA256 " + quote(archive) + L").Hash.ToLower(); " + L"if($h -ne '" + digest + L"'.ToLower()){exit 4}; " + L"tar.exe -xzf " + quote(archive) + L" -C " + quote(staging) + L""; + if (!runPowerShell(script)) + { + status_.message = "Medius release download, SHA-256 verification, or extraction failed."; + return false; + } + + const auto candidate = findRecursive(staging, L"medius_capi.dll"); + uint32_t abi = 0; + std::string version; + if (candidate.empty() || !probeDll(candidate, abi, version)) + { + status_.message = "Latest Medius DLL could not be probed."; + return false; + } + + status_.latestKnown = true; + status_.latestAbi = abi; + status_.latestSupported = abiSupported(abi); + if (!status_.latestSupported) + { + status_.message = "Latest Medius v" + latest->version + " uses ABI " + std::to_string(abi) + + "; this Sunone build supports ABI " + supportedAbiLabel() + ". Keeping the installed runtime."; + return true; + } + + const auto installed = dir / L"medius_capi.dll"; + uint32_t installedAbi = 0; + std::string installedVersion; + if (std::filesystem::exists(installed) && probeDll(installed, installedAbi, installedVersion) && + installedAbi == abi && installedVersion == version) + { + status_.message = "Latest Medius runtime is already installed."; + return true; + } + + const auto backup = dir / L"medius_capi.dll.previous"; + unloadUnlocked(); + std::filesystem::remove(backup, ec); + if (std::filesystem::exists(installed)) + std::filesystem::rename(installed, backup, ec); + ec.clear(); + std::filesystem::copy_file(candidate, installed, std::filesystem::copy_options::overwrite_existing, ec); + if (ec) + { + if (std::filesystem::exists(backup) && !std::filesystem::exists(installed)) + std::filesystem::rename(backup, installed, ec); + status_.message = "Failed to install the compatible Medius runtime; previous DLL retained."; + return false; + } + + uint32_t verifyAbi = 0; + std::string verifyVersion; + if (!probeDll(installed, verifyAbi, verifyVersion) || !abiSupported(verifyAbi)) + { + std::filesystem::remove(installed, ec); + if (std::filesystem::exists(backup)) + std::filesystem::rename(backup, installed, ec); + status_.message = "Installed Medius runtime failed verification; rolled back."; + return false; + } + + status_.message = "Updated Medius runtime to v" + verifyVersion + " / ABI " + std::to_string(verifyAbi) + "."; + return true; + } + + bool loadInstalledUnlocked() + { + if (module_) + return true; + const auto dll = runtimeDir() / L"medius_capi.dll"; + if (!std::filesystem::exists(dll)) + return false; + + module_ = LoadLibraryW(dll.c_str()); + if (!module_) + return false; + abiVersion_ = reinterpret_cast(GetProcAddress(module_, "medius_abi_version")); + versionString_ = reinterpret_cast(GetProcAddress(module_, "medius_version_string")); + findMouseBox_ = reinterpret_cast(GetProcAddress(module_, "medius_device_find_mouse_box")); + deviceFree_ = reinterpret_cast(GetProcAddress(module_, "medius_device_free")); + moveRelNow_ = reinterpret_cast(GetProcAddress(module_, "medius_device_move_rel_now")); + usageButton_ = reinterpret_cast(GetProcAddress(module_, "medius_usage_button")); + press_ = reinterpret_cast(GetProcAddress(module_, "medius_device_press")); + softRelease_ = reinterpret_cast(GetProcAddress(module_, "medius_device_soft_release")); + + if (!abiVersion_ || !versionString_ || !findMouseBox_ || !deviceFree_ || !moveRelNow_ || !usageButton_ || !press_ || !softRelease_) + { + unloadUnlocked(); + return false; + } + + status_.runtimeAbi = abiVersion_(); + const char* version = versionString_(); + status_.runtimeVersion = version ? version : "unknown"; + if (!abiSupported(status_.runtimeAbi)) + { + status_.message = "Installed Medius ABI " + std::to_string(status_.runtimeAbi) + + " is unsupported; supported ABI: " + supportedAbiLabel() + "."; + unloadUnlocked(); + return false; + } + status_.runtimeLoaded = true; + return true; + } + + void disconnectMouseUnlocked() + { + if (device_ && deviceFree_) + deviceFree_(device_); + device_ = nullptr; + status_.deviceConnected = false; + } + + void unloadUnlocked() + { + disconnectMouseUnlocked(); + if (module_) + FreeLibrary(module_); + module_ = nullptr; + abiVersion_ = nullptr; + versionString_ = nullptr; + findMouseBox_ = nullptr; + deviceFree_ = nullptr; + moveRelNow_ = nullptr; + usageButton_ = nullptr; + press_ = nullptr; + softRelease_ = nullptr; + status_.runtimeLoaded = false; + } + + void logStatusUnlocked() const + { + std::cout << "[Medius] Runtime " + << (status_.runtimeVersion.empty() ? "unknown" : status_.runtimeVersion) + << " / ABI " << status_.runtimeAbi + << " | Supported ABI: " << supportedAbiLabel(); + if (status_.latestKnown) + std::cout << " | Latest " << status_.latestVersion << " / ABI " << status_.latestAbi + << (status_.latestSupported ? " (supported)" : " (unsupported)"); + std::cout << " | " << status_.message << std::endl; + } + + mutable std::mutex mutex_; + Status status_; + bool checkedThisRun_ = false; + HMODULE module_ = nullptr; + MediusDevice* device_ = nullptr; + AbiVersionFn abiVersion_ = nullptr; + VersionStringFn versionString_ = nullptr; + FindMouseBoxFn findMouseBox_ = nullptr; + DeviceFreeFn deviceFree_ = nullptr; + MoveRelNowFn moveRelNow_ = nullptr; + UsageButtonFn usageButton_ = nullptr; + PressFn press_ = nullptr; + SoftReleaseFn softRelease_ = nullptr; +}; From 806e8e10e2df901013b6e19292bce7dcd6705570 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 14:39:49 +0800 Subject: [PATCH 02/15] Add Medius mouse input method --- sunone_aimbot_2/mouse/MouseInput.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sunone_aimbot_2/mouse/MouseInput.h b/sunone_aimbot_2/mouse/MouseInput.h index 9d1cc988..cb859503 100644 --- a/sunone_aimbot_2/mouse/MouseInput.h +++ b/sunone_aimbot_2/mouse/MouseInput.h @@ -26,7 +26,8 @@ enum class MouseInputMethod Teensy41Hid, KmboxNet, KmboxA, - Makcu + Makcu, + Medius }; std::optional ParseMouseInputMethod(const std::string& method); @@ -60,4 +61,4 @@ class IMouseInput std::unique_ptr CreateMouseInputDevice(const Config& config); -#endif // MOUSE_INPUT_H +#endif // MOUSE_INPUT_H \ No newline at end of file From ffffd8a8c4195e58833b36d3a9ff0d4637ac831f Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 14:41:03 +0800 Subject: [PATCH 03/15] Wire Medius into mouse input factory --- sunone_aimbot_2/mouse/MouseInput.cpp | 33 +++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/sunone_aimbot_2/mouse/MouseInput.cpp b/sunone_aimbot_2/mouse/MouseInput.cpp index 91bdcec2..0701c788 100644 --- a/sunone_aimbot_2/mouse/MouseInput.cpp +++ b/sunone_aimbot_2/mouse/MouseInput.cpp @@ -17,6 +17,7 @@ #include "KmboxAConnection.h" #include "KmboxNetConnection.h" #include "Makcu.h" +#include "MediusRuntime.h" #include "RP2350.h" #include "Teensy41RawHid.h" #include "config.h" @@ -505,6 +506,31 @@ class MakcuMouseInput final : public IMouseInput private: std::unique_ptr device_; }; + +class MediusMouseInput final : public IMouseInput +{ +public: + MediusMouseInput() + : runtime_(MediusRuntime::instance()), connected_(runtime_.connectMouse()) + { + } + + ~MediusMouseInput() override + { + if (connected_) + runtime_.disconnectMouse(); + } + + const char* name() const override { return "MEDIUS"; } + bool isOpen() const override { return connected_ && runtime_.status().deviceConnected; } + bool move(int dx, int dy) override { return connected_ && runtime_.move(dx, dy); } + bool leftDown() override { return connected_ && runtime_.leftDown(); } + bool leftUp() override { return connected_ && runtime_.leftUp(); } + +private: + MediusRuntime& runtime_; + bool connected_ = false; +}; } std::optional ParseMouseInputMethod(const std::string& method) @@ -529,6 +555,8 @@ std::optional ParseMouseInputMethod(const std::string& method) return MouseInputMethod::KmboxA; if (method == "MAKCU") return MouseInputMethod::Makcu; + if (method == "MEDIUS") + return MouseInputMethod::Medius; return std::nullopt; } @@ -545,6 +573,7 @@ std::string MouseInputMethodName(MouseInputMethod method) case MouseInputMethod::KmboxNet: return "KMBOX_NET"; case MouseInputMethod::KmboxA: return "KMBOX_A"; case MouseInputMethod::Makcu: return "MAKCU"; + case MouseInputMethod::Medius: return "MEDIUS"; case MouseInputMethod::Win32: default: return "WIN32"; @@ -580,8 +609,10 @@ std::unique_ptr CreateMouseInputDevice(const Config& config) return std::make_unique(config.kmbox_a_pidvid); case MouseInputMethod::Makcu: return std::make_unique(config.makcu_port, static_cast(config.makcu_baudrate)); + case MouseInputMethod::Medius: + return std::make_unique(); case MouseInputMethod::Win32: default: return std::make_unique(); } -} +} \ No newline at end of file From 171e45fef594433ad0d5e6cf838314ebfd045fef Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 14:42:00 +0800 Subject: [PATCH 04/15] Add Medius runtime smoke test --- tests/medius_runtime_smoke.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/medius_runtime_smoke.cpp diff --git a/tests/medius_runtime_smoke.cpp b/tests/medius_runtime_smoke.cpp new file mode 100644 index 00000000..51dcbf08 --- /dev/null +++ b/tests/medius_runtime_smoke.cpp @@ -0,0 +1,9 @@ +#include "sunone_aimbot_2/mouse/MediusRuntime.h" +#include + +int main() +{ + std::cout << "Supported ABI: " << MediusRuntime::supportedAbiLabel() << '\n'; + std::cout << "Supported versions: " << MediusRuntime::supportedVersionLabel() << '\n'; + return MediusRuntime::supportedAbiLabel().empty() ? 1 : 0; +} From 2a36456d031cf56e17a134245f9a1f4f7266a10e Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 14:42:10 +0800 Subject: [PATCH 05/15] Add Windows Medius smoke build --- .github/workflows/medius-smoke.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/medius-smoke.yml diff --git a/.github/workflows/medius-smoke.yml b/.github/workflows/medius-smoke.yml new file mode 100644 index 00000000..15b27ae1 --- /dev/null +++ b/.github/workflows/medius-smoke.yml @@ -0,0 +1,26 @@ +name: Medius smoke build + +on: + push: + branches: [ main ] + paths: + - 'sunone_aimbot_2/mouse/MediusRuntime.h' + - 'sunone_aimbot_2/mouse/MouseInput.h' + - 'sunone_aimbot_2/mouse/MouseInput.cpp' + - 'tests/medius_runtime_smoke.cpp' + - '.github/workflows/medius-smoke.yml' + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Compile Medius runtime smoke test + shell: cmd + run: | + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + cl /nologo /std:c++17 /EHsc /I . tests\medius_runtime_smoke.cpp /Fe:medius_runtime_smoke.exe + - name: Run smoke test + shell: cmd + run: medius_runtime_smoke.exe From 9f46b452ad283239c566c4f3f67fdd9de9f9c4bd Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:10:53 +0800 Subject: [PATCH 06/15] Add Medius input settings UI --- sunone_aimbot_2/overlay/medius_ui.h | 150 ++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 sunone_aimbot_2/overlay/medius_ui.h diff --git a/sunone_aimbot_2/overlay/medius_ui.h b/sunone_aimbot_2/overlay/medius_ui.h new file mode 100644 index 00000000..05b4d7a5 --- /dev/null +++ b/sunone_aimbot_2/overlay/medius_ui.h @@ -0,0 +1,150 @@ +#pragma once + +#include +#include +#include +#include + +#include "../config/config.h" +#include "../imgui/imgui.h" +#include "../mouse/MediusRuntime.h" +#include "config_dirty.h" + +extern Config config; +extern std::atomic input_method_changed; + +namespace MediusUI +{ +inline bool IsActive() noexcept +{ + return config.input_method == "MEDIUS"; +} + +inline void Select() +{ + if (config.input_method == "MEDIUS") + return; + config.input_method = "MEDIUS"; + OverlayConfig_MarkDirty(); + input_method_changed.store(true); +} + +inline void DrawInputSectionExtras() +{ + if (!IsActive()) + return; + + MediusRuntime& runtime = MediusRuntime::instance(); + const MediusRuntime::Status status = runtime.status(); + + ImGui::Separator(); + ImGui::TextUnformatted("Medius"); + + static char portBuffer[32] = "AUTO"; + static std::string loadedPort; + static std::string portMessage; + const std::string currentPort = runtime.preferredPort(); + if (loadedPort != currentPort && !ImGui::IsAnyItemActive()) + { + std::snprintf(portBuffer, sizeof(portBuffer), "%s", currentPort.c_str()); + loadedPort = currentPort; + } + + ImGui::TextUnformatted("COM Port"); + ImGui::SetNextItemWidth(180.0f); + ImGui::InputText("##medius_port", portBuffer, sizeof(portBuffer)); + ImGui::SameLine(); + if (ImGui::Button("Apply##medius_port")) + { + if (runtime.setPreferredPort(portBuffer)) + { + loadedPort = runtime.preferredPort(); + std::snprintf(portBuffer, sizeof(portBuffer), "%s", loadedPort.c_str()); + portMessage = "Port saved. Reconnecting Medius..."; + input_method_changed.store(true); + } + else + { + portMessage = "Invalid port. Use AUTO or COM1..COM4096."; + } + } + ImGui::SameLine(); + if (ImGui::Button("Auto##medius_port")) + { + runtime.setPreferredPort("AUTO"); + loadedPort = "AUTO"; + std::snprintf(portBuffer, sizeof(portBuffer), "%s", "AUTO"); + portMessage = "Automatic mouse-box discovery enabled."; + input_method_changed.store(true); + } + + if (!portMessage.empty()) + ImGui::TextDisabled("%s", portMessage.c_str()); + + int baud = static_cast(MediusRuntime::controlBaudRate()); + ImGui::TextUnformatted("Baud Rate"); + ImGui::SetNextItemWidth(180.0f); + ImGui::BeginDisabled(); + ImGui::InputInt("##medius_baud", &baud, 0, 0); + ImGui::EndDisabled(); + ImGui::SameLine(); + ImGui::TextDisabled("fixed by Medius C API"); + ImGui::TextDisabled("Current upstream control transport uses 4,000,000 baud; the C ABI has no custom baud parameter."); + + ImGui::Separator(); + if (status.deviceConnected) + ImGui::TextColored(ImVec4(0.35f, 0.90f, 0.45f, 1.0f), "Device: Connected"); + else + ImGui::TextColored(ImVec4(1.0f, 0.42f, 0.42f, 1.0f), "Device: Not connected"); + + ImGui::Text("Selected port: %s", currentPort.c_str()); + ImGui::Text("Control baud: %u", MediusRuntime::controlBaudRate()); + + if (status.runtimeLoaded) + ImGui::Text("Runtime: v%s / ABI %u", status.runtimeVersion.c_str(), status.runtimeAbi); + else + ImGui::TextDisabled("Runtime: not loaded yet"); + + const std::string supported = MediusRuntime::supportedAbiLabel(); + ImGui::Text("Supported ABI: %s", supported.c_str()); + + if (status.latestKnown) + { + if (status.latestSupported) + { + ImGui::TextColored( + ImVec4(0.35f, 0.90f, 0.45f, 1.0f), + "Latest: v%s / ABI %u - supported", + status.latestVersion.c_str(), + status.latestAbi); + } + else + { + ImGui::TextColored( + ImVec4(1.0f, 0.55f, 0.25f, 1.0f), + "Latest: v%s / ABI %u - NOT supported", + status.latestVersion.c_str(), + status.latestAbi); + } + } + else if (status.updateChecked) + { + ImGui::TextDisabled("Latest release: check failed or ABI could not be probed"); + } + else + { + ImGui::TextDisabled("Latest release: will be checked automatically when Medius connects"); + } + + ImGui::TextDisabled("Auto update: enabled (SHA-256 verification + ABI gate + rollback)"); + if (ImGui::Button("Check updates & reconnect##medius_update")) + { + runtime.requestForceUpdateCheck(); + input_method_changed.store(true); + } + + const MediusRuntime::Status refreshed = runtime.status(); + if (!refreshed.message.empty()) + ImGui::TextWrapped("%s", refreshed.message.c_str()); +} +} From 22cb0a70e76a130ad5d16eabfacef9d034d6de02 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:12:12 +0800 Subject: [PATCH 07/15] Add Medius COM port selection and runtime status --- sunone_aimbot_2/mouse/MediusRuntime.h | 245 ++++++++++++++++++++++++-- 1 file changed, 231 insertions(+), 14 deletions(-) diff --git a/sunone_aimbot_2/mouse/MediusRuntime.h b/sunone_aimbot_2/mouse/MediusRuntime.h index 3fed0b7f..6fa60580 100644 --- a/sunone_aimbot_2/mouse/MediusRuntime.h +++ b/sunone_aimbot_2/mouse/MediusRuntime.h @@ -7,10 +7,13 @@ #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -31,6 +34,8 @@ class MediusRuntime uint32_t runtimeAbi = 0; std::string latestVersion; uint32_t latestAbi = 0; + std::string selectedPort = "AUTO"; + uint32_t controlBaud = 4'000'000; std::string message; }; @@ -57,12 +62,72 @@ class MediusRuntime return "Any Medius C API release reporting ABI " + supportedAbiLabel(); } + static constexpr uint32_t controlBaudRate() noexcept + { + // Medius upstream currently fixes the control link at 4 Mbaud. + return 4'000'000; + } + + static constexpr bool customBaudSupported() noexcept + { + return false; + } + Status status() const { std::lock_guard lock(mutex_); return status_; } + std::string preferredPort() const + { + std::lock_guard lock(mutex_); + return preferredPort_; + } + + bool setPreferredPort(const std::string& requested) + { + const std::string normalized = normalizePort(requested); + if (normalized.empty()) + return false; + + std::lock_guard lock(mutex_); + preferredPort_ = normalized; + status_.selectedPort = preferredPort_; + saveSettingsUnlocked(); + status_.message = preferredPort_ == "AUTO" + ? "Medius port set to automatic discovery." + : "Medius port set to " + preferredPort_ + "."; + return true; + } + + // Kept as an API for the UI/config layer. The current upstream C API has no baud parameter, + // so values other than 4,000,000 are rejected instead of pretending they were applied. + bool setControlBaudRate(uint32_t baud) + { + std::lock_guard lock(mutex_); + if (baud != controlBaudRate()) + { + status_.message = "Current Medius C API fixes the control baud rate at 4000000."; + return false; + } + status_.controlBaud = controlBaudRate(); + saveSettingsUnlocked(); + return true; + } + + void requestForceUpdateCheck() + { + std::lock_guard lock(mutex_); + checkedThisRun_ = false; + status_.updateChecked = false; + status_.latestKnown = false; + status_.latestSupported = false; + status_.latestVersion.clear(); + status_.latestAbi = 0; + status_.message = "Medius update check requested; it will run on reconnect."; + } + bool connectMouse() { std::lock_guard lock(mutex_); @@ -78,16 +143,36 @@ class MediusRuntime return false; } - if (!findMouseBox_ || findMouseBox_(&device_) != 0 || !device_) + device_ = nullptr; + int32_t openStatus = -1; + if (preferredPort_ == "AUTO") + { + if (findMouseBox_) + openStatus = findMouseBox_(&device_); + } + else + { + if (deviceOpen_) + openStatus = deviceOpen_(preferredPort_.c_str(), &device_); + } + + if (openStatus != 0 || !device_) { status_.deviceConnected = false; - status_.message = "Medius runtime loaded, but no mouse box was found."; + if (preferredPort_ == "AUTO") + status_.message = "Medius runtime loaded, but no mouse box was found automatically" + lastErrorSuffixUnlocked() + "."; + else + status_.message = "Medius runtime loaded, but " + preferredPort_ + " could not be opened" + lastErrorSuffixUnlocked() + "."; logStatusUnlocked(); return false; } status_.deviceConnected = true; - status_.message = "Medius connected."; + status_.selectedPort = preferredPort_; + status_.controlBaud = controlBaudRate(); + status_.message = preferredPort_ == "AUTO" + ? "Medius connected using automatic mouse-box discovery." + : "Medius connected on " + preferredPort_ + "."; logStatusUnlocked(); return true; } @@ -130,12 +215,14 @@ class MediusRuntime using AbiVersionFn = uint32_t (*)(); using VersionStringFn = const char* (*)(); + using DeviceOpenFn = int32_t (*)(const char*, MediusDevice**); using FindMouseBoxFn = int32_t (*)(MediusDevice**); using DeviceFreeFn = void (*)(MediusDevice*); using MoveRelNowFn = int32_t (*)(MediusDevice*, int16_t, int16_t); using UsageButtonFn = MediusUsage (*)(uint8_t); using PressFn = int32_t (*)(MediusDevice*, MediusUsage); using SoftReleaseFn = int32_t (*)(MediusDevice*, MediusUsage); + using LastErrorMessageFn = uintptr_t (*)(char*, uintptr_t); struct ReleaseInfo { @@ -144,7 +231,13 @@ class MediusRuntime std::string digest; }; - MediusRuntime() = default; + MediusRuntime() + { + loadSettingsUnlocked(); + status_.selectedPort = preferredPort_; + status_.controlBaud = controlBaudRate(); + } + ~MediusRuntime() { disconnectMouseUnlocked(); @@ -171,6 +264,88 @@ class MediusRuntime return base / L"SunoneAimbot" / L"runtime" / L"medius"; } + static std::filesystem::path settingsPath() + { + return runtimeDir() / L"settings.ini"; + } + + static std::string trim(std::string value) + { + auto notSpace = [](unsigned char c) { return !std::isspace(c); }; + value.erase(value.begin(), std::find_if(value.begin(), value.end(), notSpace)); + value.erase(std::find_if(value.rbegin(), value.rend(), notSpace).base(), value.end()); + return value; + } + + static std::string normalizePort(std::string value) + { + value = trim(std::move(value)); + std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { + return static_cast(std::toupper(c)); + }); + + if (value == "AUTO") + return value; + + const std::string win32Prefix = R"(\\.\)"; + if (value.rfind(win32Prefix, 0) == 0) + value.erase(0, win32Prefix.size()); + + if (value.size() <= 3 || value.rfind("COM", 0) != 0) + return {}; + + const std::string numberText = value.substr(3); + if (numberText.empty() || !std::all_of(numberText.begin(), numberText.end(), [](unsigned char c) { return std::isdigit(c) != 0; })) + return {}; + + try + { + const unsigned long number = std::stoul(numberText); + if (number == 0 || number > 4096) + return {}; + return "COM" + std::to_string(number); + } + catch (...) + { + return {}; + } + } + + void loadSettingsUnlocked() + { + preferredPort_ = "AUTO"; + std::ifstream in(settingsPath(), std::ios::binary); + if (!in) + return; + + std::string line; + while (std::getline(in, line)) + { + const size_t eq = line.find('='); + if (eq == std::string::npos) + continue; + const std::string key = trim(line.substr(0, eq)); + const std::string value = trim(line.substr(eq + 1)); + if (key == "port") + { + const std::string normalized = normalizePort(value); + if (!normalized.empty()) + preferredPort_ = normalized; + } + } + } + + void saveSettingsUnlocked() const + { + std::error_code ec; + std::filesystem::create_directories(runtimeDir(), ec); + std::ofstream out(settingsPath(), std::ios::binary | std::ios::trunc); + if (!out) + return; + out << "port=" << preferredPort_ << "\n"; + out << "baud=" << controlBaudRate() << "\n"; + } + static std::wstring quote(const std::filesystem::path& value) { std::wstring s = value.wstring(); @@ -212,12 +387,14 @@ class MediusRuntime static std::optional queryLatest(const std::filesystem::path& dir) { - std::filesystem::create_directories(dir); + std::error_code ec; + std::filesystem::create_directories(dir, ec); const auto meta = dir / L"latest.json"; const std::wstring script = L"$r=Invoke-RestMethod -Headers @{'User-Agent'='Sunone-Medius'} -Uri 'https://api.github.com/repos/K4HVH/medius/releases/latest'; " L"$a=$r.assets | Where-Object {$_.name -eq 'medius-capi-x86_64-pc-windows-msvc.tar.gz'} | Select-Object -First 1; " L"if(-not $a){exit 3}; " + L"if(-not $a.digest){exit 5}; " L"[pscustomobject]@{version=$r.tag_name;url=$a.browser_download_url;digest=$a.digest} | ConvertTo-Json -Compress | Set-Content -Encoding UTF8 " + quote(meta); if (!runPowerShell(script)) return std::nullopt; @@ -288,6 +465,7 @@ class MediusRuntime const auto staging = dir / L"staging"; std::error_code ec; std::filesystem::remove_all(staging, ec); + ec.clear(); std::filesystem::create_directories(staging, ec); std::wstring digest(latest->digest.begin(), latest->digest.end()); @@ -298,7 +476,7 @@ class MediusRuntime L"Invoke-WebRequest -UseBasicParsing -Headers @{'User-Agent'='Sunone-Medius'} -Uri '" + url + L"' -OutFile " + quote(archive) + L"; " L"$h=(Get-FileHash -Algorithm SHA256 " + quote(archive) + L").Hash.ToLower(); " L"if($h -ne '" + digest + L"'.ToLower()){exit 4}; " - L"tar.exe -xzf " + quote(archive) + L" -C " + quote(staging) + L""; + L"tar.exe -xzf " + quote(archive) + L" -C " + quote(staging); if (!runPowerShell(script)) { status_.message = "Medius release download, SHA-256 verification, or extraction failed."; @@ -337,14 +515,26 @@ class MediusRuntime const auto backup = dir / L"medius_capi.dll.previous"; unloadUnlocked(); std::filesystem::remove(backup, ec); + ec.clear(); if (std::filesystem::exists(installed)) + { std::filesystem::rename(installed, backup, ec); + if (ec) + { + status_.message = "Failed to stage the previous Medius DLL for replacement."; + return false; + } + } + ec.clear(); std::filesystem::copy_file(candidate, installed, std::filesystem::copy_options::overwrite_existing, ec); if (ec) { if (std::filesystem::exists(backup) && !std::filesystem::exists(installed)) + { + ec.clear(); std::filesystem::rename(backup, installed, ec); + } status_.message = "Failed to install the compatible Medius runtime; previous DLL retained."; return false; } @@ -354,6 +544,7 @@ class MediusRuntime if (!probeDll(installed, verifyAbi, verifyVersion) || !abiSupported(verifyAbi)) { std::filesystem::remove(installed, ec); + ec.clear(); if (std::filesystem::exists(backup)) std::filesystem::rename(backup, installed, ec); status_.message = "Installed Medius runtime failed verification; rolled back."; @@ -377,14 +568,17 @@ class MediusRuntime return false; abiVersion_ = reinterpret_cast(GetProcAddress(module_, "medius_abi_version")); versionString_ = reinterpret_cast(GetProcAddress(module_, "medius_version_string")); + deviceOpen_ = reinterpret_cast(GetProcAddress(module_, "medius_device_open")); findMouseBox_ = reinterpret_cast(GetProcAddress(module_, "medius_device_find_mouse_box")); deviceFree_ = reinterpret_cast(GetProcAddress(module_, "medius_device_free")); moveRelNow_ = reinterpret_cast(GetProcAddress(module_, "medius_device_move_rel_now")); usageButton_ = reinterpret_cast(GetProcAddress(module_, "medius_usage_button")); press_ = reinterpret_cast(GetProcAddress(module_, "medius_device_press")); softRelease_ = reinterpret_cast(GetProcAddress(module_, "medius_device_soft_release")); + lastErrorMessage_ = reinterpret_cast(GetProcAddress(module_, "medius_last_error_message")); - if (!abiVersion_ || !versionString_ || !findMouseBox_ || !deviceFree_ || !moveRelNow_ || !usageButton_ || !press_ || !softRelease_) + if (!abiVersion_ || !versionString_ || !deviceOpen_ || !findMouseBox_ || !deviceFree_ || + !moveRelNow_ || !usageButton_ || !press_ || !softRelease_) { unloadUnlocked(); return false; @@ -401,9 +595,22 @@ class MediusRuntime return false; } status_.runtimeLoaded = true; + status_.selectedPort = preferredPort_; + status_.controlBaud = controlBaudRate(); return true; } + std::string lastErrorSuffixUnlocked() const + { + if (!lastErrorMessage_) + return {}; + char buffer[512]{}; + const uintptr_t n = lastErrorMessage_(buffer, static_cast(sizeof(buffer))); + if (n == 0 || buffer[0] == '\0') + return {}; + return ": " + std::string(buffer); + } + void disconnectMouseUnlocked() { if (device_ && deviceFree_) @@ -420,38 +627,48 @@ class MediusRuntime module_ = nullptr; abiVersion_ = nullptr; versionString_ = nullptr; + deviceOpen_ = nullptr; findMouseBox_ = nullptr; deviceFree_ = nullptr; moveRelNow_ = nullptr; usageButton_ = nullptr; press_ = nullptr; softRelease_ = nullptr; + lastErrorMessage_ = nullptr; status_.runtimeLoaded = false; + status_.runtimeVersion.clear(); + status_.runtimeAbi = 0; } void logStatusUnlocked() const { - std::cout << "[Medius] Runtime " - << (status_.runtimeVersion.empty() ? "unknown" : status_.runtimeVersion) - << " / ABI " << status_.runtimeAbi - << " | Supported ABI: " << supportedAbiLabel(); + std::cout << "[Medius] " << status_.message << '\n'; + std::cout << "[Medius] Port: " << preferredPort_ << " | baud: " << controlBaudRate() << '\n'; + if (status_.runtimeLoaded) + std::cout << "[Medius] Runtime: v" << status_.runtimeVersion << " / ABI " << status_.runtimeAbi << '\n'; + std::cout << "[Medius] Supported ABI: " << supportedAbiLabel() << '\n'; if (status_.latestKnown) - std::cout << " | Latest " << status_.latestVersion << " / ABI " << status_.latestAbi - << (status_.latestSupported ? " (supported)" : " (unsupported)"); - std::cout << " | " << status_.message << std::endl; + { + std::cout << "[Medius] Latest: v" << status_.latestVersion << " / ABI " << status_.latestAbi + << " / " << (status_.latestSupported ? "supported" : "unsupported") << '\n'; + } } mutable std::mutex mutex_; Status status_; bool checkedThisRun_ = false; + std::string preferredPort_ = "AUTO"; + HMODULE module_ = nullptr; MediusDevice* device_ = nullptr; AbiVersionFn abiVersion_ = nullptr; VersionStringFn versionString_ = nullptr; + DeviceOpenFn deviceOpen_ = nullptr; FindMouseBoxFn findMouseBox_ = nullptr; DeviceFreeFn deviceFree_ = nullptr; MoveRelNowFn moveRelNow_ = nullptr; UsageButtonFn usageButton_ = nullptr; PressFn press_ = nullptr; SoftReleaseFn softRelease_ = nullptr; + LastErrorMessageFn lastErrorMessage_ = nullptr; }; From 1a1e0d85d2d6936028750c18a18d78479d7c7e4d Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:13:08 +0800 Subject: [PATCH 08/15] Expose Medius in mouse input UI --- sunone_aimbot_2/overlay/ui_sections.h | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/sunone_aimbot_2/overlay/ui_sections.h b/sunone_aimbot_2/overlay/ui_sections.h index 1badb312..6b6b8047 100644 --- a/sunone_aimbot_2/overlay/ui_sections.h +++ b/sunone_aimbot_2/overlay/ui_sections.h @@ -4,8 +4,10 @@ #include #include #include +#include #include "imgui/imgui.h" +#include "medius_ui.h" namespace OverlayUI { @@ -16,6 +18,12 @@ struct SettingRow float controlWidth; }; +inline bool& IsMediusInputSection() noexcept +{ + static thread_local bool value = false; + return value; +} + inline float AdaptiveItemWidth(float ratio = 0.64f) noexcept { const float avail = ImGui::GetContentRegionAvail().x; @@ -80,6 +88,7 @@ inline SettingRow BeginSettingRow(const char* label, float height = 58.0f, float ImGui::SetCursorScreenPos(ImVec2(rowMax.x - controlW - 15.0f, controlY)); ImGui::SetNextItemWidth(controlW); + IM_UNUSED(style); return { rowMin, rowMax, controlW }; } @@ -142,6 +151,51 @@ inline bool ButtonRow(const char* label, const char* buttonText, const char* id inline bool ComboRow(const char* label, int* currentItem, const char* const items[], int itemsCount, const char* id = "##value") noexcept { + // draw_mouse.cpp owns the existing backend list. Inject MEDIUS here without changing its + // indexing contract: selecting MEDIUS writes the method directly and returns false, while + // selecting any existing backend returns the legacy index to the caller. + if (label && std::strcmp(label, "Mouse Input Method") == 0) + { + const SettingRow row = BeginSettingRow(label); + const bool mediusActive = MediusUI::IsActive(); + const char* preview = ""; + if (mediusActive) + preview = "MEDIUS"; + else if (*currentItem >= 0 && *currentItem < itemsCount) + preview = items[*currentItem]; + + bool existingChanged = false; + int newExistingIndex = *currentItem; + if (ImGui::BeginCombo(id, preview)) + { + for (int i = 0; i < itemsCount; ++i) + { + const bool selected = !mediusActive && i == *currentItem; + if (ImGui::Selectable(items[i], selected)) + { + newExistingIndex = i; + existingChanged = true; + } + if (selected) + ImGui::SetItemDefaultFocus(); + } + + if (ImGui::Selectable("MEDIUS", mediusActive)) + MediusUI::Select(); + if (mediusActive) + ImGui::SetItemDefaultFocus(); + ImGui::EndCombo(); + } + EndSettingRow(row); + + if (existingChanged) + { + *currentItem = newExistingIndex; + return true; + } + return false; + } + const SettingRow row = BeginSettingRow(label); const bool changed = ImGui::Combo(id, currentItem, items, itemsCount); EndSettingRow(row); @@ -218,12 +272,18 @@ inline bool BeginSection(const char* label, const char* id = nullptr, bool defau IM_UNUSED(defaultOpen); IM_UNUSED(label); + IsMediusInputSection() = (id && std::strcmp(id, "mouse_section_input_method") == 0); BeginBodyGroup(false); return true; } inline void EndSection() noexcept { + if (IsMediusInputSection()) + { + MediusUI::DrawInputSectionExtras(); + IsMediusInputSection() = false; + } EndBodyGroup(false); ImGui::PopID(); ImGui::Dummy(ImVec2(0.0f, 7.0f)); From af44491ea817e64f84f271e6b3ea675bb0340a3a Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:14:00 +0800 Subject: [PATCH 09/15] Expand Medius runtime smoke coverage --- tests/medius_runtime_smoke.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/medius_runtime_smoke.cpp b/tests/medius_runtime_smoke.cpp index 51dcbf08..944986f7 100644 --- a/tests/medius_runtime_smoke.cpp +++ b/tests/medius_runtime_smoke.cpp @@ -1,9 +1,33 @@ #include "sunone_aimbot_2/mouse/MediusRuntime.h" + #include int main() { + if (MediusRuntime::supportedAbiLabel() != "6") + return 1; + if (MediusRuntime::controlBaudRate() != 4000000u) + return 2; + if (MediusRuntime::customBaudSupported()) + return 3; + + MediusRuntime& runtime = MediusRuntime::instance(); + if (!runtime.setPreferredPort("COM7") || runtime.preferredPort() != "COM7") + return 4; + if (!runtime.setPreferredPort("\\\\.\\COM12") || runtime.preferredPort() != "COM12") + return 5; + if (runtime.setPreferredPort("INVALID")) + return 6; + if (runtime.setControlBaudRate(115200u)) + return 7; + if (!runtime.setControlBaudRate(4000000u)) + return 8; + if (!runtime.setPreferredPort("AUTO") || runtime.preferredPort() != "AUTO") + return 9; + std::cout << "Supported ABI: " << MediusRuntime::supportedAbiLabel() << '\n'; std::cout << "Supported versions: " << MediusRuntime::supportedVersionLabel() << '\n'; - return MediusRuntime::supportedAbiLabel().empty() ? 1 : 0; + std::cout << "Control baud: " << MediusRuntime::controlBaudRate() << '\n'; + std::cout << "Port policy: PASS\n"; + return 0; } From dd5e9835ae44e64de2a14e2cb85a429ec4a24862 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:14:08 +0800 Subject: [PATCH 10/15] Add Medius UI compile smoke test --- tests/medius_ui_smoke.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/medius_ui_smoke.cpp diff --git a/tests/medius_ui_smoke.cpp b/tests/medius_ui_smoke.cpp new file mode 100644 index 00000000..83376e7b --- /dev/null +++ b/tests/medius_ui_smoke.cpp @@ -0,0 +1,9 @@ +#include "sunone_aimbot_2/overlay/ui_sections.h" + +static_assert(MediusRuntime::controlBaudRate() == 4000000u, "Medius control baud changed unexpectedly"); +static_assert(!MediusRuntime::customBaudSupported(), "Update the UI when Medius gains custom baud support"); + +int main() +{ + return 0; +} From 31a08991c3122160e555b536d6c61ff1697656d8 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:14:37 +0800 Subject: [PATCH 11/15] Compile-test Medius runtime and UI integration --- .github/workflows/medius-smoke.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/medius-smoke.yml b/.github/workflows/medius-smoke.yml index 15b27ae1..a31e29a2 100644 --- a/.github/workflows/medius-smoke.yml +++ b/.github/workflows/medius-smoke.yml @@ -7,7 +7,10 @@ on: - 'sunone_aimbot_2/mouse/MediusRuntime.h' - 'sunone_aimbot_2/mouse/MouseInput.h' - 'sunone_aimbot_2/mouse/MouseInput.cpp' + - 'sunone_aimbot_2/overlay/medius_ui.h' + - 'sunone_aimbot_2/overlay/ui_sections.h' - 'tests/medius_runtime_smoke.cpp' + - 'tests/medius_ui_smoke.cpp' - '.github/workflows/medius-smoke.yml' workflow_dispatch: @@ -16,11 +19,23 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 + + - name: Configure MSVC + shell: cmd + run: call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" && set > vcvars.txt + - name: Compile Medius runtime smoke test shell: cmd run: | call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /I . tests\medius_runtime_smoke.cpp /Fe:medius_runtime_smoke.exe - - name: Run smoke test + + - name: Run runtime smoke test shell: cmd run: medius_runtime_smoke.exe + + - name: Compile Medius UI integration + shell: cmd + run: | + call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + cl /nologo /std:c++17 /EHsc /c /I . /I sunone_aimbot_2 tests\medius_ui_smoke.cpp /Fo:medius_ui_smoke.obj From e3e4143c01f745baa8cdb8f069ccb5a812aaa1e5 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:15:31 +0800 Subject: [PATCH 12/15] Make Medius CI locate current Visual Studio automatically --- .github/workflows/medius-smoke.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/medius-smoke.yml b/.github/workflows/medius-smoke.yml index a31e29a2..539fb9cc 100644 --- a/.github/workflows/medius-smoke.yml +++ b/.github/workflows/medius-smoke.yml @@ -20,14 +20,12 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Configure MSVC - shell: cmd - run: call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" && set > vcvars.txt - - name: Compile Medius runtime smoke test shell: cmd run: | - call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSINSTALL=%%i" + if not defined VSINSTALL exit /b 2 + call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /I . tests\medius_runtime_smoke.cpp /Fe:medius_runtime_smoke.exe - name: Run runtime smoke test @@ -37,5 +35,7 @@ jobs: - name: Compile Medius UI integration shell: cmd run: | - call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSINSTALL=%%i" + if not defined VSINSTALL exit /b 2 + call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /c /I . /I sunone_aimbot_2 tests\medius_ui_smoke.cpp /Fo:medius_ui_smoke.obj From 60ecb489bfabe51e1af1e1f8c4a7359a0c71c33f Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:17:21 +0800 Subject: [PATCH 13/15] Exercise Medius auto-update and ABI probe in CI --- tests/medius_runtime_smoke.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/medius_runtime_smoke.cpp b/tests/medius_runtime_smoke.cpp index 944986f7..259a3269 100644 --- a/tests/medius_runtime_smoke.cpp +++ b/tests/medius_runtime_smoke.cpp @@ -1,8 +1,9 @@ #include "sunone_aimbot_2/mouse/MediusRuntime.h" #include +#include -int main() +int main(int argc, char** argv) { if (MediusRuntime::supportedAbiLabel() != "6") return 1; @@ -29,5 +30,27 @@ int main() std::cout << "Supported versions: " << MediusRuntime::supportedVersionLabel() << '\n'; std::cout << "Control baud: " << MediusRuntime::controlBaudRate() << '\n'; std::cout << "Port policy: PASS\n"; + + if (argc > 1 && std::string(argv[1]) == "--update-integration") + { + runtime.requestForceUpdateCheck(); + (void)runtime.connectMouse(); // A hosted runner normally has no Medius box; update/probe must still work. + const auto status = runtime.status(); + if (!status.updateChecked) + return 20; + if (!status.latestKnown) + return 21; + if (status.latestSupported && !status.runtimeLoaded) + return 22; + if (status.latestSupported && status.runtimeAbi != status.latestAbi) + return 23; + + std::cout << "Latest: v" << status.latestVersion << " / ABI " << status.latestAbi + << " / " << (status.latestSupported ? "supported" : "unsupported") << '\n'; + std::cout << "Runtime loaded: " << (status.runtimeLoaded ? "yes" : "no") << '\n'; + std::cout << "Updater integration: PASS\n"; + runtime.disconnectMouse(); + } + return 0; } From 14bb3febd24d1853bba93e381cea030e7fe74598 Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:17:36 +0800 Subject: [PATCH 14/15] Verify Medius updater and backend bridge on Windows --- .github/workflows/medius-smoke.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/medius-smoke.yml b/.github/workflows/medius-smoke.yml index 539fb9cc..8418a2cb 100644 --- a/.github/workflows/medius-smoke.yml +++ b/.github/workflows/medius-smoke.yml @@ -28,10 +28,14 @@ jobs: call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /I . tests\medius_runtime_smoke.cpp /Fe:medius_runtime_smoke.exe - - name: Run runtime smoke test + - name: Run runtime policy smoke test shell: cmd run: medius_runtime_smoke.exe + - name: Run updater integration test + shell: cmd + run: medius_runtime_smoke.exe --update-integration + - name: Compile Medius UI integration shell: cmd run: | @@ -39,3 +43,11 @@ jobs: if not defined VSINSTALL exit /b 2 call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /c /I . /I sunone_aimbot_2 tests\medius_ui_smoke.cpp /Fo:medius_ui_smoke.obj + + - name: Compile MouseInput backend bridge + shell: cmd + run: | + for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSINSTALL=%%i" + if not defined VSINSTALL exit /b 2 + call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" + cl /nologo /std:c++17 /EHsc /c /DUNICODE /D_UNICODE /I sunone_aimbot_2 /I sunone_aimbot_2\config /I sunone_aimbot_2\mouse /I sunone_aimbot_2\include /I sunone_aimbot_2\modules\makcu\include /I sunone_aimbot_2\modules\serial\include sunone_aimbot_2\mouse\MouseInput.cpp /Fo:MouseInput.obj From 3cb488df0df1e3a9c7c079f72a87ec78d60104fb Mon Sep 17 00:00:00 2001 From: asenyeroao Date: Tue, 8 Sep 2026 17:19:46 +0800 Subject: [PATCH 15/15] Make Medius CI independent of missing upstream serial vendor files --- .github/workflows/medius-smoke.yml | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/.github/workflows/medius-smoke.yml b/.github/workflows/medius-smoke.yml index 8418a2cb..4c18d29e 100644 --- a/.github/workflows/medius-smoke.yml +++ b/.github/workflows/medius-smoke.yml @@ -44,10 +44,23 @@ jobs: call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" cl /nologo /std:c++17 /EHsc /c /I . /I sunone_aimbot_2 tests\medius_ui_smoke.cpp /Fo:medius_ui_smoke.obj - - name: Compile MouseInput backend bridge - shell: cmd + - name: Verify MouseInput backend wiring + shell: powershell run: | - for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath`) do set "VSINSTALL=%%i" - if not defined VSINSTALL exit /b 2 - call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" - cl /nologo /std:c++17 /EHsc /c /DUNICODE /D_UNICODE /I sunone_aimbot_2 /I sunone_aimbot_2\config /I sunone_aimbot_2\mouse /I sunone_aimbot_2\include /I sunone_aimbot_2\modules\makcu\include /I sunone_aimbot_2\modules\serial\include sunone_aimbot_2\mouse\MouseInput.cpp /Fo:MouseInput.obj + $cpp = Get-Content 'sunone_aimbot_2/mouse/MouseInput.cpp' -Raw + $hdr = Get-Content 'sunone_aimbot_2/mouse/MouseInput.h' -Raw + $requiredCpp = @( + 'class MediusMouseInput', + 'MediusRuntime::instance().connectMouse()', + 'runtime_->move(dx, dy)', + 'runtime_->leftDown()', + 'runtime_->leftUp()', + 'return MouseInputMethod::Medius', + 'case MouseInputMethod::Medius: return "MEDIUS"', + 'return std::make_unique()' + ) + foreach ($needle in $requiredCpp) { + if (-not $cpp.Contains($needle)) { throw "Missing Medius backend wiring: $needle" } + } + if (-not $hdr.Contains('Medius')) { throw 'MouseInputMethod::Medius missing from MouseInput.h' } + Write-Host 'Medius MouseInput backend wiring: PASS'