From 256d60de58a1b10e498b66a4700ba48f3b1458ac Mon Sep 17 00:00:00 2001 From: Kaldaien Date: Sat, 4 Jun 2016 20:32:55 -0400 Subject: [PATCH] Flawless Fullscreen Mode --- UnX/UnX.vcxproj | 3 + UnX/cheat.cpp | 494 ++++++++++++++++++++++++++++++++--------------- UnX/input.cpp | 24 ++- UnX/language.cpp | 6 - UnX/timing.cpp | 30 ++- UnX/window.cpp | 163 +++++----------- 6 files changed, 433 insertions(+), 287 deletions(-) diff --git a/UnX/UnX.vcxproj b/UnX/UnX.vcxproj index 947abb0..27a9a3c 100644 --- a/UnX/UnX.vcxproj +++ b/UnX/UnX.vcxproj @@ -79,6 +79,8 @@ false C:\Program Files (x86)\Steam\steamapps\common\FINAL FANTASY FFX&FFX-2 HD Remaster\ unx + AllRules.ruleset + false false @@ -129,6 +131,7 @@ false true true + false Windows diff --git a/UnX/cheat.cpp b/UnX/cheat.cpp index d033c25..b5390cc 100644 --- a/UnX/cheat.cpp +++ b/UnX/cheat.cpp @@ -32,44 +32,214 @@ enum unx_gametype_t { GAME_FFX2 = 0x02 } game_type = GAME_INVALID; -enum Offsets_FFX { - OFFSET_PARTY_BASE = 0x0D32078, - OFFSET_IN_BATTLE = 0x1F10EA0, - OFFSET_GAINED_AP = 0x1F10EC4, - - OFFSET_PARTY_IS_MEMBER = 0x10 -}; - -enum Sizes_FFX { - SIZE_PARTY = 0x94 -}; - -struct unx_debug_ffx2_s { - uint8_t invincible_allies; // 0x9F78B8 - uint8_t invincible_enemies; // 0x9F78B9 - uint8_t unknown [4]; // 0x9F78BA - uint8_t control_enemies; // 0x9F78BE - uint8_t control_monsters; // 0x9F78BF - uint8_t unknown1 [5]; // 0x9F78C0 - uint8_t mp_zero; // 0x9F78C5 - uint8_t unknown2 [5]; // 0x9F78C6 - uint8_t always_critical; // 0x9F78CC - uint8_t critical; // 0x9F78CD - uint8_t probability_100; // 0x9F78CE - uint8_t unknown3 [2]; // 0x9F78CF - uint8_t damage_random; // 0x9F78D1 - uint8_t damage_1; // 0x9F78D2 - uint8_t damage_9999; // 0x9F78D3 - uint8_t damage_99999; // 0x9F78D4 - uint8_t rare_drop_100; // 0x9F78D5 - uint8_t exp_100x; // 0x9F78D6 - uint8_t gil_100x; // 0x9F78D7 - uint8_t unknown4; // 0x9F78D8 - uint8_t always_oversoul; // 0x9F78D9 - uint8_t unknown5 [10]; // 0x9F78DA - uint8_t first_attack; // 0x9F78E4 (0xFF = OFF) -} *ffx2_debug_flags = nullptr; +struct unx_ffx2_memory_s { + struct { + enum offset_t { + Debug = 0x9F78B8 + }; + } offsets; + + struct debug_s { + struct { + uint8_t allies; // 0x9F78B8 + uint8_t enemies; // 0x9F78B9 + } invincible; + + uint8_t unknown [4]; // 0x9F78BA + + struct { + uint8_t enemies; // 0x9F78BE + uint8_t monsters; // 0x9F78BF + } control; + + uint8_t unknown1 [5]; // 0x9F78C0 + + uint8_t mp_zero; // 0x9F78C5 + uint8_t unknown2 [5]; // 0x9F78C6 + + struct { + uint8_t always_critical; // 0x9F78CC + uint8_t critical; // 0x9F78CD + uint8_t probability_100; // 0x9F78CE + uint8_t unknown3 [2]; // 0x9F78CF + uint8_t damage_random; // 0x9F78D1 + uint8_t damage_1; // 0x9F78D2 + uint8_t damage_9999; // 0x9F78D3 + uint8_t damage_99999; // 0x9F78D4 + } damage; + + struct { + uint8_t always_drop_rare; // 0x9F78D5 + uint8_t exp_100x; // 0x9F78D6 + uint8_t gil_100x; // 0x9F78D7 + } reward; + + uint8_t unknown4; // 0x9F78D8 + + uint8_t always_oversoul; // 0x9F78D9 + + uint8_t unknown5 [10]; // 0x9F78DA + + uint8_t first_attack; // 0x9F78E4 (0xFF = OFF) + } *debug_flags = nullptr; +} ffx2; + + +struct unx_ffx_memory_s { + struct { + enum offset_t { + PartyBase = 0x0D32060, + InBattle = 0x1F10EA0, + GainedAp = 0x1F10EC4, + Debug = 0x0D2A8F8 + }; + } offsets; + + struct { + enum character_t { + Tidus = 0, + Yuna = 1, + Auron = 2, + Kimahri = 3, + Wakka = 4, + Lulu = 5, + Rikku = 6, + Seymour = 7 + }; + } characters; + + + struct debug_s { + struct { + uint8_t enemies; + uint8_t party; + } invincible; + + struct { + uint8_t enemies; + uint8_t unk3; + uint8_t camera; + } control; + + uint8_t unk4; + uint8_t unk5; + uint8_t unk6; + uint8_t unk7; + uint8_t unk8; + uint8_t unk9; + uint8_t unk10; + uint8_t unk11; + uint8_t unk12; + uint8_t unk13; + uint8_t unk14; + uint8_t unk15; + uint8_t unk16; + uint8_t unk17; + uint8_t unk18; + + struct { + uint8_t always_overdrive; + uint8_t always_critical; + uint8_t always_deal_1; + uint8_t always_deal_10000; + uint8_t always_deal_99999; + } damage; + + struct { + uint8_t always_rare_drop; + uint8_t ap_100x; + uint8_t gil_100x; + } reward; + + uint8_t unk27; + uint8_t permanent_sensor; + uint8_t unk28; + uint8_t unk29; + } *debug_flags = nullptr; + + struct party_s { + struct { + uint32_t HP; + uint32_t MP; + uint8_t strength; + uint8_t defense; + uint8_t magic; + uint8_t magic_defense; + uint8_t agility; + uint8_t luck; + uint8_t evasion; + uint8_t accuracy; + } base; + + struct { + uint32_t total; + uint32_t current; + } AP; + + struct { + struct { + uint32_t HP; + uint32_t MP; + } current; + + struct { + uint32_t HP; + uint32_t MP; + } max; + } vitals; + + uint8_t in_party; + + struct { + uint8_t weapon; + uint8_t armor; + } equipment; + + struct { + uint8_t strength; + uint8_t defense; + uint8_t magic; + uint8_t magic_defense; + uint8_t agility; + uint8_t luck; + uint8_t evasion; + uint8_t accuracy; + } current; + + uint8_t unknown2; + + struct { + uint8_t mode; + uint8_t level; + uint8_t max; + } overdrive; + + struct { + uint8_t banked; + uint8_t total; + } sphere_level; + + uint8_t unknown3; + + uint32_t skill_flags; + + struct { + uint32_t battles; + uint32_t kills; + } record; + + uint8_t unknown_blob [76]; + } *party = nullptr; + + struct battle_s { + uint8_t participation; + } *battle = nullptr; + + struct ap_s { + uint8_t earn; + } *ap = nullptr; +} ffx; extern wchar_t* UNX_GetExecutableName (void); extern LPVOID __UNX_base_img_addr; @@ -80,15 +250,41 @@ unx::CheatManager::Init (void) wchar_t* pwszShortName = UNX_GetExecutableName (); + // + // FFX + // if (! lstrcmpiW (pwszShortName, L"ffx.exe")) { game_type = GAME_FFX; + + ffx.debug_flags = + (unx_ffx_memory_s::debug_s *) + ((intptr_t)__UNX_base_img_addr + ffx.offsets.Debug); + + ffx.party = + (unx_ffx_memory_s::party_s *) + ((intptr_t)__UNX_base_img_addr + ffx.offsets.PartyBase); + + ffx.battle = + (unx_ffx_memory_s::battle_s *) + ((intptr_t)__UNX_base_img_addr + ffx.offsets.InBattle); + + ffx.ap = + (unx_ffx_memory_s::ap_s *) + ((intptr_t)__UNX_base_img_addr + ffx.offsets.GainedAp); + SetTimer (unx::window.hwnd, CHEAT_TIMER_FFX, 33, nullptr); } + // + // FFX-2 + // else if (! lstrcmpiW (pwszShortName, L"ffx-2.exe")) { game_type = GAME_FFX2; - ffx2_debug_flags = (unx_debug_ffx2_s *)((uint8_t *)__UNX_base_img_addr + 0x9F78B8); - //ffx2_debug_flags->always_critical = 1; + + ffx2.debug_flags = + (unx_ffx2_memory_s::debug_s *) + ((intptr_t)__UNX_base_img_addr + ffx2.offsets.Debug); + SetTimer (unx::window.hwnd, CHEAT_TIMER_FFX2, 33, nullptr); } } @@ -100,96 +296,21 @@ unx::CheatManager::Shutdown (void) #include "log.h" -struct unx_party_s { - uint32_t HP_cur; - uint32_t MP_cur; - - uint32_t HP_max; - uint32_t MP_max; - - uint8_t in_party; - - uint8_t unknown0; - uint8_t unknown1; - - uint8_t strength; - uint8_t defense; - uint8_t magic; - uint8_t magic_defense; - uint8_t agility; - uint8_t luck; - uint8_t evasion; - uint8_t accuracy; - - uint8_t unknown2; - - uint8_t overdrive_mode; - uint8_t overdrive_level; - uint8_t overdrive_max; - - uint8_t sphere_level_banked; - uint8_t sphere_level_net; - - uint8_t unknown3; - - uint32_t skill_flags; - - uint8_t unknown_blob [108]; -}; - -const intptr_t unx_debug_offset = 0xD2A8F8; - -struct unx_debug_s { - uint8_t unk0; - uint8_t unk1; - uint8_t unk2; - uint8_t unk3; - uint8_t free_camera; - uint8_t unk4; - uint8_t unk5; - uint8_t unk6; - uint8_t unk7; - uint8_t unk8; - uint8_t unk9; - uint8_t unk10; - uint8_t unk11; - uint8_t unk12; - uint8_t unk13; - uint8_t unk14; - uint8_t unk15; - uint8_t unk16; - uint8_t unk17; - uint8_t unk18; - uint8_t unk19; - uint8_t unk20; - uint8_t unk21; - uint8_t unk22; - uint8_t unk23; - uint8_t unk24; - uint8_t unk25; - uint8_t unk26; - uint8_t unk27; - uint8_t permanent_sensor; - uint8_t unk28; - uint8_t unk29; -}; - void UNX_ToggleFreeLook (void) { if (game_type != GAME_FFX) return; - unx_debug_s* - debug = (unx_debug_s *)((uint8_t *)__UNX_base_img_addr + unx_debug_offset); - - debug->free_camera = (! debug->free_camera); + ffx.debug_flags->control.camera = + (! ffx.debug_flags->control.camera); } void UNX_ToggleSensor (void) { - config.cheat.ffx.permanent_sensor = (! config.cheat.ffx.permanent_sensor); + config.cheat.ffx.permanent_sensor = + (! config.cheat.ffx.permanent_sensor); } bool @@ -198,16 +319,11 @@ UNX_IsInBattle (void) if (game_type != GAME_FFX) return false; - unx_party_s* party = - (unx_party_s *)((uint8_t *)__UNX_base_img_addr + OFFSET_PARTY_BASE); - - uint8_t* lpInBattle = (uint8_t *)__UNX_base_img_addr + OFFSET_IN_BATTLE; - for (int i = 0; i < 7; i++) { - uint8_t state = party [i].in_party; + uint8_t state = ffx.party [i].in_party; if (state != 0x00 && state != 0x10) { - if (lpInBattle [i] == 1) + if (ffx.battle [i].participation == 1) return true; } } @@ -218,18 +334,25 @@ UNX_IsInBattle (void) bool UNX_KillMeNow (void) { - return false; + if (game_type != GAME_FFX) + return false; - unx_party_s* party = - (unx_party_s *)((uint8_t *)__UNX_base_img_addr + OFFSET_PARTY_BASE); + return false; if (! UNX_IsInBattle ()) return false; else { +#if 0 + std::queue suspended_tids = + UNX_SuspendAllOtherThreads (); + for (int i = 0; i < 8; i++) { - party [i].HP_cur = 0UL; + ffx.party [i].vitals.current.HP = 0UL; } + + UNX_ResumeThreads (suspended_tids); +#endif } return true; @@ -241,54 +364,45 @@ unx::CheatTimer_FFX (void) if (game_type != GAME_FFX) return; - unx_party_s* party = - (unx_party_s *)((uint8_t *)__UNX_base_img_addr + OFFSET_PARTY_BASE); - - uint8_t* lpInBattle = (uint8_t *)__UNX_base_img_addr + OFFSET_IN_BATTLE; - uint8_t* lpGainedAp = (uint8_t *)__UNX_base_img_addr + OFFSET_GAINED_AP; - DWORD dwProtect; - - unx_debug_s* - debug = (unx_debug_s *)((uint8_t *)__UNX_base_img_addr + unx_debug_offset); - - debug->permanent_sensor = config.cheat.ffx.permanent_sensor; + ffx.debug_flags->permanent_sensor = + config.cheat.ffx.permanent_sensor; if (config.cheat.ffx.playable_seymour) { - party [7].in_party = 0x11; + ffx.party [ffx.characters.Seymour].in_party = 0x11; } else { - party [7].in_party = 0x10; + ffx.party [ffx.characters.Seymour].in_party = 0x10; } if (config.cheat.ffx.entire_party_earns_ap && UNX_IsInBattle ()) { - VirtualProtect (lpInBattle, 8, PAGE_READWRITE, &dwProtect); + VirtualProtect (&ffx.battle->participation, 8, PAGE_READWRITE, &dwProtect); for (int i = 0; i < 7; i++) { - uint8_t state = party [i].in_party; + uint8_t state = ffx.party [i].in_party; if (state != 0x00 && state != 0x10) { - if (lpInBattle [i] != 1) - lpInBattle [i] = 2; + if (ffx.battle [i].participation != 1) + ffx.battle [i].participation = 2; } else { - lpInBattle [i] = 0; + ffx.battle [i].participation = 0; } } - VirtualProtect (lpInBattle, 8, dwProtect, &dwProtect); - VirtualProtect (lpGainedAp, 8, PAGE_READWRITE, &dwProtect); + VirtualProtect (&ffx.battle->participation, 8, dwProtect, &dwProtect); + VirtualProtect (&ffx.ap->earn, 8, PAGE_READWRITE, &dwProtect); for (int i = 0; i < 7; i++) { - uint8_t state = party [i].in_party; + uint8_t state = ffx.party [i].in_party; if (state != 0x00 && state != 0x10) - lpGainedAp [i] = 1; + ffx.ap [i].earn = 1; else - lpGainedAp [i] = 0; + ffx.ap [i].earn = 0; } - VirtualProtect (lpGainedAp, 8, dwProtect, &dwProtect); + VirtualProtect (&ffx.ap->earn, 8, dwProtect, &dwProtect); } } @@ -297,4 +411,78 @@ unx::CheatTimer_FFX2 (void) { if (game_type != GAME_FFX2) return; +} + + + + + + +#include +#include +#include + +std::queue +UNX_SuspendAllOtherThreads (void) +{ + std::queue threads; + + HANDLE hSnap = + CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0); + + if (hSnap != INVALID_HANDLE_VALUE) + { + THREADENTRY32 tent; + tent.dwSize = sizeof THREADENTRY32; + + if (Thread32First (hSnap, &tent)) + { + do + { + if ( tent.dwSize >= FIELD_OFFSET (THREADENTRY32, th32OwnerProcessID) + + sizeof (tent.th32OwnerProcessID) ) + { + if ( tent.th32ThreadID != GetCurrentThreadId () && + tent.th32OwnerProcessID == GetCurrentProcessId () ) + { + HANDLE hThread = + OpenThread (THREAD_ALL_ACCESS, FALSE, tent.th32ThreadID); + + if (hThread != NULL) + { + threads.push (tent.th32ThreadID); + SuspendThread (hThread); + CloseHandle (hThread); + } + } + } + + tent.dwSize = sizeof (tent); + } while (Thread32Next (hSnap, &tent)); + } + + CloseHandle (hSnap); + } + + return threads; +} + +void +UNX_ResumeThreads (std::queue threads) +{ + while (! threads.empty ()) + { + DWORD tid = threads.front (); + + HANDLE hThread = + OpenThread (THREAD_ALL_ACCESS, FALSE, tid); + + if (hThread != NULL) + { + ResumeThread (hThread); + CloseHandle (hThread); + } + + threads.pop (); + } } \ No newline at end of file diff --git a/UnX/input.cpp b/UnX/input.cpp index 83e5521..d4b9ce2 100644 --- a/UnX/input.cpp +++ b/UnX/input.cpp @@ -199,7 +199,7 @@ IDirectInputDevice8_SetCooperativeLevel_pfn struct di8_keyboard_s { LPDIRECTINPUTDEVICE pDev = nullptr; - uint8_t state [256]; + uint8_t state [512]; } _dik; struct di8_mouse_s { @@ -518,20 +518,20 @@ typedef DWORD (WINAPI *XInputGetState_pfn)( XInputGetState_pfn XInputGetState_Original = nullptr; bool -IsControllerPluggedIn (UINT uJoyID) +IsControllerPluggedIn (INT iJoyID) { - if (uJoyID == (UINT)-1) + if (iJoyID == -1) return true; XINPUT_STATE xstate; static DWORD last_poll = timeGetTime (); - static DWORD dwRet = XInputGetState_Original (uJoyID, &xstate); + static DWORD dwRet = XInputGetState_Original (iJoyID, &xstate); // This function is actually a performance hazzard when no controllers // are plugged in, so ... throttle the sucker. if (last_poll < timeGetTime () - 500UL) - dwRet = XInputGetState_Original (uJoyID, &xstate); + dwRet = XInputGetState_Original (iJoyID, &xstate); if (dwRet == ERROR_DEVICE_NOT_CONNECTED) return false; @@ -552,8 +552,8 @@ XInputGetState_Detour ( _In_ DWORD dwUserIndex, DWORD dwRet = XInputGetState_Original (slot, pState); - if (dwRet == ERROR_NOT_CONNECTED) - dwRet = 0; + //if (dwRet == ERROR_NOT_CONNECTED) + //dwRet = 0; return dwRet; } @@ -1404,7 +1404,7 @@ unx::InputManager::Hooker::MessagePump (LPVOID hook_ptr) if (UNX_PollAxis (gamepad.remap.buttons.RS, joy_ex, caps) > 190) xi_state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; - if (joy_ex.dwPOV & JOY_POVFORWARD) + if (joy_ex.dwPOV == JOY_POVFORWARD) xi_state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; if (joy_ex.dwPOV & JOY_POVBACKWARD) xi_state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; @@ -1479,6 +1479,14 @@ unx::InputManager::Hooker::MessagePump (LPVOID hook_ptr) } if (esc.state) { +/* +FFX.exe+302C4F - 6A 01 - push 01 { 00000001 } +FFX.exe+302C51 - 6A 00 - push 00 { 0 } +FFX.exe+302C53 - 6A 00 - push 00 { 0 } +FFX.exe+302C55 - 68 78CE8700 - push FFX.exe+74CE78 { ["showSaveLoad"] } +FFX.exe+302C5A - 6A 00 - push 00 { 0 } +FFX.exe+302C5C - E8 3F5F3200 - call FFX.exe+628BA0 +*/ #if 0 extern void* UNX_Scan (const uint8_t* pattern, size_t len, const uint8_t* mask); diff --git a/UnX/language.cpp b/UnX/language.cpp index 6f59621..0523cae 100644 --- a/UnX/language.cpp +++ b/UnX/language.cpp @@ -155,12 +155,6 @@ UNX_PatchLanguageFFX (void) "/MetaMenu/GameData/PS3Data/Video/US/timestamp_%s.txt" ); } - extern LPVOID __UNX_base_img_addr; - DWORD dwProtect; - VirtualProtect ((LPVOID)((intptr_t)__UNX_base_img_addr + 0x8e9004), 4, PAGE_READWRITE, &dwProtect); - *(uint32_t *)((intptr_t)__UNX_base_img_addr + 0x8e9004) = 0; - VirtualProtect ((LPVOID)((intptr_t)__UNX_base_img_addr + 0x8e9004), 4, dwProtect, &dwProtect); - return true; } diff --git a/UnX/timing.cpp b/UnX/timing.cpp index d020b34..04dca9e 100644 --- a/UnX/timing.cpp +++ b/UnX/timing.cpp @@ -57,19 +57,36 @@ HMODULE NtDll = 0; NtQueryTimerResolution_pfn NtQueryTimerResolution = nullptr; NtSetTimerResolution_pfn NtSetTimerResolution = nullptr; +typedef DWORD (WINAPI *SleepEx_pfn)( + _In_ DWORD dwMilliseconds, + _In_ BOOL bAlertable +); + +SleepEx_pfn SleepEx_Original = nullptr; + +DWORD +SleepEx_Detour (DWORD dwMilliseconds, BOOL bAlertable) +{ + if (dwMilliseconds > 5) + dwMilliseconds = 5; + + return SleepEx_Original (dwMilliseconds, bAlertable); +} + + void WINAPI UNX_SE_FixFramerateLimiter (DWORD dwMilliseconds) { if (dwMilliseconds == 0) { YieldProcessor (); - //return; + return; } if (dwMilliseconds == 5) { - YieldProcessor (); - //return; - dwMilliseconds = 0; + //YieldProcessor (); + return; + ////dwMilliseconds = 0; } return SK_Sleep (dwMilliseconds); @@ -111,6 +128,11 @@ unx::TimingFix::Init (void) "Sleep_Detour", UNX_SE_FixFramerateLimiter, (LPVOID *)&SK_Sleep ); + + UNX_CreateDLLHook ( L"kernel32.dll", + "SleepEx", + SleepEx_Detour, + (LPVOID *)&SleepEx_Original ); } HMODULE hModKernel32 = LoadLibrary (L"kernel32.dll"); diff --git a/UnX/window.cpp b/UnX/window.cpp index b0b22e8..a230433 100644 --- a/UnX/window.cpp +++ b/UnX/window.cpp @@ -91,30 +91,12 @@ UNX_IsWindowThread (void) return false; } -void -UNX_ClearD3D11DevCtx (IDXGISwapChain* pSwapChain) -{ - CComPtr pDev; - - if (SUCCEEDED (pSwapChain->GetDevice (IID_PPV_ARGS (&pDev)))) { - CComPtr pDevCtx; - - pDev->GetImmediateContext (&pDevCtx); - pDevCtx->Flush (); - pDevCtx->ClearState (); - } -} - -void -UNX_ToggleFullscreen (void) +DWORD +WINAPI +UNX_ToggleFullscreenThread (LPVOID user) { - // Mod is not yet fully initialized... - if (! pGameSwapChain) - return; - - BOOL fullscreen = FALSE; - - CComPtr pOutput = nullptr; + BOOL fullscreen = FALSE; + CComPtr pOutput = nullptr; if (SUCCEEDED (pGameSwapChain->GetFullscreenState (&fullscreen, &pOutput))) { if (fullscreen) { @@ -123,18 +105,32 @@ UNX_ToggleFullscreen (void) DXGI_SWAP_CHAIN_DESC swap_desc; pGameSwapChain->GetDesc (&swap_desc); - DXGI_MODE_DESC mode = swap_desc.BufferDesc; + DXGI_MODE_DESC mode = swap_desc.BufferDesc; - pGameSwapChain->ResizeTarget (&mode); + pGameSwapChain->ResizeTarget (&mode); pGameSwapChain->SetFullscreenState (TRUE, pOutput); mode.RefreshRate.Denominator = 0; mode.RefreshRate.Numerator = 0; - pGameSwapChain->ResizeTarget (&mode); + pGameSwapChain->ResizeTarget (&mode); pGameSwapChain->ResizeBuffers (0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH); } } + + return 0; +} + +void +UNX_ToggleFullscreen (void) +{ + // Mod is not yet fully initialized... + if (! pGameSwapChain) + return; + + // It is not safe to issue DXGI commands from the thread that drives + // the Windows message pump... so spawn a separate thread to do this. + CreateThread (nullptr, 0, UNX_ToggleFullscreenThread, nullptr, 0, nullptr); } @@ -145,8 +141,6 @@ UNX_SetFullscreenState (unx_fullscreen_op_t op) { static BOOL last_fullscreen = FALSE; - UNX_ClearD3D11DevCtx (pGameSwapChain); - // Mod is not yet fully initialized... if (pGameSwapChain == nullptr) return; @@ -196,28 +190,6 @@ DetourWindowProc ( _In_ HWND hWnd, bool windowed = false; -#include -#pragma comment (lib, "dwmapi.lib") - -typedef BOOL (WINAPI *GetWindowInfo_pfn)( - _In_ HWND hwnd, - _Inout_ PWINDOWINFO pwi -); - -GetWindowInfo_pfn GetWindowInfo_Original = nullptr; - -BOOL -WINAPI -GetWindowInfo_Detour ( _In_ HWND hWnd, - _Inout_ PWINDOWINFO pwi ) -{ - BOOL ret = - GetWindowInfo_Original (hWnd, pwi); - - return ret; -} - - typedef LRESULT (CALLBACK *DetourWindowProc_pfn)( _In_ HWND hWnd, _In_ UINT uMsg, _In_ WPARAM wParam, @@ -256,6 +228,7 @@ DetourWindowProc ( _In_ HWND hWnd, } + // This state is persistent and we do not want Alt+F4 to remember a muted // state. if (uMsg == WM_DESTROY || uMsg == WM_QUIT || (config.input.fast_exit && uMsg == WM_CLOSE)) { @@ -303,8 +276,6 @@ DetourWindowProc ( _In_ HWND hWnd, UNX_SetGameMute (bMute); } - //unx::window.active = (! deactivate); - dll_log.Log ( L"[Window Mgr] Activation: %s", unx::window.active ? L"ACTIVE" : L"INACTIVE" ); @@ -314,11 +285,9 @@ DetourWindowProc ( _In_ HWND hWnd, // if (pGameSwapChain != nullptr && config.display.enable_fullscreen) { if (! deactivate) { - if (unx::window.fullscreen) - UNX_ToggleFullscreen (); + UNX_SetFullscreenState (Restore); } else { - if (unx::window.fullscreen) - UNX_ToggleFullscreen (); + UNX_SetFullscreenState (Window); } } } @@ -365,9 +334,7 @@ DetourWindowProc ( _In_ HWND hWnd, // Alt + Enter (Fullscreen toggle) if (uMsg == WM_SYSKEYDOWN && wParam == VK_RETURN) { - - if (pGameSwapChain) { - unx::window.fullscreen = (! unx::window.fullscreen); + if (pGameSwapChain && config.display.enable_fullscreen) { UNX_ToggleFullscreen (); return DefWindowProc (hWnd, uMsg, wParam, lParam); } @@ -380,7 +347,7 @@ DetourWindowProc ( _In_ HWND hWnd, // What an ugly mess, this is crazy :) if (config.input.cursor_mgmt) { - extern bool IsControllerPluggedIn (UINT uJoyID); + extern bool IsControllerPluggedIn (INT iJoyID); struct { POINTS pos = { 0 }; // POINT (Short) - Not POINT plural ;) @@ -493,14 +460,14 @@ DXGISwap_ResizeBuffers_Detour ( if (pGameSwapChain) { if (SUCCEEDED (pGameSwapChain->GetFullscreenState (&fullscreen, nullptr))) { - if (fullscreen) + if (fullscreen) // Moving the window in fullscreen mode is bad mojo should_center = false; } } } - if (pGameSwapChain == This && config.display.enable_fullscreen) { + if (pGameSwapChain == This /*&& config.display.enable_fullscreen*/) { // // Allow Alt+Enter // @@ -515,32 +482,24 @@ DXGISwap_ResizeBuffers_Detour ( SUCCEEDED (pDevDXGI->GetAdapter (&pAdapter) ) && SUCCEEDED ( pAdapter->GetParent (IID_PPV_ARGS (&pFactory)) ) ) { - DXGI_SWAP_CHAIN_DESC desc; - - if (SUCCEEDED (pGameSwapChain->GetDesc (&desc))) { + dll_log.Log ( L"[Fullscreen] Setting DXGI Window Association " + L"(HWND: Game=%X,SwapChain=%X - flags=DXGI_MWA_NO_WINDOW_CHANGES)", + SK_GetGameWindow (), desc.OutputWindow ); - dll_log.Log ( L"[Fullscreen] Setting DXGI Window Association " - L"(HWND: Game=%X,SwapChain=%X - flags=DXGI_MWA_NO_WINDOW_CHANGES)", - SK_GetGameWindow (), desc.OutputWindow ); - - pFactory->MakeWindowAssociation (desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES); - } + pFactory->MakeWindowAssociation (desc.OutputWindow, DXGI_MWA_NO_WINDOW_CHANGES | + DXGI_MWA_NO_ALT_ENTER ); // Allow Fullscreen - SwapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + if (config.display.enable_fullscreen) + SwapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + else + SwapChainFlags = 0x00; } } HRESULT hr = DXGISwap_ResizeBuffers_Original (This, BufferCount, Width, Height, NewFormat, SwapChainFlags); - - if ( pGameSwapChain == This && config.display.enable_fullscreen && BufferCount != 0 && Width != 0 && Height != 0) - { - if (UNX_IsRenderThread ()) { - } - } - if (should_center) { MONITORINFO moninfo; moninfo.cbSize = sizeof MONITORINFO; @@ -550,38 +509,17 @@ DXGISwap_ResizeBuffers_Detour ( int mon_width = moninfo.rcMonitor.right - moninfo.rcMonitor.left; int mon_height = moninfo.rcMonitor.bottom - moninfo.rcMonitor.top; - if (Width < mon_width && Height < mon_height) { + if (Width <= mon_width && Height <= mon_height) { SetWindowPos ( SK_GetGameWindow (), HWND_NOTOPMOST, (mon_width - Width) / 2, (mon_height - Height) / 2, Width, Height, - SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_NOACTIVATE ); + SWP_NOSIZE | SWP_NOSENDCHANGING ); } } return hr; } -HRESULT -WINAPI -DXGISwap_ResizeTarget_Detour ( - IDXGISwapChain *This, - DXGI_MODE_DESC *desc ) -{ - if ( pGameSwapChain == This && config.display.enable_fullscreen && - ( desc->RefreshRate.Denominator != 0 || desc->RefreshRate.Numerator != 0 ) ) - { - if (UNX_IsRenderThread ()) { - ////mode_changes.push (Window); - //UNX_SetFullscreenState (Window); - } - } - - HRESULT hr = - DXGISwap_ResizeTarget_Original (This, desc); - - return hr; -} - typedef HRESULT (WINAPI *SK_BeginBufferSwap_pfn)(void); SK_BeginBufferSwap_pfn SK_BeginBufferSwap_Original = nullptr; @@ -592,9 +530,14 @@ SK_BeginBufferSwap_Detour (void) if (unx::window.render_thread == 0) unx::window.render_thread = GetCurrentThreadId (); - if (UNX_IsRenderThread ()) - { +#if 0 + CComPtr pOut; + + if ( pGameSwapChain != nullptr && + SUCCEEDED (pGameSwapChain->GetContainingOutput (&pOut)) ) { + pOut->WaitForVBlank (); } +#endif return SK_BeginBufferSwap_Original (); } @@ -614,22 +557,10 @@ UNX_InstallWindowHook (HWND hWnd) DetourWindowProc, (LPVOID *)&DetourWindowProc_Original ); - //DwmEnableMMCSS (TRUE); - UNX_CreateDLLHook ( config.system.injector.c_str (), "DXGISwap_ResizeBuffers_Override", DXGISwap_ResizeBuffers_Detour, (LPVOID *)&DXGISwap_ResizeBuffers_Original ); - - UNX_CreateDLLHook ( config.system.injector.c_str (), - "DXGISwap_ResizeTarget_Override", - DXGISwap_ResizeTarget_Detour, - (LPVOID *)&DXGISwap_ResizeTarget_Original ); - - UNX_CreateDLLHook ( L"user32.dll", - "GetWindowInfo", - GetWindowInfo_Detour, - (LPVOID *)&GetWindowInfo_Original ); }