core: Send WM_ resize msgs instead of requesting device resize

This commit is contained in:
Jade Macho 2025-06-28 21:38:35 +02:00
parent 3831b5f64f
commit 78ff318397
Signed by: 0x0ade
GPG key ID: E1960710FE4FBEEF
6 changed files with 107 additions and 33 deletions

View file

@ -79,12 +79,12 @@ public sealed class MainCmd : Cmd
return;
case "debugsizeold":
Service.DebugConfig.SetSizeMode = SetSizeMode.LegacyHookSetWindowPos;
Service.DebugConfig.ForceSizeMode = ForceSizeMode.LegacyRequestResolutionChange;
Service.PrintChat("Switched to legacy size mode. Please report your use case / any bugs with the new mode to 0x0ade.");
return;
case "debugsizenew":
Service.DebugConfig.SetSizeMode = SetSizeMode.InterceptSystemConfig;
Service.DebugConfig.ForceSizeMode = ForceSizeMode.FakeWindowResize;
Service.PrintChat("Switched back to new size mode.");
return;
}

View file

@ -8,13 +8,15 @@ public class DebugConfiguration
{
public bool IsDebug { get; set; } = false;
public SetSizeMode SetSizeMode { get; set; } = SetSizeMode.InterceptSystemConfig;
public SetWindowSizeMode SetWindowSizeMode { get; set; } = SetWindowSizeMode.InterceptSystemConfig;
public ForceSizeMode ForceSizeMode { get; set; } = ForceSizeMode.FakeWindowResize;
}
public enum SetSizeMode
public enum SetWindowSizeMode
{
/// <summary>
/// Intercept the system config width / height and scale it, but don't intercept window size sets.
/// Intercept the system config width / height and scale it to the window size, and don't intercept window size sets.
/// Has got a mild risk of growing / shrinking windows if any codepath tries to get->set the window size,
/// most notably with other plugins trying to change the window size. You shouldn't mix and match those anyway tho...
/// ... and even then, I'm probably the only one who's going to read this and care about this. -jade
@ -22,8 +24,10 @@ public enum SetSizeMode
InterceptSystemConfig = 0,
/// <summary>
/// Legacy mode, went through more testing, works well except for the game getting confused about windowed mode size.
/// Legacy mode, went through more initial testing, works well except for the game getting confused about windowed mode size.
/// Might revert or remove depending on how InterceptSystemConfig testing / fixups proceed.
///
/// Hook SetWindowPos and turn the wanted size from scaled to window size on the fly.
/// </summary>
LegacyHookSetWindowPos = 1
}

View file

@ -62,13 +62,18 @@ public sealed unsafe class WindowRectHooks : IDisposable
return rv;
}
public bool SetWindowPosOrig(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags)
{
return _setWindowPosHook.Original(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
}
private bool SetWindowPosDetour(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags)
{
#if false
Service.PluginLog.Debug($"SetWindowPosDetour A @ {X} {Y} {cx} {cy}");
#endif
if (Service.DebugConfig.SetSizeMode == SetSizeMode.LegacyHookSetWindowPos && hWnd == Service.Plugin.CurrentHWND)
if (Service.DebugConfig.SetWindowSizeMode == SetWindowSizeMode.LegacyHookSetWindowPos && hWnd == Service.Plugin.CurrentHWND)
{
Service.Plugin.ConvertCoordsGameToWin(ref cx, ref cy);
}

View file

@ -74,32 +74,32 @@ public sealed unsafe class WndProcHook : IDisposable
}
}
private static void ParamToCoords(LPARAM param, out int x, out int y)
public static void ParamToCoords(LPARAM param, out int x, out int y)
{
x = (short) (ushort) (param.Value & 0xFFFF);
y = (short) (ushort) (param.Value >> 16 & 0xFFFF);
y = (short) (ushort) ((param.Value >> 16) & 0xFFFF);
}
private static LPARAM CoordsToParam(int x, int y)
public static LPARAM CoordsToParam(int x, int y)
{
nint value = 0;
value |= ((ushort) (short) x) & 0xFFFF;
value |= ((ushort) (short) y) >> 16 & 0xFFFF;
value |= (((ushort) (short) y) & 0xFFFF) << 16;
return value;
}
private static void ParamToSize(LPARAM param, out uint x, out uint y)
public static void ParamToSize(LPARAM param, out uint x, out uint y)
{
x = (ushort) (param.Value & 0xFFFF);
y = (ushort) (param.Value >> 16 & 0xFFFF);
y = (ushort) ((param.Value >> 16) & 0xFFFF);
}
private static LPARAM SizeToParam(uint x, uint y)
public static LPARAM SizeToParam(uint x, uint y)
{
nint value = 0;
value |= ((ushort) x) & 0xFFFF;
value |= ((ushort) y) >> 16 & 0xFFFF;
value |= (((ushort) y) & 0xFFFF) << 16;
return value;
}

View file

