Move mostly away from D3D resize to fake window size (fix ReShade)

This commit is contained in:
Jade Macho 2025-03-09 22:40:46 +01:00
parent 3a54a2781f
commit 80ca36b0a8
Signed by: 0x0ade
GPG key ID: E1960710FE4FBEEF
5 changed files with 153 additions and 43 deletions

View file

@ -73,4 +73,5 @@ public sealed unsafe class CursorPosHooks : IDisposable
return _setCursorPosHook.Original(x, y); return _setCursorPosHook.Original(x, y);
} }
} }

View file

@ -0,0 +1,81 @@
using CustomResolution.WndProcHookManagerProxyApi;
using Dalamud.Hooking;
using Serilog.Events;
using System;
using System.Linq;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using TerraFX.Interop.Windows;
namespace CustomResolution.Hooks;
// THIS. IS. UGLY.
public sealed unsafe class WindowRectHooks : IDisposable
{
private readonly Hook<GetClientRectDelegate> _getClientRectHook;
private readonly Hook<SetWindowPosDelegate> _setWindowPosHook;
public WindowRectHooks()
{
_getClientRectHook = Service.GameInteropProvider.HookFromSymbol<GetClientRectDelegate>("user32.dll", "GetClientRect", GetClientRectDetour);
_getClientRectHook.Enable();
_setWindowPosHook = Service.GameInteropProvider.HookFromSymbol<SetWindowPosDelegate>("user32.dll", "SetWindowPos", SetWindowPosDetour);
_setWindowPosHook.Enable();
}
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private unsafe delegate bool GetClientRectDelegate(HWND hWnd, RECT* lpRect);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private unsafe delegate bool SetWindowPosDelegate(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
public void Dispose()
{
_getClientRectHook.Dispose();
}
public bool GetClientRectOrig(HWND hWnd, RECT* lpRect)
{
return _getClientRectHook.Original(hWnd, lpRect);
}
private bool GetClientRectDetour(HWND hWnd, RECT* lpRect)
{
var rv = _getClientRectHook.Original(hWnd, lpRect);
if (!rv)
{
return false;
}
#if false
Service.PluginLog.Debug($"GetClientRectDetour A @ {lpRect->left} {lpRect->top} {lpRect->right} {lpRect->bottom}");
#endif
Service.Plugin.ConvertCoordsWinToGame(ref lpRect->right, ref lpRect->bottom);
#if false
Service.PluginLog.Debug($"GetClientRectDetour B @ {lpRect->left} {lpRect->top} {lpRect->right} {lpRect->bottom}");
#endif
return rv;
}
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
Service.Plugin.ConvertCoordsGameToWin(ref cx, ref cy);
#if false
Service.PluginLog.Debug($"SetWindowPosDetour B @ {X} {Y} {cx} {cy}");
#endif
return _setWindowPosHook.Original(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
}
}

View file

@ -71,6 +71,21 @@ public sealed unsafe class WndProcHook : IDisposable
return value; return value;
} }
private static void ParamToSize(LPARAM param, out uint x, out uint y)
{
x = (ushort) (param.Value & 0xFFFF);
y = (ushort) (param.Value >> 16 & 0xFFFF);
}
private static LPARAM SizeToParam(uint x, uint y)
{
nint value = 0;
value |= ((ushort) x) & 0xFFFF;
value |= ((ushort) y) >> 16 & 0xFFFF;
return value;
}
private void Invoke(WndProcEventArgs args) private void Invoke(WndProcEventArgs args)
{ {
if (Service.Plugin is not { } plugin) if (Service.Plugin is not { } plugin)
@ -78,6 +93,14 @@ public sealed unsafe class WndProcHook : IDisposable
return; return;
} }
if (args.Message == WM.WM_SIZE)
{
ParamToCoords(args.LParam, out int x, out int y);
Service.PluginLog.Debug($"WM_SIZE {x} x {y}");
Service.Plugin.Update();
args.LParam = SizeToParam(Service.Plugin.CurrentWidth, Service.Plugin.CurrentHeight);
}
if (WM.WM_MOUSEFIRST <= args.Message && args.Message <= WM.WM_MOUSELAST) if (WM.WM_MOUSEFIRST <= args.Message && args.Message <= WM.WM_MOUSELAST)
{ {
ParamToCoords(args.LParam, out int x, out int y); ParamToCoords(args.LParam, out int x, out int y);

View file

@ -1,8 +1,10 @@
using Dalamud.Game.ClientState.Keys; using CustomResolution.Hooks;
using Dalamud.Game.ClientState.Keys;
using Dalamud.IoC; using Dalamud.IoC;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.System.Framework;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Common.Lua; using FFXIVClientStructs.FFXIV.Common.Lua;
using FFXIVClientStructs.Interop; using FFXIVClientStructs.Interop;
@ -11,6 +13,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using TerraFX.Interop.Windows; using TerraFX.Interop.Windows;
using static Dalamud.Interface.Utility.Raii.ImRaii;
using static TerraFX.Interop.Windows.Windows; using static TerraFX.Interop.Windows.Windows;
namespace CustomResolution; namespace CustomResolution;
@ -23,10 +26,9 @@ public sealed unsafe class Plugin : IDalamudPlugin
private readonly List<Cmd> _cmds; private readonly List<Cmd> _cmds;
private bool _unloading = false; private bool _unloading = false;
private int _tickCount = 0; private bool _wasEnabled = false;
private HWND _currentHwnd; private HWND _currentHwnd;
private RECT _currentClientRect; private RECT _currentClientRect;
private RECT _currentWindowRect;
private DXVKDWMHackMode _currentDXVKDWMHackMode = DXVKDWMHackMode.Off; private DXVKDWMHackMode _currentDXVKDWMHackMode = DXVKDWMHackMode.Off;
public Plugin(IDalamudPluginInterface pluginInterface) public Plugin(IDalamudPluginInterface pluginInterface)
@ -44,6 +46,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
Service.WndProcHook = new(); Service.WndProcHook = new();
Service.CursorPosHooks = new(); Service.CursorPosHooks = new();
Service.WindowRectHooks = new();
_cmds = typeof(Plugin).Assembly.GetTypes() _cmds = typeof(Plugin).Assembly.GetTypes()
.Where(t => !t.IsAbstract && typeof(Cmd).IsAssignableFrom(t)) .Where(t => !t.IsAbstract && typeof(Cmd).IsAssignableFrom(t))
@ -77,8 +80,6 @@ public sealed unsafe class Plugin : IDalamudPlugin
lock (_disposeLock) lock (_disposeLock)
{ {
_tickCount = 0;
Service.Framework.Update -= OnFrameworkUpdate; Service.Framework.Update -= OnFrameworkUpdate;
Service.Framework.RunOnFrameworkThread(Update); Service.Framework.RunOnFrameworkThread(Update);
@ -89,6 +90,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
cmd.Dispose(); cmd.Dispose();
} }
Service.WindowRectHooks.Dispose();
Service.CursorPosHooks.Dispose(); Service.CursorPosHooks.Dispose();
Service.WndProcHook.Dispose(); Service.WndProcHook.Dispose();
@ -99,7 +101,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
public void ConvertCoordsWinToGame(ref int x, ref int y) public void ConvertCoordsWinToGame(ref int x, ref int y)
{ {
if (CurrentWidth == CurrentWindowWidth && CurrentHeight == CurrentWindowHeight) if (CurrentWidth == CurrentWindowWidth && CurrentHeight == CurrentWindowHeight)
{ {
return; return;
} }
@ -174,6 +176,15 @@ public sealed unsafe class Plugin : IDalamudPlugin
public void Update() public void Update()
{ {
var dev = Device.Instance(); var dev = Device.Instance();
var framework = Framework.Instance();
var win = framework->GameWindow;
_currentHwnd = (HWND) (IntPtr) dev->hWnd;
fixed (RECT* currentClientRectPtr = &_currentClientRect)
{
Service.WindowRectHooks.GetClientRectOrig(_currentHwnd, currentClientRectPtr);
}
int rectWidth = _currentClientRect.right - _currentClientRect.left; int rectWidth = _currentClientRect.right - _currentClientRect.left;
int rectHeight = _currentClientRect.bottom - _currentClientRect.top; int rectHeight = _currentClientRect.bottom - _currentClientRect.top;
@ -185,11 +196,16 @@ public sealed unsafe class Plugin : IDalamudPlugin
uint width, height; uint width, height;
bool disabled = _unloading || !Service.Config.IsEnabled; bool enabled = !_unloading && Service.Config.IsEnabled;
if (_wasEnabled != enabled)
if (Service.Config.IsScale || disabled)
{ {
var scale = disabled ? 1f : Service.Config.Scale; Service.PluginLog.Info($"Changing state to: {enabled}");
_wasEnabled = enabled;
}
if (Service.Config.IsScale || !enabled)
{
var scale = enabled ? Service.Config.Scale : 1f;
width = (uint) Math.Round(rectWidth * scale); width = (uint) Math.Round(rectWidth * scale);
height = (uint) Math.Round(rectHeight * scale); height = (uint) Math.Round(rectHeight * scale);
@ -200,27 +216,33 @@ public sealed unsafe class Plugin : IDalamudPlugin
height = Service.Config.Height; height = Service.Config.Height;
} }
if (width < 256)
{
width = 256;
}
if (height < 256)
{
height = 256;
}
if (width != dev->Width || height != dev->Height) if (width != dev->Width || height != dev->Height)
{ {
Service.PluginLog.Info($"Changing resolution to {width} x {height}"); Service.PluginLog.Info($"Changing graphics resolution from {dev->Width} x {dev->Height} to {width} x {height}");
if (width < 256)
{
width = 256;
}
if (height < 256)
{
height = 256;
}
dev->NewWidth = width; dev->NewWidth = width;
dev->NewHeight = height; dev->NewHeight = height;
dev->RequestResolutionChange = 1; 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;
} }
// TODO: This isn't accurate! Figure out how to read the game's settings instead. //Service.PluginLog.Debug($"NewWidth 0x{(long) (IntPtr) (&dev->NewWidth):X16}");
CurrentBorderlessFullscreen = (GetWindowLong(_currentHwnd, GWL.GWL_STYLE) & WS.WS_SYSMENU) == 0; //Service.PluginLog.Debug($"GameWindow->Width 0x{(long) (IntPtr) (&win->WindowWidth):X16}");
//Service.PluginLog.Info($"Game window at {win->WindowWidth} x {win->WindowHeight}");
CurrentBorderlessFullscreen = win->Borderless;
if (Service.Config.DXVKDWMHackMode != DXVKDWMHackMode.Off && !_unloading) if (Service.Config.DXVKDWMHackMode != DXVKDWMHackMode.Off && !_unloading)
{ {
@ -338,25 +360,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
Service.Config.Save(); Service.Config.Save();
} }
var dev = Device.Instance(); Update();
_currentHwnd = (HWND) (IntPtr) dev->hWnd;
fixed (RECT* currentClientRectPtr = &_currentClientRect)
fixed (RECT* currentWindowRectPtr = &_currentWindowRect)
{
GetClientRect(_currentHwnd, currentClientRectPtr);
GetWindowRect(_currentHwnd, currentWindowRectPtr);
}
if (_tickCount++ >= 2)
{
_tickCount = 0;
Update();
}
_tickCount++;
} }
} }
} }

View file

@ -16,6 +16,7 @@ public sealed class Service
public static WndProcHook WndProcHook { get; internal set; } = null!; public static WndProcHook WndProcHook { get; internal set; } = null!;
public static CursorPosHooks CursorPosHooks { get; internal set; } = null!; public static CursorPosHooks CursorPosHooks { get; internal set; } = null!;
public static WindowRectHooks WindowRectHooks { get; internal set; } = null!;
[PluginService] [PluginService]
public static IDalamudPluginInterface PluginInterface { get; private set; } = null!; public static IDalamudPluginInterface PluginInterface { get; private set; } = null!;