ad::WindowManager::CommandProcessor::CommandProcessor (void) { foreground_fps_ = new eTB_VarStub <float> (&config.render.foreground_fps, this); background_fps_ = new eTB_VarStub <float> (&config.render.background_fps, this); eTB_CommandProcessor* pCommandProc = SK_GetCommandProcessor (); pCommandProc->AddVariable ("Window.BackgroundFPS", background_fps_); pCommandProc->AddVariable ("Window.ForegroundFPS", foreground_fps_); // If the user has an FPS limit preference, set it up now... pCommandProc->ProcessCommandFormatted ("TargetFPS %f", config.render.foreground_fps); }
bool pp::WindowManager:: CommandProcessor::OnVarChange (eTB_Variable* var, void* val) { eTB_CommandProcessor* pCommandProc = SK_GetCommandProcessor (); bool known = false; if (var == background_fps_) { known = true; // Range validation if (val != nullptr && *(float *)val >= 0.0f) { config.window.background_fps = *(float *)val; // How this was changed while the window was inactive is a bit of a // mystery, but whatever :P if ((! window.active)) pCommandProc->ProcessCommandFormatted ("TargetFPS %f", *(float *)val); return true; } } if (var == foreground_fps_) { known = true; // Range validation if (val != nullptr && *(float *)val >= 0.0f) { config.window.foreground_fps = *(float *)val; // Immediately apply limiter changes if (window.active) pCommandProc->ProcessCommandFormatted ("TargetFPS %f", *(float *)val); return true; } } if (! known) { dll_log.Log ( L"[Window Mgr] UNKNOWN Variable Changed (%p --> %p)", var, val ); } return false; }
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); }
void CALLBACK SK_TZF_PluginKeyPress ( BOOL Control, BOOL Shift, BOOL Alt, BYTE vkCode ) { SK_ICommandProcessor& command = *SK_GetCommandProcessor (); if (Control && Shift) { if (vkCode == '1') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 60"); command.ProcessCommandLine ("BattleFPS 60"); command.ProcessCommandLine ("CutsceneFPS 60"); command.ProcessCommandLine ("TickScale 1"); return; } else if (vkCode == '2') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 30"); command.ProcessCommandLine ("BattleFPS 30"); command.ProcessCommandLine ("CutsceneFPS 30"); command.ProcessCommandLine ("TickScale 2"); return; } else if (vkCode == '3') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 20"); command.ProcessCommandLine ("BattleFPS 20"); command.ProcessCommandLine ("CutsceneFPS 20"); command.ProcessCommandLine ("TickScale 3"); return; } else if (vkCode == '4') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 15"); command.ProcessCommandLine ("BattleFPS 15"); command.ProcessCommandLine ("CutsceneFPS 15"); command.ProcessCommandLine ("TickScale 4"); return; } else if (vkCode == '5') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 12"); command.ProcessCommandLine ("BattleFPS 12"); command.ProcessCommandLine ("CutsceneFPS 12"); command.ProcessCommandLine ("TickScale 5"); return; } else if (vkCode == '6') { command.ProcessCommandLine ("AutoAdjust false"); command.ProcessCommandLine ("TargetFPS 10"); command.ProcessCommandLine ("BattleFPS 10"); command.ProcessCommandLine ("CutsceneFPS 10"); command.ProcessCommandLine ("TickScale 6"); return; } else if (vkCode == '9') { command.ProcessCommandLine ("AutoAdjust true"); command.ProcessCommandLine ("TargetFPS 60"); command.ProcessCommandLine ("BattleFPS 60"); command.ProcessCommandLine ("CutsceneFPS 60"); command.ProcessCommandLine ("TickScale 1"); return; } else if (vkCode == VK_OEM_PERIOD) { command.ProcessCommandLine ("AutoAdjust true"); command.ProcessCommandLine ("TickScale 30"); return; } else if (vkCode == 'U') { command.ProcessCommandLine ("Textures.Remap toggle"); tzf::RenderFix::tex_mgr.updateOSD (); return; } else if (vkCode == 'Z') { command.ProcessCommandLine ("Textures.Purge true"); tzf::RenderFix::tex_mgr.updateOSD (); return; } else if (vkCode == 'X') { command.ProcessCommandLine ("Textures.Trace true"); tzf::RenderFix::tex_mgr.updateOSD (); return; } else if (vkCode == 'V') { command.ProcessCommandLine ("Textures.ShowCache toggle"); tzf::RenderFix::tex_mgr.updateOSD (); return; } else if (vkCode == VK_OEM_6) { extern std::vector <uint32_t> textures_used_last_dump; extern int tex_dbg_idx; ++tex_dbg_idx; if (tex_dbg_idx > textures_used_last_dump.size ()) tex_dbg_idx = textures_used_last_dump.size (); extern int debug_tex_id; debug_tex_id = (int)textures_used_last_dump [tex_dbg_idx]; tzf::RenderFix::tex_mgr.updateOSD (); return; } else if (vkCode == VK_OEM_4) { extern std::vector <uint32_t> textures_used_last_dump; extern int tex_dbg_idx; extern int debug_tex_id; --tex_dbg_idx; if (tex_dbg_idx < 0) { tex_dbg_idx = -1; debug_tex_id = 0; } else { if (tex_dbg_idx > textures_used_last_dump.size ()) tex_dbg_idx = textures_used_last_dump.size (); debug_tex_id = (int)textures_used_last_dump [tex_dbg_idx]; } tzf::RenderFix::tex_mgr.updateOSD (); return; } } SK_PluginKeyPress_Original (Control, Shift, Alt, vkCode); }