Last active
August 6, 2025 10:44
-
-
Save aidnzz/1e19829efa615d64c32b0747bd4af482 to your computer and use it in GitHub Desktop.
Injecting raw input into roblox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #define NOMINMAX | |
| #include <mutex> | |
| #include <string_view> | |
| #include <windows.h> | |
| #include "minhook.h" | |
| #pragma comment(lib, "libminhook-x86") | |
| class Haze | |
| { | |
| public: | |
| using DefWindowProcW_t = std::add_pointer_t<decltype(::DefWindowProcW)>; | |
| using GetRawInputData_t = std::add_pointer_t<decltype(::GetRawInputData)>; | |
| enum Type : UINT | |
| { | |
| BASE = WM_APP, | |
| START, | |
| DISABLE, | |
| SHOW, | |
| HIDE | |
| }; | |
| Haze(const std::wstring_view window) noexcept | |
| : m_hwnd(::FindWindowW(nullptr, window.data())) {} | |
| [[nodiscard]] bool install() noexcept | |
| { | |
| DefWindowProcW = reinterpret_cast<DefWindowProcW_t>(SetWindowLongPtr(m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG>(hook))); | |
| return DefWindowProcW && MH_Initialize() == MH_OK; | |
| } | |
| operator HWND() const noexcept { return m_hwnd; } | |
| private: | |
| static __declspec(noinline) HWND WINAPI DetourGetFocus() noexcept | |
| { | |
| static auto window = FindWindowW(nullptr, L"Roblox"); | |
| return window; | |
| } | |
| static UINT WINAPI DetourGetRawInputData(HRAWINPUT input, UINT command, PRAWINPUT data, PUINT size, UINT header_size) noexcept | |
| { | |
| static unsigned long current = RI_MOUSE_LEFT_BUTTON_DOWN; | |
| static unsigned long next = RI_MOUSE_LEFT_BUTTON_UP; | |
| // Faked input header | |
| const RAWINPUT buffer{.header=RAWINPUTHEADER{.dwSize=sizeof(buffer)}, .data=RAWMOUSE{.ulButtons=current}}; | |
| // Emulated Input | |
| if (!input) | |
| { | |
| if (!data) | |
| { | |
| *size = sizeof(buffer); | |
| return 0u; | |
| } | |
| std::memcpy(data, &buffer, sizeof(buffer)); | |
| std::swap(current, next); | |
| return sizeof(buffer); | |
| } | |
| const auto status = GetRawInputData(input, command, data, size, header_size); | |
| if (data && data->header.wParam == 0u && data->header.dwType == RIM_TYPEMOUSE) | |
| { | |
| if (data->data.mouse.ulButtons == RI_MOUSE_LEFT_BUTTON_DOWN || data->data.mouse.ulButtons == RI_MOUSE_LEFT_BUTTON_UP) | |
| return std::numeric_limits<size_t>::max(); | |
| } | |
| return status; | |
| } | |
| static LRESULT WINAPI hook(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
| { | |
| static std::once_flag flag; | |
| std::call_once(flag, [] { | |
| MH_CreateHookApi(L"user32", "GetFocus", DetourGetFocus, nullptr); | |
| MH_CreateHookApi(L"user32", "GetRawInputData", DetourGetRawInputData, reinterpret_cast<void**>(&GetRawInputData)); | |
| }); | |
| switch (msg) | |
| { | |
| case START: | |
| MH_EnableHook(MH_ALL_HOOKS); | |
| break; | |
| case DISABLE: | |
| MH_DisableHook(MH_ALL_HOOKS); | |
| break; | |
| case SHOW: | |
| ShowWindow(hwnd, SW_NORMAL); | |
| break; | |
| case HIDE: | |
| ShowWindow(hwnd, SW_HIDE); | |
| break; | |
| } | |
| return ::CallWindowProcW(DefWindowProcW, hwnd, msg, wparam, lparam); | |
| } | |
| HWND m_hwnd; | |
| inline static DefWindowProcW_t DefWindowProcW; | |
| inline static GetRawInputData_t GetRawInputData; | |
| }; | |
| BOOL APIENTRY DllMain([[maybe_unused]] HMODULE module, DWORD reason, [[maybe_unused]] LPVOID reserved) | |
| { | |
| if (reason == DLL_PROCESS_ATTACH) | |
| { | |
| if (Haze haze{L"Roblox"}; haze.install()) | |
| { | |
| for (;;Sleep(100)) | |
| PostMessageW(haze, WM_INPUT, 0u, 0u); | |
| } | |
| MessageBoxW(nullptr, L"Failed to install hooks", L"Haze", MB_ICONERROR); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment