199 lines
4.8 KiB
C++
199 lines
4.8 KiB
C++
#include <std_include.hpp>
|
|
#include "loader/component_loader.hpp"
|
|
|
|
#include "game/game.hpp"
|
|
#include "game/dvars.hpp"
|
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include <hidusage.h>
|
|
|
|
namespace raw_mouse
|
|
{
|
|
namespace
|
|
{
|
|
int mouse_raw_x = 0;
|
|
int mouse_raw_y = 0;
|
|
const game::dvar_t* cl_rawInput = nullptr;
|
|
|
|
LRESULT wnd_proc_hook(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
if (msg == WM_INPUT)
|
|
{
|
|
std::uint32_t size = sizeof(RAWINPUT);
|
|
static BYTE lpb[sizeof(RAWINPUT)];
|
|
|
|
GetRawInputData(
|
|
reinterpret_cast<HRAWINPUT>(lparam),
|
|
RID_INPUT, lpb, &size,
|
|
sizeof(RAWINPUTHEADER)
|
|
);
|
|
|
|
auto* raw = reinterpret_cast<RAWINPUT*>(lpb);
|
|
if (raw->header.dwType == RIM_TYPEMOUSE)
|
|
{
|
|
// Is there's really absolute mouse on earth?
|
|
if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
|
|
{
|
|
mouse_raw_x = raw->data.mouse.lLastX;
|
|
mouse_raw_y = raw->data.mouse.lLastY;
|
|
}
|
|
else
|
|
{
|
|
mouse_raw_x += raw->data.mouse.lLastX;
|
|
mouse_raw_y += raw->data.mouse.lLastY;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return game::MainWndProc(hwnd, msg, wparam, lparam);
|
|
}
|
|
|
|
void in_clamp_mouse_move(tagPOINT ¤t_position)
|
|
{
|
|
tagRECT rc;
|
|
GetWindowRect(game::g_wv->hWnd, &rc);
|
|
|
|
auto is_clamped = false;
|
|
if (current_position.x >= rc.left)
|
|
{
|
|
if (current_position.x >= rc.right)
|
|
{
|
|
current_position.x = rc.right - 1;
|
|
is_clamped = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
current_position.x = rc.left;
|
|
is_clamped = true;
|
|
}
|
|
if (current_position.y >= rc.top)
|
|
{
|
|
if (current_position.y >= rc.bottom)
|
|
{
|
|
current_position.y = rc.bottom - 1;
|
|
is_clamped = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
current_position.y = rc.top;
|
|
is_clamped = true;
|
|
}
|
|
|
|
if (is_clamped)
|
|
{
|
|
SetCursorPos(current_position.x, current_position.y);
|
|
}
|
|
}
|
|
|
|
void in_raw_mouse_move()
|
|
{
|
|
static const auto* r_displayMode = game::Dvar_FindVar("r_displayMode");
|
|
|
|
if (GetForegroundWindow() == game::g_wv->hWnd)
|
|
{
|
|
static tagPOINT current_position;
|
|
GetCursorPos(¤t_position);
|
|
|
|
// is fullscreen
|
|
if (r_displayMode->current.integer == 0)
|
|
{
|
|
in_clamp_mouse_move(current_position);
|
|
}
|
|
|
|
static auto old_x = 0, old_y = 0;
|
|
|
|
const auto need_reset = game::s_wmv->oldPos.x == -100000;
|
|
|
|
const auto delta_x = need_reset ? 0 : mouse_raw_x - old_x;
|
|
const auto delta_y = need_reset ? 0 : mouse_raw_y - old_y;
|
|
|
|
old_x = mouse_raw_x;
|
|
old_y = mouse_raw_y;
|
|
|
|
game::s_wmv->oldPos = current_position;
|
|
ScreenToClient(game::g_wv->hWnd, ¤t_position);
|
|
|
|
current_position.x = current_position.x * game::vidConfigOut->displayWidth / game::vidConfigOut->monitorWidth;
|
|
current_position.y = current_position.y * game::vidConfigOut->displayHeight / game::vidConfigOut->monitorHeight;
|
|
|
|
game::g_wv->recenterMouse = game::CL_MouseEvent(current_position.x, current_position.y, delta_x, delta_y);
|
|
|
|
if (game::g_wv->recenterMouse && (delta_x || delta_y || need_reset))
|
|
{
|
|
game::IN_RecenterMouse();
|
|
}
|
|
}
|
|
}
|
|
|
|
void in_mouse_move()
|
|
{
|
|
if (cl_rawInput->current.enabled)
|
|
{
|
|
in_raw_mouse_move();
|
|
}
|
|
else
|
|
{
|
|
game::IN_MouseMove();
|
|
}
|
|
}
|
|
|
|
void in_raw_mouse_init(HWND hwnd)
|
|
{
|
|
RAWINPUTDEVICE rid[1];
|
|
rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
|
|
rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
|
|
rid[0].dwFlags = RIDEV_INPUTSINK;
|
|
rid[0].hwndTarget = hwnd;
|
|
|
|
RegisterRawInputDevices(rid, ARRAYSIZE(rid), sizeof(rid[0]));
|
|
}
|
|
|
|
HWND CALLBACK create_window_ex_a_stub(DWORD dw_ex_style, LPCSTR lp_class_name, LPCSTR lp_window_name,
|
|
DWORD dw_style, int x, int y, int n_width, int n_height, HWND h_wnd_parent, HMENU h_menu, HINSTANCE h_instance, LPVOID lp_param)
|
|
{
|
|
const auto hwnd = CreateWindowExA(dw_ex_style, lp_class_name, lp_window_name,
|
|
dw_style, x, y, n_width, n_height, h_wnd_parent, h_menu, h_instance, lp_param);
|
|
|
|
in_raw_mouse_init(hwnd);
|
|
|
|
return hwnd;
|
|
}
|
|
|
|
ATOM CALLBACK register_class_ex_a_stub(WNDCLASSEXA* wnd_class)
|
|
{
|
|
wnd_class->lpfnWndProc = wnd_proc_hook;
|
|
return RegisterClassExA(wnd_class);
|
|
}
|
|
}
|
|
|
|
class component final : public component_interface
|
|
{
|
|
public:
|
|
void post_unpack() override
|
|
{
|
|
if (game::environment::is_dedi())
|
|
{
|
|
return;
|
|
}
|
|
|
|
utils::hook::call(SELECT_VALUE(0x14043845F, 0x1404FC3FB), &in_mouse_move);
|
|
|
|
utils::hook::call(SELECT_VALUE(0x140519F71, 0x1405E69A1), &create_window_ex_a_stub);
|
|
utils::hook::set<std::uint8_t>(SELECT_VALUE(0x140519F76, 0x1405E69A6), 0x90);
|
|
|
|
utils::hook::call(SELECT_VALUE(0x14043BF04, 0x140500824), ®ister_class_ex_a_stub);
|
|
utils::hook::set<std::uint8_t>(SELECT_VALUE(0x14043BF09, 0x140500829), 0x90);
|
|
|
|
cl_rawInput = game::Dvar_RegisterBool("cl_rawInput", true,
|
|
game::DVAR_FLAG_SAVED, "Use Raw Input for mouse input. This fixes mouse acceleration issue");
|
|
}
|
|
};
|
|
}
|
|
|
|
REGISTER_COMPONENT(raw_mouse::component)
|