NoFocusLoss Changes
#define WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#define NOMINMAX
#include <Windows.h>
#include <Windows.h>
#include "MinHook.h"
#include "MinHook.h"
#include <TlHelp32.h>
#include <TlHelp32.h>
#pragma region GetMainWindow
#pragma region GetMainWindow
struct EnumWindowsCallbackArgs {
struct EnumWindowsCallbackArgs {
HWND hwnd = nullptr;
HWND hwnd = nullptr;
int area = -1;
int area = -1;
};
};
static BOOL CALLBACK EnumWindowsCallback(HWND hnd, LPARAM lParam) {
static BOOL CALLBACK EnumWindowsCallback(HWND hnd, LPARAM lParam) {
EnumWindowsCallbackArgs* args = (EnumWindowsCallbackArgs*)lParam;
EnumWindowsCallbackArgs* args = (EnumWindowsCallbackArgs*)lParam;
RECT rect = { 0 };
RECT rect = { 0 };
::GetWindowRect(hnd, &rect);
::GetWindowRect(hnd, &rect);
int area = (rect.right - rect.left) * (rect.bottom - rect.top);
int area = (rect.right - rect.left) * (rect.bottom - rect.top);
if (area > args->area) {
if (area > args->area) {
args->area = area;
args->area = area;
args->hwnd = hnd;
args->hwnd = hnd;
}
}
return true;
return true;
}
}
template<class _CB>
template<class _CB>
bool VisitProcessThreads(_CB visitor) {
bool VisitProcessThreads(_CB visitor) {
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (hThreadSnap == INVALID_HANDLE_VALUE) return false;
if (hThreadSnap == INVALID_HANDLE_VALUE) return false;
THREADENTRY32 te32;
THREADENTRY32 te32;
te32.dwSize = sizeof(THREADENTRY32);
te32.dwSize = sizeof(THREADENTRY32);
if (!Thread32First(hThreadSnap, &te32)) {
if (!Thread32First(hThreadSnap, &te32)) {
CloseHandle(hThreadSnap);
CloseHandle(hThreadSnap);
return false;
return false;
}
}
do {
do {
visitor(te32);
visitor(te32);
} while (Thread32Next(hThreadSnap, &te32));
} while (Thread32Next(hThreadSnap, &te32));
CloseHandle(hThreadSnap);
CloseHandle(hThreadSnap);
return true;
return true;
}
}
HWND GetMainWindow() {
HWND GetMainWindow() {
DWORD currentProcessId = ::GetCurrentProcessId();
DWORD currentProcessId = ::GetCurrentProcessId();
EnumWindowsCallbackArgs args{};
EnumWindowsCallbackArgs args{};
VisitProcessThreads([&](THREADENTRY32 threadEntry) {
VisitProcessThreads([&](THREADENTRY32 threadEntry) {
if (threadEntry.th32OwnerProcessID != currentProcessId) return;
if (threadEntry.th32OwnerProcessID != currentProcessId) return;
EnumThreadWindows(threadEntry.th32ThreadID, &EnumWindowsCallback, (LPARAM)&args);
EnumThreadWindows(threadEntry.th32ThreadID, &EnumWindowsCallback, (LPARAM)&args);
});
});
return args.hwnd;
return args.hwnd;
}
}
#pragma endregion
#pragma endregion
template <typename T>
template <typename T>
inline MH_STATUS MH_CreateHookEx(LPVOID pTarget, LPVOID pDetour, T** ppOriginal) {
inline MH_STATUS MH_CreateHookEx(LPVOID pTarget, LPVOID pDetour, T** ppOriginal) {
return MH_CreateHook(pTarget, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
return MH_CreateHook(pTarget, pDetour, reinterpret_cast<LPVOID*>(ppOriginal));
}
}
HWND hwnd;
HWND hwnd;
BOOL unfocused = FALSE;
BOOL unfocused = FALSE;
WNDPROC OldWndProc;
WNDPROC OldWndProc;
static decltype(GetForegroundWindow)* real_GetForegroundWindow = GetForegroundWindow;
static decltype(GetForegroundWindow)* real_GetForegroundWindow = GetForegroundWindow;
static decltype(SetCursorPos)* real_SetCursorPos = SetCursorPos;
static decltype(SetCursorPos)* real_SetCursorPos = SetCursorPos;
static decltype(ClipCursor)* real_ClipCursor = ClipCursor;
static decltype(ClipCursor)* real_ClipCursor = ClipCursor;
static decltype(GetCursorPos)* real_GetCursorPos = GetCursorPos;
static decltype(GetRawInputData)* real_GetRawInputData = GetRawInputData;
HWND WINAPI DetourGetForegroundWindow() {
HWND WINAPI DetourGetForegroundWindow() {
return hwnd;
return hwnd;
}
}
BOOL WINAPI DetourSetCursorPos(int X, int Y) {
BOOL WINAPI DetourSetCursorPos(int X, int Y) {
if (unfocused) return TRUE;
if (unfocused) return TRUE;
return real_SetCursorPos(X, Y);
return real_SetCursorPos(X, Y);
}
}
BOOL WINAPI DetourClipCursor(const RECT* lpRect) {
BOOL WINAPI DetourClipCursor(const RECT* lpRect) {
if (unfocused) return TRUE;
if (unfocused) return TRUE;
return real_ClipCursor(lpRect);
return real_ClipCursor(lpRect);
}
}
BOOL WINAPI DetourGetCursorPos(LPPOINT lpPoint) {
if (unfocused) {
lpPoint->x = 0;
lpPoint->y = 0;
return TRUE;
}
return real_GetCursorPos(lpPoint);
}
UINT WINAPI DetourGetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader) {
if (unfocused) {
// Suppress raw input by returning 0 bytes read
if (pcbSize) *pcbSize = 0;
return 0;
}
return real_GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
}
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_NCACTIVATE && wParam == TRUE) {
if (message == WM_NCACTIVATE && wParam == TRUE) {
unfocused = FALSE;
unfocused = FALSE;
}
}
else if (message == WM_NCACTIVATE && wParam == FALSE) {
else if (message == WM_NCACTIVATE && wParam == FALSE) {
unfocused = TRUE;
unfocused = TRUE;
return 0;
return 0;
}
}
else if (message == WM_ACTIVATE && wParam == WA_INACTIVE) {
else if (message == WM_ACTIVATE && wParam == WA_INACTIVE) {
return 0;
return 0;
}
}
else if (message == WM_ACTIVATEAPP && wParam == FALSE) {
else if (message == WM_ACTIVATEAPP && wParam == FALSE) {
return 0;
return 0;
}
}
else if (message == WM_KILLFOCUS) {
else if (message == WM_KILLFOCUS) {
return 0;
return 0;
}
}
else if (message == WM_IME_SETCONTEXT && wParam == FALSE) {
else if (message == WM_IME_SETCONTEXT && wParam == FALSE) {
return 0;
return 0;
}
}
return CallWindowProc(OldWndProc, hwnd, message, wParam, lParam);
return CallWindowProc(OldWndProc, hwnd, message, wParam, lParam);
}
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) {
BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved) {
switch (fdwReason) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH: {
case DLL_PROCESS_ATTACH: {
MH_Initialize();
MH_Initialize();
hwnd = GetMainWindow();
hwnd = GetMainWindow();
MH_CreateHookEx(GetForegroundWindow, DetourGetForegroundWindow, &real_GetForegroundWindow);
MH_CreateHookEx(GetForegroundWindow, DetourGetForegroundWindow, &real_GetForegroundWindow);
MH_CreateHookEx(SetCursorPos, DetourSetCursorPos, &real_SetCursorPos);
MH_CreateHookEx(SetCursorPos, DetourSetCursorPos, &real_SetCursorPos);
MH_CreateHookEx(ClipCursor, DetourClipCursor, &real_ClipCursor);
MH_CreateHookEx(ClipCursor, DetourClipCursor, &real_ClipCursor);
MH_CreateHookEx(GetCursorPos, DetourGetCursorPos, &real_GetCursorPos);
MH_CreateHookEx(GetRawInputData, DetourGetRawInputData, &real_GetRawInputData);
if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK) return FALSE;
if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK) return FALSE;
OldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
OldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
break;
break;
}
}
case DLL_PROCESS_DETACH: {
case DLL_PROCESS_DETACH: {
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)OldWndProc);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)OldWndProc);
MH_DisableHook(MH_ALL_HOOKS);
MH_DisableHook(MH_ALL_HOOKS);
MH_Uninitialize();
MH_Uninitialize();
break;
break;
}
}
}
}
return TRUE;
return TRUE;
}
}