2022-02-27 07:53:44 -05:00
|
|
|
#include <STDInclude.hpp>
|
2017-01-19 16:23:59 -05:00
|
|
|
|
2023-01-03 07:16:44 -05:00
|
|
|
#include "FastFiles.hpp"
|
|
|
|
|
2017-01-19 16:23:59 -05:00
|
|
|
namespace Components
|
|
|
|
{
|
|
|
|
Dvar::Var Window::NoBorder;
|
|
|
|
Dvar::Var Window::NativeCursor;
|
|
|
|
|
2017-01-20 16:41:03 -05:00
|
|
|
HWND Window::MainWindow = nullptr;
|
2017-01-19 16:23:59 -05:00
|
|
|
BOOL Window::CursorVisible = TRUE;
|
2022-04-29 10:26:14 -04:00
|
|
|
std::unordered_map<UINT, Utils::Slot<Window::WndProcCallback>> Window::WndMessageCallbacks;
|
|
|
|
Utils::Signal<Window::CreateCallback> Window::CreateSignals;
|
2017-01-19 16:23:59 -05:00
|
|
|
|
|
|
|
int Window::Width()
|
|
|
|
{
|
|
|
|
return Window::Width(Window::MainWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window::Height()
|
|
|
|
{
|
|
|
|
return Window::Height(Window::MainWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window::Width(HWND window)
|
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
Window::Dimension(window, &rect);
|
|
|
|
return (rect.right - rect.left);
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window::Height(HWND window)
|
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
Window::Dimension(window, &rect);
|
|
|
|
return (rect.bottom - rect.top);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::Dimension(RECT* rect)
|
|
|
|
{
|
|
|
|
Window::Dimension(Window::MainWindow, rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::Dimension(HWND window, RECT* rect)
|
|
|
|
{
|
|
|
|
if (rect)
|
|
|
|
{
|
|
|
|
ZeroMemory(rect, sizeof(RECT));
|
|
|
|
|
|
|
|
if (window && IsWindow(window))
|
|
|
|
{
|
|
|
|
GetWindowRect(window, rect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::IsCursorWithin(HWND window)
|
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
POINT point;
|
|
|
|
Window::Dimension(window, &rect);
|
|
|
|
|
|
|
|
GetCursorPos(&point);
|
|
|
|
|
|
|
|
return ((point.x - rect.left) > 0 && (point.y - rect.top) > 0 && (rect.right - point.x) > 0 && (rect.bottom - point.y) > 0);
|
|
|
|
}
|
|
|
|
|
2017-02-10 03:50:08 -05:00
|
|
|
HWND Window::GetWindow()
|
|
|
|
{
|
|
|
|
return Window::MainWindow;
|
|
|
|
}
|
|
|
|
|
2022-04-29 10:26:14 -04:00
|
|
|
void Window::OnWndMessage(UINT Msg, Utils::Slot<Window::WndProcCallback> callback)
|
|
|
|
{
|
|
|
|
WndMessageCallbacks.emplace(Msg, callback);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::OnCreate(Utils::Slot<CreateCallback> callback)
|
|
|
|
{
|
|
|
|
CreateSignals.connect(callback);
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:23:59 -05:00
|
|
|
int Window::IsNoBorder()
|
|
|
|
{
|
|
|
|
return Window::NoBorder.get<bool>();
|
|
|
|
}
|
|
|
|
|
|
|
|
__declspec(naked) void Window::StyleHookStub()
|
|
|
|
{
|
|
|
|
__asm
|
|
|
|
{
|
|
|
|
call Window::IsNoBorder
|
|
|
|
test al, al
|
|
|
|
jz setBorder
|
|
|
|
|
|
|
|
mov ebp, WS_VISIBLE | WS_POPUP
|
|
|
|
retn
|
|
|
|
|
|
|
|
setBorder:
|
|
|
|
mov ebp, WS_VISIBLE | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX
|
|
|
|
retn
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-15 08:50:22 -04:00
|
|
|
void Window::DrawCursorStub(Game::ScreenPlacement* scrPlace, float x, float y, float w, float h, int horzAlign, int vertAlign, const float* color, Game::Material* material)
|
2017-01-19 16:23:59 -05:00
|
|
|
{
|
|
|
|
if (Window::NativeCursor.get<bool>())
|
|
|
|
{
|
|
|
|
Window::CursorVisible = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Game::UI_DrawHandlePic(scrPlace, x, y, w, h, horzAlign, vertAlign, color, material);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI Window::ShowCursorHook(BOOL show)
|
|
|
|
{
|
|
|
|
if (Window::NativeCursor.get<bool>() && IsWindow(Window::MainWindow) && GetForegroundWindow() == Window::MainWindow && Window::IsCursorWithin(Window::MainWindow))
|
|
|
|
{
|
|
|
|
static int count = 0;
|
|
|
|
(show ? ++count : --count);
|
|
|
|
|
|
|
|
if (count >= 0)
|
|
|
|
{
|
|
|
|
Window::CursorVisible = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ShowCursor(show);
|
|
|
|
}
|
|
|
|
|
|
|
|
HWND WINAPI Window::CreateMainWindow(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam)
|
|
|
|
{
|
|
|
|
Window::MainWindow = CreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
|
2022-04-29 10:26:14 -04:00
|
|
|
|
|
|
|
CreateSignals();
|
|
|
|
|
2017-01-19 16:23:59 -05:00
|
|
|
return Window::MainWindow;
|
|
|
|
}
|
|
|
|
|
2017-06-06 16:13:08 -04:00
|
|
|
void Window::ApplyCursor()
|
|
|
|
{
|
|
|
|
bool isLoading = !FastFiles::Ready();
|
2017-06-11 15:25:18 -04:00
|
|
|
SetCursor(LoadCursor(nullptr, isLoading ? IDC_APPSTARTING : IDC_ARROW));
|
2017-06-06 16:13:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI Window::MessageHandler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2022-04-29 13:42:47 -04:00
|
|
|
if (const auto cb = WndMessageCallbacks.find(Msg); cb != WndMessageCallbacks.end())
|
2017-06-06 16:13:08 -04:00
|
|
|
{
|
2022-04-29 13:42:47 -04:00
|
|
|
return cb->second(lParam, wParam);
|
2017-06-06 16:13:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return Utils::Hook::Call<BOOL(__stdcall)(HWND, UINT, WPARAM, LPARAM)>(0x4731F0)(hWnd, Msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
2022-04-29 10:26:14 -04:00
|
|
|
void Window::EnableDpiAwareness()
|
|
|
|
{
|
2022-05-02 22:11:02 -04:00
|
|
|
const Utils::Library user32{"user32.dll"};
|
2022-04-29 10:26:14 -04:00
|
|
|
|
|
|
|
user32.invokePascal<void>("SetProcessDpiAwarenessContext", DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
|
|
|
}
|
|
|
|
|
2017-01-19 16:23:59 -05:00
|
|
|
Window::Window()
|
|
|
|
{
|
|
|
|
// Borderless window
|
2022-07-02 13:52:57 -04:00
|
|
|
Window::NoBorder = Dvar::Register<bool>("r_noborder", true, Game::DVAR_ARCHIVE, "Do not use a border in windowed mode");
|
|
|
|
Window::NativeCursor = Dvar::Register<bool>("ui_nativeCursor", false, Game::DVAR_ARCHIVE, "Display native cursor");
|
2017-01-19 16:23:59 -05:00
|
|
|
|
|
|
|
Utils::Hook(0x507643, Window::StyleHookStub, HOOK_CALL).install()->quick();
|
|
|
|
|
|
|
|
// Main window creation
|
|
|
|
Utils::Hook::Nop(0x5076AA, 1);
|
|
|
|
Utils::Hook(0x5076AB, Window::CreateMainWindow, HOOK_CALL).install()->quick();
|
|
|
|
|
|
|
|
// Mark the cursor as visible
|
|
|
|
Utils::Hook(0x48E5D3, Window::DrawCursorStub, HOOK_CALL).install()->quick();
|
|
|
|
|
|
|
|
// Draw the cursor if necessary
|
2022-05-05 10:03:14 -04:00
|
|
|
Scheduler::Loop([]
|
2017-01-19 16:23:59 -05:00
|
|
|
{
|
|
|
|
if (Window::NativeCursor.get<bool>() && IsWindow(Window::MainWindow) && GetForegroundWindow() == Window::MainWindow && Window::IsCursorWithin(Window::MainWindow))
|
|
|
|
{
|
|
|
|
int value = 0;
|
2017-06-06 16:13:08 -04:00
|
|
|
Window::ApplyCursor();
|
2017-01-19 16:23:59 -05:00
|
|
|
|
|
|
|
if (Window::CursorVisible)
|
|
|
|
{
|
2017-01-20 16:41:03 -05:00
|
|
|
while ((value = ShowCursor(TRUE)) < 0) {};
|
2017-01-19 16:23:59 -05:00
|
|
|
while (value > 0) { value = ShowCursor(FALSE); } // Set display counter to 0
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-01-20 16:41:03 -05:00
|
|
|
while ((value = ShowCursor(FALSE)) >= 0) {};
|
2017-01-19 16:23:59 -05:00
|
|
|
while (value < -1) { value = ShowCursor(TRUE); } // Set display counter to -1
|
|
|
|
}
|
|
|
|
|
|
|
|
Window::CursorVisible = FALSE;
|
|
|
|
}
|
2022-05-05 10:03:14 -04:00
|
|
|
}, Scheduler::Pipeline::RENDERER);
|
2017-01-19 16:23:59 -05:00
|
|
|
|
|
|
|
// Don't let the game interact with the native cursor
|
|
|
|
Utils::Hook::Set(0x6D7348, Window::ShowCursorHook);
|
2017-06-06 16:13:08 -04:00
|
|
|
|
|
|
|
// Use custom message handler
|
|
|
|
Utils::Hook::Set(0x64D298, Window::MessageHandler);
|
2022-04-29 10:26:14 -04:00
|
|
|
|
|
|
|
Window::OnWndMessage(WM_SETCURSOR, [](WPARAM, LPARAM)
|
|
|
|
{
|
|
|
|
Window::ApplyCursor();
|
|
|
|
return TRUE;
|
|
|
|
});
|
|
|
|
|
|
|
|
Window::EnableDpiAwareness();
|
2017-01-19 16:23:59 -05:00
|
|
|
}
|
|
|
|
}
|