Skip to content

Instantly share code, notes, and snippets.

@aidnzz
Last active August 6, 2025 10:44
Show Gist options
  • Select an option

  • Save aidnzz/1e19829efa615d64c32b0747bd4af482 to your computer and use it in GitHub Desktop.

Select an option

Save aidnzz/1e19829efa615d64c32b0747bd4af482 to your computer and use it in GitHub Desktop.
Injecting raw input into roblox
#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