177 lines
4.7 KiB
C#
177 lines
4.7 KiB
C#
using CustomResolution.WndProcHookManagerProxyApi;
|
|
using Serilog.Events;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Reflection.Emit;
|
|
using TerraFX.Interop.Windows;
|
|
using static TerraFX.Interop.Windows.Windows;
|
|
|
|
|
|
namespace CustomResolution.Hooks;
|
|
|
|
// THIS. IS. UGLY.
|
|
public sealed unsafe class WndProcHook : IDisposable
|
|
{
|
|
private static WndProcHook? _instance;
|
|
|
|
private readonly WndProcHookManager _manager;
|
|
|
|
private bool _applied = false;
|
|
private DynamicMethod? _genMethod;
|
|
private Delegate? _genDelegate;
|
|
|
|
public WndProcHook()
|
|
{
|
|
_instance = this;
|
|
|
|
_manager = new();
|
|
|
|
Apply();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_applied)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_manager.PreWndProc is not { } preWndProcProp)
|
|
{
|
|
Service.PluginLog.Information("CustomResolution couldn't obtain the PreWndProc event.");
|
|
|
|
return;
|
|
}
|
|
|
|
preWndProcProp.RemoveEventHandler(_manager.ProxiedValue, _genDelegate);
|
|
|
|
_applied = false;
|
|
}
|
|
|
|
public static void InvokeStatic(object args)
|
|
{
|
|
if (_instance is { } instance)
|
|
{
|
|
instance.Invoke(new WndProcEventArgs(instance._manager, args));
|
|
}
|
|
}
|
|
|
|
private static void ParamToCoords(LPARAM param, out int x, out int y)
|
|
{
|
|
x = (short) (ushort) (param.Value & 0xFFFF);
|
|
y = (short) (ushort) (param.Value >> 16 & 0xFFFF);
|
|
}
|
|
|
|
private static LPARAM CoordsToParam(int x, int y)
|
|
{
|
|
nint value = 0;
|
|
value |= ((ushort) (short) x) & 0xFFFF;
|
|
value |= ((ushort) (short) y) >> 16 & 0xFFFF;
|
|
|
|
return value;
|
|
}
|
|
|
|
private void Invoke(WndProcEventArgs args)
|
|
{
|
|
if (Service.Plugin is not { } plugin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (WM.WM_MOUSEFIRST <= args.Message && args.Message <= WM.WM_MOUSELAST)
|
|
{
|
|
ParamToCoords(args.LParam, out int x, out int y);
|
|
|
|
#if false
|
|
Service.PluginLog.Debug($"WM_MOUSE A @ {x} {y}");
|
|
#endif
|
|
|
|
plugin.ConvertCoordsWinToGame(ref x, ref y);
|
|
|
|
#if false
|
|
Service.PluginLog.Debug($"WM_MOUSE B @ {x} {y}");
|
|
#endif
|
|
|
|
args.LParam = CoordsToParam(x, y);
|
|
}
|
|
|
|
if (args.Message == WM.WM_NCCALCSIZE && args.WParam != 0 && plugin.CurrentBorderlessFullscreen &&
|
|
Service.Config.DXVKDWMHackMode.IsSetClientEdge())
|
|
{
|
|
NCCALCSIZE_PARAMS* ncsize = (NCCALCSIZE_PARAMS*) args.LParam;
|
|
MONITORINFO monitorInfo = new()
|
|
{
|
|
cbSize = (uint) sizeof(MONITORINFO)
|
|
};
|
|
|
|
if (MonitorFromWindow(plugin.CurrentHWND, MONITOR.MONITOR_DEFAULTTONEAREST) is { } monitor && monitor != HMONITOR.NULL &&
|
|
GetMonitorInfo(monitor, &monitorInfo))
|
|
{
|
|
ncsize->rgrc[0] = monitorInfo.rcMonitor;
|
|
|
|
switch (Service.Config.DXVKDWMHackMode)
|
|
{
|
|
case DXVKDWMHackMode.SetClientEdgeResize:
|
|
ncsize->rgrc[0].bottom += 1;
|
|
break;
|
|
|
|
case DXVKDWMHackMode.SetClientEdgeBorder:
|
|
ncsize->rgrc[0].left += 1;
|
|
ncsize->rgrc[0].top += 1;
|
|
ncsize->rgrc[0].right -= 1;
|
|
ncsize->rgrc[0].bottom -= 1;
|
|
break;
|
|
}
|
|
|
|
args.SuppressCall = true;
|
|
}
|
|
|
|
// TODO: Check if border + repaing nc area to black works? Otherwise unset composited
|
|
}
|
|
}
|
|
|
|
private void Apply()
|
|
{
|
|
if (!_manager.Refresh())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_applied)
|
|
{
|
|
Dispose();
|
|
}
|
|
|
|
if (_manager.PreWndProc is not { } preWndProcProp)
|
|
{
|
|
Service.PluginLog.Information("CustomResolution couldn't obtain the PreWndProc event.");
|
|
|
|
return;
|
|
}
|
|
|
|
if (_genDelegate is null)
|
|
{
|
|
var delegateType = preWndProcProp.EventHandlerType!;
|
|
var delegateInvoke = delegateType.GetMethod("Invoke")!;
|
|
|
|
_genMethod = new DynamicMethod(
|
|
"CustomResolution_PreWndProc",
|
|
delegateInvoke.ReturnType,
|
|
delegateInvoke.GetParameters().Select(p => p.ParameterType).ToArray()
|
|
);
|
|
|
|
var il = _genMethod.GetILGenerator();
|
|
|
|
il.Emit(OpCodes.Ldarg_0);
|
|
il.Emit(OpCodes.Call, typeof(WndProcHook).GetMethod("InvokeStatic")!);
|
|
il.Emit(OpCodes.Ret);
|
|
|
|
_genDelegate = _genMethod.CreateDelegate(delegateType);
|
|
}
|
|
|
|
preWndProcProp.AddEventHandler(_manager.ProxiedValue, _genDelegate);
|
|
|
|
_applied = true;
|
|
}
|
|
}
|