LRESULT CALLBACK DetourWindowProc ( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { // Block keyboard input to the game while the console is visible if (uMsg == WM_INPUT && ad::InputManager::Hooker::getInstance ()->isVisible ()) return 0; // Allow the game to run in the background if (uMsg == WM_ACTIVATEAPP) { bool last_active = window.active; window.active = wParam; // // The window activation state is changing, among other things we can take // this opportunity to setup a special framerate limit. // if (window.active != last_active) { eTB_CommandProcessor* pCommandProc = SK_GetCommandProcessor (); #if 0 eTB_CommandResult result = pCommandProc->ProcessCommandLine ("TargetFPS"); eTB_VarStub <float>* pOriginalLimit = (eTB_VarStub <float>*)result.getVariable (); #endif // Went from active to inactive (enforce background limit) if (! window.active) pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.render.background_fps); // Went from inactive to active (restore foreground limit) else pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.render.foreground_fps); } // Unrestrict the mouse when the app is deactivated if ((! window.active) && config.render.allow_background) { LONG dwStyle = GetWindowLong (ad::RenderFix::hWndDevice, GWL_STYLE); LONG dwStyleEx = GetWindowLong (ad::RenderFix::hWndDevice, GWL_EXSTYLE); dwStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU); dwStyleEx &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); SetWindowLong (ad::RenderFix::hWndDevice, GWL_STYLE, dwStyle); SetWindowLong (ad::RenderFix::hWndDevice, GWL_EXSTYLE, dwStyleEx); SetWindowPos ( ad::RenderFix::hWndDevice, NULL, 0,0,ad::RenderFix::width,ad::RenderFix::height, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOOWNERZORDER ); ClipCursor_Original (nullptr); } // Restore it when the app is activated else { ClipCursor_Original (&window.cursor_clip); } if (config.render.allow_background) { CallWindowProc (original_wndproc, hWnd, uMsg, FALSE, ad::RenderFix::dwRenderThreadID); CallWindowProc (original_wndproc, hWnd, uMsg, TRUE, ad::RenderFix::dwRenderThreadID); //window.activating = true; return 0; } } // Don't let the game do anything with the mouse or keyboard when // the game is not active if (config.render.allow_background) { if ((! window.active) && uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) return 0; if ((! window.active) && uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST) return 0; } if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) { static POINT last_p = { LONG_MIN, LONG_MIN }; POINT p; p.x = MAKEPOINTS (lParam).x; p.y = MAKEPOINTS (lParam).y; if (/*game_state.needsFixedMouseCoords () &&*/config.render.aspect_correction) { // Only do this if cursor actually moved! // // Otherwise, it tricks the game into thinking the input device changed // from gamepad to mouse (and changes buessagetton icons). if (last_p.x != p.x || last_p.y != p.y) { ad::InputManager::CalcCursorPos (&p); last_p = p; } return CallWindowProc (original_wndproc, hWnd, uMsg, wParam, MAKELPARAM (p.x, p.y)); } last_p = p; } return CallWindowProc (original_wndproc, hWnd, uMsg, wParam, lParam); }
LRESULT CALLBACK DetourWindowProc ( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam ) { bool last_active = pp::window.active; pp::window.active = GetForegroundWindow_Original () == pp::window.hwnd/* || GetForegroundWindow_Original () == nullptr*/; bool console_visible = pp::InputManager::Hooker::getInstance ()->isVisible (); bool background_render = config.render.allow_background && (! pp::window.active); // // The window activation state is changing, among other things we can take // this opportunity to setup a special framerate limit. // if (pp::window.active != last_active) { eTB_CommandProcessor* pCommandProc = SK_GetCommandProcessor (); #if 0 eTB_CommandResult result = pCommandProc->ProcessCommandLine ("TargetFPS"); eTB_VarStub <float>* pOriginalLimit = (eTB_VarStub <float>*)result.getVariable (); #endif #if 0 // Went from active to inactive (enforce background limit) if (! pp::window.active) pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.window.background_fps); // Went from inactive to active (restore foreground limit) else { pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.window.foreground_fps); } #endif #if 0 // Unrestrict the mouse when the app is deactivated if ((! pp::window.active) && config.render.allow_background) { ClipCursor_Original (nullptr); SetCursorPos (pp::window.cursor_pos.x, pp::window.cursor_pos.y); ShowCursor (TRUE); } // Restore it when the app is activated else { GetCursorPos (&pp::window.cursor_pos); ShowCursor (FALSE); ClipCursor_Original (&pp::window.cursor_clip); } #endif } #if 0 // Ignore this event if (uMsg == WM_MOUSEACTIVATE && config.render.allow_background) { return DefWindowProc (hWnd, uMsg, wParam, lParam); } // Allow the game to run in the background if (uMsg == WM_ACTIVATEAPP || uMsg == WM_ACTIVATE || uMsg == WM_NCACTIVATE /*|| uMsg == WM_MOUSEACTIVATE*/) { if (config.render.allow_background) { // We must fully consume one of these messages or audio will stop playing // when the game loses focus, so do not simply pass this through to the // default window procedure. return 0;//DefWindowProc (hWnd, uMsg, wParam, lParam); } } #endif // Block keyboard input to the game while the console is visible if (console_visible/* || background_render*/) { // Only prevent the mouse from working while the window is in the bg //if (background_render && uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST) //return DefWindowProc (hWnd, uMsg, wParam, lParam); if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST) return DefWindowProc (hWnd, uMsg, wParam, lParam); // Block RAW Input if (uMsg == WM_INPUT) return DefWindowProc (hWnd, uMsg, wParam, lParam); } #if 0 // Block the menu key from messing with stuff* if (config.input.block_left_alt && (uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP)) { // Make an exception for Alt+Enter, for fullscreen mode toggle. // F4 as well for exit if (wParam != VK_RETURN && wParam != VK_F4) return DefWindowProc (hWnd, uMsg, wParam, lParam); } #endif // What an ugly mess, this is crazy :) if (config.input.cursor_mgmt) { extern bool IsControllerPluggedIn (UINT uJoyID); struct { POINTS pos = { 0 }; // POINT (Short) - Not POINT plural ;) DWORD sampled = 0UL; bool cursor = true; int init = false; int timer_id = 0x68992; } static last_mouse; auto ActivateCursor = [](bool changed = false)-> bool { bool was_active = last_mouse.cursor; if (! last_mouse.cursor) { while (ShowCursor (TRUE) < 0) ; last_mouse.cursor = true; } if (changed) last_mouse.sampled = timeGetTime (); return (last_mouse.cursor != was_active); }; auto DeactivateCursor = []()-> bool { if (! last_mouse.cursor) return false; bool was_active = last_mouse.cursor; if (last_mouse.sampled <= timeGetTime () - config.input.cursor_timeout) { while (ShowCursor (FALSE) >= 0) ; last_mouse.cursor = false; } return (last_mouse.cursor != was_active); }; if (! last_mouse.init) { SetTimer (hWnd, last_mouse.timer_id, config.input.cursor_timeout / 2, nullptr); last_mouse.init = true; } bool activation_event = (uMsg == WM_MOUSEMOVE); // Don't blindly accept that WM_MOUSEMOVE actually means the mouse moved... if (activation_event) { const short threshold = 2; // Filter out small movements if ( abs (last_mouse.pos.x - GET_X_LPARAM (lParam)) < threshold && abs (last_mouse.pos.y - GET_Y_LPARAM (lParam)) < threshold ) activation_event = false; last_mouse.pos = MAKEPOINTS (lParam); } // We cannot use WM_KEYDOWN as a condition, because the game is constantly // flooding the message pump with this message !!! if (config.input.activate_on_kbd) activation_event |= ( uMsg == WM_CHAR || uMsg == WM_SYSKEYDOWN || uMsg == WM_SYSKEYUP ); if (activation_event) ActivateCursor (true); else if (uMsg == WM_TIMER && wParam == last_mouse.timer_id) { if (IsControllerPluggedIn (config.input.gamepad_slot)) DeactivateCursor (); else ActivateCursor (); } } #if 0 // The game can process WM_CHAR, rather than these events that // fire at a ridiculous rate... if (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST && uMsg != WM_CHAR) return 0; #endif // // This isn't much better than what NISA was already doing // with their keybd_event spam. // if (config.input.alias_wasd && (uMsg == WM_KEYDOWN || uMsg == WM_KEYUP)) { DWORD dwFlags = (uMsg == WM_KEYUP ? KEYEVENTF_KEYUP : 0UL); switch (wParam) { case VK_UP: keybd_event_Original ('W', 0, dwFlags, (ULONG_PTR)nullptr); break; case VK_DOWN: keybd_event_Original ('S', 0, dwFlags, (ULONG_PTR)nullptr); break; case VK_LEFT: keybd_event_Original ('A', 0, dwFlags, (ULONG_PTR)nullptr); break; case VK_RIGHT: keybd_event_Original ('D', 0, dwFlags, (ULONG_PTR)nullptr); break; } } return CallWindowProc (pp::window.WndProc_Original, hWnd, uMsg, wParam, lParam); }