@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.Keys;
using CustomResolution.Hooks;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Config;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
@ -29,6 +30,8 @@ public sealed unsafe class Plugin : IDalamudPlugin
private RECT _currentClientRect;
private DXVKDWMHackMode _currentDXVKDWMHackMode = DXVKDWMHackMode.Off;
private bool _ignoreConfigChanges = false;
private bool _currentlyFakeResize = false;
private bool _requestedResolutionChange = false;
public Plugin(IDalamudPluginInterface pluginInterface)
{
@ -226,14 +229,9 @@ public sealed unsafe class Plugin : IDalamudPlugin
return;
}
uint width, height;
var enabled = !_unloading && Service.Config.IsEnabled;
if (_wasEnabled != enabled)
{
Service.PluginLog.Info($"Changing state to: {enabled}");
_wasEnabled = enabled;
}
uint width, height;
if (Service.Config.IsScale || !enabled)
{
@ -258,15 +256,61 @@ public sealed unsafe class Plugin : IDalamudPlugin
height = 256;
}
if (width != dev->Width || height != dev->Height)
_requestedResolutionChange |= (*_dev_RequestResolutionChange) != 0;
if (!_currentlyFakeResize && (_unloading || enabled || _wasEnabled || _requestedResolutionChange) &&
(width != dev->Width || height != dev->Height))
{
Service.PluginLog.Info($"Changing graphics resolution from {dev->Width} x {dev->Height} to {width} x {height}");
var mode = Service.DebugConfig.ForceSizeMode;
if (_requestedResolutionChange)
{
// Let's try to be cautious about other plugins (f.e. SimpleTweaks) changing the game resolution.
Service.PluginLog.Info($"Game resolution was changed externally - forcing resize via device, not window resize.");
mode = ForceSizeMode.LegacyRequestResolutionChange;
_requestedResolutionChange = false;
}
switch (mode)
{
case ForceSizeMode.Skip:
break;
case ForceSizeMode.LegacyRequestResolutionChange:
*_dev_NewWidth = width;
*_dev_NewHeight = height;
*_dev_RequestResolutionChange = 1;
Service.PluginLog.Info($"Changing game window from {win->WindowWidth} x {win->WindowHeight} to {width} x {height}");
win->WindowWidth = (int) width;
win->WindowHeight = (int) height;
break;
case ForceSizeMode.FakeWindowResize:
var adjustedClientRect = new RECT(0, 0, rectWidth, rectHeight);
AdjustWindowRect(&adjustedClientRect, (uint) GetWindowLongPtr(_currentHwnd, GWL.GWL_STYLE), false);
var adjustedWidth = adjustedClientRect.right - adjustedClientRect.left;
var adjustedHeight = adjustedClientRect.bottom - adjustedClientRect.top;
Service.PluginLog.Info($"Resizing window to {adjustedWidth} x {adjustedHeight}");
try
{
_currentlyFakeResize = true;
SendMessage(_currentHwnd, WM.WM_ENTERSIZEMOVE, 0, 0);
SendMessage(_currentHwnd, WM.WM_SIZE, SIZE_MAXSHOW, WndProcHook.SizeToParam((uint) adjustedWidth, (uint) adjustedHeight));
SendMessage(_currentHwnd, WM.WM_PAINT, 0, 0);
SendMessage(_currentHwnd, WM.WM_EXITSIZEMOVE, 0, 0);
}
finally
{
_currentlyFakeResize = false;
}
break;
default:
Service.PluginLog.Error($"Unknown ForceSizeMode: {Service.DebugConfig.ForceSizeMode}");
break;
}
}
if (_wasEnabled != enabled)
{
Service.PluginLog.Info($"Changed state to: {enabled}");
_wasEnabled = enabled;
}
//Service.PluginLog.Debug($"NewWidth 0x{(long) (IntPtr) (&dev->NewWidth):X16}");
@ -423,7 +467,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
{
case SystemConfigOption.ScreenWidth:
case SystemConfigOption.ScreenHeight:
if (Service.DebugConfig.SetSizeMode == SetSizeMode.InterceptSystemConfig)
if (Service.DebugConfig.SetWindowSizeMode == SetWindowSizeMode.InterceptSystemConfig)
{
var name = e.ConfigOption.ToString();
var valueOrig = Service.GameConfig.System.GetUInt(name);
@ -448,3 +492,22 @@ public sealed unsafe class Plugin : IDalamudPlugin
}
}
}
public enum ForceSizeMode
{
Skip = -1,
/// <summary>
/// Fake a window resize event.
/// </summary>
FakeWindowResize = 0,
/// <summary>
/// Legacy mode, went through more initial testing, works well except for conflicts with other plugins.
/// Might revert or remove depending on how FakeWindowResize testing / fixups proceed.
///
/// Update the graphics device width / height and set RequestResolutionChange.
/// This is the same method that other plugins such as SimpleTweaks or XIVWindowResizer use.
/// </summary>
LegacyRequestResolutionChange = 1
}

View file

@ -33,6 +33,8 @@ time than I have on my hands right now.
</details>
<details><summary>I'm using DLSS, and my game looks pixelated / is small!</summary>
DLSS and cres at very small scales (width / height under about 500 pixels) seems to be a conflicting combo.
Resizing the game window usually undoes any miniaturization, but I've yet to figure out why the game pixelates. Sorry!
DLSS in FFXIV is bugged. No, I'm not joking: even without any plugins or mods loaded, it can glitch out when
simply resizing the window (most notably by rapidly pressing WinKey + Down and WinKey + Up).
This issue doesn't happen with FSR and non-DLSS dynamic resolution.
</details>