From 45b4604b13e1c820117fc430dea16be6cbe35529 Mon Sep 17 00:00:00 2001 From: Sainan Date: Sat, 3 Feb 2024 16:15:04 +0100 Subject: [PATCH] Add autoswitch approach --- .gitignore | 1 + autoswitch/.sun | 2 + autoswitch/README.md | 14 ++++ autoswitch/main.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 autoswitch/.sun create mode 100644 autoswitch/README.md create mode 100644 autoswitch/main.cpp diff --git a/.gitignore b/.gitignore index 203ea98..37d6931 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ int/ +*.exe *.dll *.exp *.lib diff --git a/autoswitch/.sun b/autoswitch/.sun new file mode 100644 index 0000000..17547f9 --- /dev/null +++ b/autoswitch/.sun @@ -0,0 +1,2 @@ ++*.cpp +require ../../Soup/soup diff --git a/autoswitch/README.md b/autoswitch/README.md new file mode 100644 index 0000000..51532db --- /dev/null +++ b/autoswitch/README.md @@ -0,0 +1,14 @@ +## Automatic profile switcher for Wooting keyboards + +Automatically switches the profile on your Wooting keyboard based on if a game is focused and what state the game is in. + +### Profile Setup + +This program is made to "just work" with the factory state of Wooting keyboards: + +1. "Digital Profile" - No game active. +2. "Rapid Profile" - Unused by this program. +3. "Racing Profile" - Used for "in vehicle" contexts: W and S are mapped to RT and LT. A and D are mapped to LSTICK LEFT and LSTICK RIGHT. "Gamepad mapping override" is enabled. +4. "Mixed Movement" - Used for most game contexts: WASD is mapped to LSTICK directional inputs. "Gamepad mapping override" is enabled. + +However, note that the default state of Wooting keyboards has "Gamepad Mode" set to "No Gamepad", so do be sure to change this so it can be recognised as a controller. diff --git a/autoswitch/main.cpp b/autoswitch/main.cpp new file mode 100644 index 0000000..73f9e3a --- /dev/null +++ b/autoswitch/main.cpp @@ -0,0 +1,150 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace soup; + +static DWORD prev_focus_pid = -1; +static UniquePtr proc; +static std::shared_ptr mod; +static DelayedCtor fib; +static bool fib_ret; + +#define YIELD_VALUE(x) fib_ret = x; Fiber::current()->yield(); + +[[nodiscard]] static bool isAppropriateGameProcess(const std::string& name) +{ + switch (joaat::hash(name)) + { + case joaat::hash("Cyberpunk2077.exe"): + case joaat::hash("Warframe.x64.exe"): + return true; + } + return false; +} + +[[nodiscard]] static bool isInVehicleContext() +{ + if (proc->name == "Cyberpunk2077.exe") + { + if (!fib.isConstructed()) + { + fib.construct([](Capture&&) + { + auto func = mod->externalScan(Pattern("48 89 5C 24 10 4C 89 74 24 18 48 89 4C 24 08 55")); + auto player_info = func.add((0x0000000140F886F9 - 0x0000000140F88678) + 3).externalRip(*mod); + while (true) + { + if (Pointer player_ptr = mod->externalRead(player_info.add(0x10))) + { + if (Pointer player_ped_ptr = mod->externalRead(player_ptr.add(0x5B0))) + { + if (Pointer vehicle_ptr = mod->externalRead(player_ped_ptr.add(0x90))) + { + YIELD_VALUE(true); + continue; + } + } + } + YIELD_VALUE(false); + } + }); + } + } + + if (fib) + { + fib->run(); + return fib_ret; + } + return false; +} + +[[nodiscard]] static uint8_t getAppropriateProfile() +{ + DWORD focus_pid = Window::getFocused().getOwnerPid(); + if (focus_pid != prev_focus_pid) + { + prev_focus_pid = focus_pid; + proc = Process::get(focus_pid); + if (isAppropriateGameProcess(proc->name)) + { + mod = proc->open();; + std::cout << "Appropriate game process detected: " << proc->name << "\n"; + } + else + { + if (mod) + { + mod.reset(); + fib.reset(); + std::cout << "Game process no longer active/focused\n"; + } + } + } + + if (mod) + { + if (isInVehicleContext()) + { + return 2; + } + return 3; + } + return 0; +} + +static void sendProfileSwitchToHardware(uint8_t profile) +{ + for (auto& _kbd : kbRgb::getAll(false)) + { + if (_kbd->isWooting()) + { + auto kbd = _kbd->asWooting(); + if (!kbd->isUwu()) + { + std::cout << "Sending report to " << kbd->name << "..."; + { + Buffer buf(8); + buf.push_back(/* 0 */ 0); // HID report index + buf.push_back(/* 1 */ 0xD0); // Magic word + buf.push_back(/* 2 */ 0xDA); // Magic word + buf.push_back(/* 3 */ (uint8_t)WootingCommand::ActivateProfile); + buf.push_back(/* 4 */ profile); + buf.push_back(/* 5 */ 0); + buf.push_back(/* 6 */ 0); + buf.push_back(/* 7 */ 0); + kbd->hid.sendFeatureReport(std::move(buf)); + } + SOUP_UNUSED(kbd->hid.receiveReport()); + std::cout << " Success.\n"; + } + } + } +} + +int main() +{ + uint8_t profile = -1; + while (true) + { + auto appropriate_profile = getAppropriateProfile(); + if (appropriate_profile != profile) + { + profile = appropriate_profile; + std::cout << "Switching to profile " << (int)(profile + 1) << "\n"; + sendProfileSwitchToHardware(profile); + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } +}