Helpers
DockingHelper.cs
//-----------------------------------------------------------------------
//
// Copyright © Wohs Inc.
//
//-----------------------------------------------------------------------
namespace Lurker.Helpers
{
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Lurker.Extensions;
using Lurker.Models;
using Lurker.Services;
using static Lurker.Native;
///
/// Represents DockingHelper.
///
///
public clast DockingHelper : IDisposable
{
#region Fields
private const uint GainMouseCapture = 8;
private const uint LostMouseCapture = 9;
private const uint MoveEnd = 11;
private static readonly int DefaultFlaskBarHeight = 122;
private static readonly int DefaultFlaskBarWidth = 550;
private static readonly int DefaultExpBarHeight = 24;
private static readonly int DefaultHeight = 1080;
private readonly uint _windowProcessId;
private readonly uint _windowOwnerId;
private readonly WinEventDelegate _winEventDelegate;
private Process _myProcess;
private CancellationTokenSource _tokenSource;
private SettingsService _settingsService;
private IntPtr _hook;
private IntPtr _windowHandle;
private IntPtr _currentWindowStyle;
private Process _process;
#endregion
#region Constructors
///
/// Initializes a new instance of the clast.
///
/// The process identifier.
/// The settings service.
public DockingHelper(int processId, SettingsService settingsService)
{
this._process = ProcessLurker.GetProcessById(processId);
if (this._process != null)
{
this._myProcess = Process.GetCurrentProcess();
this._tokenSource = new CancellationTokenSource();
this._settingsService = settingsService;
this._windowHandle = this._process.GetWindowHandle();
this._windowOwnerId = GetWindowThreadProcessId(this._windowHandle, out this._windowProcessId);
this._winEventDelegate = this.WhenWindowMoveStartsOrEnds;
this._hook = SetWinEventHook(0, MoveEnd, this._windowHandle, this._winEventDelegate, this._windowProcessId, this._windowOwnerId, 0);
this.WindowInformation = this.GetWindowInformation();
this.WatchForegound();
/*if (settingsService.VulkanRenderer)
{
this.RemoveWindowBorder();
}*/
}
}
#endregion
#region Events
///
/// Occurs when [on window move].
///
public event EventHandler OnWindowMove;
///
/// Occurs when [on lost mouse capture].
///
public event EventHandler OnLostMouseCapture;
///
/// Occurs when [on mouse capture].
///
public event EventHandler OnMouseCapture;
///
/// Occurs when [on foreground change].
///
public event EventHandler OnForegroundChange;
#endregion
#region Properties
///
/// Gets a value indicating whether this instance is window in foreground.
///
public bool IsWindowInForeground => this._windowHandle == Native.GetForegroundWindow();
///
/// Gets the window information.
///
public PoeWindowInformation WindowInformation { get; private set; }
#endregion
#region Methods
///
/// Performs application-defined tasks astociated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
this.Dispose(true);
}
///
/// Sets the foreground.
///
public void SetForeground()
{
this.SetForeground(this._windowHandle);
}
///
/// Sets the foreground.
///
/// The handle.
public void SetForeground(IntPtr handle)
{
Native.SetForegroundWindow(handle);
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
this._myProcess.Dispose();
this._tokenSource.Cancel();
UnhookWinEvent(this._hook);
}
}
///
/// Removes the window border.
///
private void RemoveWindowBorder()
{
// Native.SetWindowLongPtr(new HandleRef(this, this._windowHandle), -16, (IntPtr)0x10000000);
Native.SetWindowLong(this._windowHandle, -16, 0x10000000);
}
///
/// Whens the window move starts or ends.
///
/// The h win event hook.
/// Type of the event.
/// The HWND.
/// The identifier object.
/// The identifier child.
/// The dw event thread.
/// The DWMS event time.
private void WhenWindowMoveStartsOrEnds(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (this._windowHandle != hwnd)
{
return;
}
switch (eventType)
{
case MoveEnd:
this.InvokeWindowMove();
break;
case GainMouseCapture:
this.Invoke(this.OnMouseCapture);
break;
case LostMouseCapture:
this.Invoke(this.OnLostMouseCapture);
break;
}
}
///
/// Watches the foregound.
///
private async void WatchForegound()
{
var token = this._tokenSource.Token;
while (true)
{
try
{
if (token.IsCancellationRequested)
{
return;
}
var inForeground = false;
var foregroundWindow = Native.GetForegroundWindow();
GetWindowThreadProcessId(foregroundWindow, out var processId);
var style = Native.GetWindowLong(this._windowHandle, -16);
if (this._currentWindowStyle != style)
{
switch ((uint)style)
{
case 0x14cf0000:
PoeApplicationContext.WindowStyle = WindowStyle.Windowed;
break;
case 0x94000000:
PoeApplicationContext.WindowStyle = WindowStyle.WindowedFullScreen;
break;
}
this._currentWindowStyle = style;
this.InvokeWindowMove();
}
if (processId == this._myProcess.Id || foregroundWindow == this._windowHandle)
{
inForeground = true;
}
if (PoeApplicationContext.InForeground != inForeground)
{
PoeApplicationContext.InForeground = inForeground;
if (this._settingsService.HideInBackground)
{
this.OnForegroundChange?.Invoke(this, inForeground);
}
}
await Task.Delay(500);
}
catch
{
}
}
}
///
/// Invokes the specified handler.
///
/// The handler.
private void Invoke(EventHandler handler)
{
handler?.Invoke(this, EventArgs.Empty);
}
///
/// Invokes the window move.
///
private void InvokeWindowMove()
{
this.WindowInformation = this.GetWindowInformation();
this.OnWindowMove?.Invoke(this, this.WindowInformation);
}
///
/// Gets the window information.
///
/// The poe window information.
private PoeWindowInformation GetWindowInformation()
{
Rect poePosition = default;
Native.GetWindowRect(this._windowHandle, ref poePosition);
double poeWidth = poePosition.Right - poePosition.Left;
double poeHeight = poePosition.Bottom - poePosition.Top;
var expBarHeight = poeHeight * DefaultExpBarHeight / DefaultHeight;
var flaskBarWidth = poeHeight * DefaultFlaskBarWidth / DefaultHeight;
var flaskBarHeight = poeHeight * DefaultFlaskBarHeight / DefaultHeight;
return new PoeWindowInformation()
{
Height = poeHeight,
Width = poeWidth,
ExpBarHeight = expBarHeight,
FlaskBarHeight = flaskBarHeight,
FlaskBarWidth = flaskBarWidth,
Position = poePosition,
};
}
#endregion
}
}