using System; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using LLib.ImGui; using Microsoft.Extensions.Logging; namespace LLib.Notifications; public sealed class OutOfGameNotifier : IDisposable { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct NOTIFYICONDATA { public uint cbSize; public nint hWnd; public uint uID; public uint uFlags; public uint uCallbackMessage; public nint hIcon; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szTip; public uint dwState; public uint dwStateMask; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szInfo; public uint uTimeoutOrVersion; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string szInfoTitle; public uint dwInfoFlags; public Guid guidItem; public nint hBalloonIcon; } private static class NativeMethods { [DllImport("user32.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] public static extern nint GetForegroundWindow(); [DllImport("user32.dll")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool MessageBeep(uint uType); [DllImport("winmm.dll", CharSet = CharSet.Unicode, EntryPoint = "PlaySoundW")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool PlaySound(string? pszSound, nint hmod, uint fdwSound); [DllImport("user32.dll", CharSet = CharSet.Auto)] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] public static extern nint SendMessage(nint hWnd, uint msg, nint wParam, nint lParam); [DllImport("user32.dll", EntryPoint = "GetClassLongPtrW")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] public static extern nint GetClassLongPtr(nint hWnd, int nIndex); [DllImport("user32.dll", EntryPoint = "LoadIconW")] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] public static extern nint LoadIcon(nint hInstance, nint lpIconName); [DllImport("shell32.dll", CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool Shell_NotifyIcon(uint dwMessage, ref NOTIFYICONDATA lpData); } private const uint NIM_ADD = 0u; private const uint NIM_MODIFY = 1u; private const uint NIM_DELETE = 2u; private const uint NIM_SETVERSION = 4u; private const uint NIF_ICON = 2u; private const uint NIF_TIP = 4u; private const uint NIF_INFO = 16u; private const uint NIIF_INFO = 1u; private const uint NOTIFYICON_VERSION_4 = 4u; private const uint MB_ICONASTERISK = 64u; private const uint SND_ASYNC = 1u; private const uint SND_NODEFAULT = 2u; private const uint SND_FILENAME = 131072u; private const uint WM_GETICON = 127u; private const nint ICON_SMALL = 0; private const nint ICON_BIG = 1; private const int GCLP_HICON = -14; private const int GCLP_HICONSM = -34; private const nint IDI_APPLICATION = 32512; private const uint TrayIconId = 176u; private readonly ILogger _logger; private bool _trayIconRegistered; private nint _trayHWnd; private bool _disposed; private unsafe static nint GameWindowHandle { get { Device* ptr = Device.Instance(); int num = ((ptr != null) ? 539179088 : 539179091); while (true) { int num2 = num; int num3 = 539179090; int num4 = num2; int num5 = num4 + num3; int num6 = num4 & num3; switch (num5 - (num6 + num6)) { case 0: goto IL_004b; case 2: return (nint)ptr->hWnd; case 1: return 0; } continue; IL_004b: num = 539179091; } } } public bool IsGameForeground { get { nint gameWindowHandle = GameWindowHandle; int num = ((gameWindowHandle == 0) ? 1427669893 : 1427669894); while (true) { int num2 = num; int num3 = 1427669892; int num4 = num2; int num5 = num4 + num3; int num6 = num4 & num3; switch (num5 - (num6 + num6)) { case 0: goto IL_0049; case 1: return false; case 2: return NativeMethods.GetForegroundWindow() == gameWindowHandle; } continue; IL_0049: num = 1427669894; } } } public OutOfGameNotifier(ILogger logger) { _logger = logger; } public void FlashTaskbar() { WindowFlash.Flash(GameWindowHandle, 0u); } [MethodImpl(MethodImplOptions.NoInlining)] public void PlayAlertSound(string? wavPath) { int num = (_202E_202E_200E_206D_200E_202B_206E_206C_202D_202D_202D_200B_206D_200C_200E_206B_206B_202D_202B_206A_202B_206A_200D_206B_206E_202B_200B_202C_206D_206F_200B_206C_200D_206D_206B_206E_200B_200C_200D_200D_202E(wavPath) ? 199681171 : 199681169); while (true) { int num2 = num; int num3 = 199681171; int num4 = num2; switch ((num4 | num3) - (num4 & num3)) { case 5: num = 199681169; break; case 3: num = ((!NativeMethods.PlaySound(wavPath, 0, 131075u)) ? 199681170 : 199681175); break; case 1: _200E_200D_202A_200C_206A_206E_200D_202D_206C_202E_202D_202C_202E_200D_200E_206D_206D_200D_200E_206F_206F_200E_202B_202B_200C_200B_200B_200B_206E_200E_206B_206F_200B_206C_200B_202C_206B_200C_200B_206F_202E((ILogger)_logger, global::_003CModule_003E._206A_202C_200C_206F_202A_200C_200F_206F_202B_202B_200D_206F_206D_200E_206A_206B_202A_200F_200B_206C_202B_202A_202B_206C_200F_206C_202C_202C_200C_206C_206F_200C_200B_202D_200E_202A_202A_206B_206B_200F_202E(-928191835), new object[1] { wavPath }); num = 199681171; break; case 2: num = ((!_200C_200B_202C_206C_206B_202D_206B_202C_202D_206C_202D_200C_206A_200F_206F_206B_202D_200F_206B_202E_206F_202B_206D_200C_202B_206D_202C_200D_200F_202E_202E_200E_206E_200F_200C_206D_200F_202A_200B_200E_202E(wavPath)) ? 199681171 : 199681168); break; case 0: num = (NativeMethods.MessageBeep(64u) ? 199681172 : 199681173); break; case 7: return; case 6: _200E_200D_202A_200C_206A_206E_200D_202D_206C_202E_202D_202C_202E_200D_200E_206D_206D_200D_200E_206F_206F_200E_202B_202B_200C_200B_200B_200B_206E_200E_206B_206F_200B_206C_200B_202C_206B_200C_200B_206F_202E((ILogger)_logger, global::_003CModule_003E._200E_206F_206C_206C_200E_202A_206D_206B_200B_202D_202B_200F_200F_206B_206C_206F_202D_206F_206A_202D_206A_200B_200B_202B_202D_202C_200F_200D_202E_200E_200D_202A_202B_206F_202E_200E_200B_206B_200E_202E_202E(1376931042), Array.Empty()); num = 199681172; break; case 4: return; } } } [MethodImpl(MethodImplOptions.NoInlining)] public void ShowTrayNotification(string title, string message) { nint gameWindowHandle = GameWindowHandle; int num = ((gameWindowHandle != 0) ? (-102834731) : (-102834730)); nint num8 = default(nint); while (true) { int num2 = num; int num3 = -102834732; int num4 = num2; switch ((num4 | num3) - (num4 & num3)) { case 0: goto IL_0050; case 2: _202C_202E_200B_206C_202C_206E_206E_202C_206B_206D_206F_206B_202C_202C_202A_206B_200B_206C_202B_202C_206F_206F_206F_202B_202C_200E_206B_200D_206B_200D_202C_202E_206D_206E_206D_206D_202D_206B_202E_206E_202E((ILogger)_logger, global::_003CModule_003E._206A_202C_200C_206F_202A_200C_200F_206F_202B_202B_200D_206F_206D_200E_206A_206B_202A_200F_200B_206C_202B_202A_202B_206C_200F_206C_202C_202C_200C_206C_206F_200C_200B_202D_200E_202A_202A_206B_206B_200F_202E(-498044301), Array.Empty()); return; case 1: try { num = (_trayIconRegistered ? (-1863308179) : (-1863308178)); while (true) { int num5 = num; num3 = -1863308179; num4 = num5; int num6 = num4 + num3; int num7 = num4 & num3; switch (num6 - (num7 + num7)) { case 4: { NOTIFYICONDATA lpData3 = new NOTIFYICONDATA { cbSize = (uint)Marshal.SizeOf(), hWnd = gameWindowHandle, uID = 176u, uTimeoutOrVersion = 4u }; NativeMethods.Shell_NotifyIcon(4u, ref lpData3); _trayHWnd = gameWindowHandle; _trayIconRegistered = true; num = -1863308179; break; } case 3: num8 = GetGameIcon(gameWindowHandle); num = ((num8 != 0) ? (-1863308184) : (-1863308180)); break; case 8: _202C_202E_200B_206C_202C_206E_206E_202C_206B_206D_206F_206B_202C_202C_202A_206B_200B_206C_202B_202C_206F_206F_206F_202B_202C_200E_206B_200D_206B_200D_202C_202E_206D_206E_206D_206D_202D_206B_202E_206E_202E((ILogger)_logger, global::_003CModule_003E._206E_202B_206C_202A_202A_200E_202B_202B_206D_200B_200C_206B_200B_206D_202E_202D_206C_202B_200B_206A_202D_206C_202A_200F_202D_200C_200B_200B_200B_200D_202C_206E_206D_202E_200C_206B_206A_206D_202D_202C_202E(-218723301), Array.Empty()); num = -1863308177; break; case 7: _202C_202E_200B_206C_202C_206E_206E_202C_206B_206D_206F_206B_202C_202C_202A_206B_200B_206C_202B_202C_206F_206F_206F_202B_202C_200E_206B_200D_206B_200D_202C_202E_206D_206E_206D_206D_202D_206B_202E_206E_202E((ILogger)_logger, global::_003CModule_003E._206A_206D_202C_206E_206D_206E_202A_200F_200D_206A_200F_206C_202C_202D_206D_206A_200D_200F_206A_206C_202C_206D_206E_200F_200F_200C_206B_200B_206B_206E_202B_206B_200E_200E_200B_206F_200F_202E_200C_200C_202E(621311524), Array.Empty()); return; case 6: num = -1863308178; break; case 1: num8 = NativeMethods.LoadIcon(0, 32512); num = -1863308184; break; case 0: { NOTIFYICONDATA lpData2 = new NOTIFYICONDATA { cbSize = (uint)Marshal.SizeOf(), hWnd = _trayHWnd, uID = 176u, uFlags = 16u, szInfoTitle = Truncate(title, 63), szInfo = Truncate(message, 255), dwInfoFlags = 1u }; num = (NativeMethods.Shell_NotifyIcon(1u, ref lpData2) ? (-1863308177) : (-1863308187)); break; } case 5: { NOTIFYICONDATA lpData = new NOTIFYICONDATA { cbSize = (uint)Marshal.SizeOf(), hWnd = gameWindowHandle, uID = 176u, uFlags = 6u, hIcon = num8, szTip = Truncate(title, 127) }; num = (NativeMethods.Shell_NotifyIcon(0u, ref lpData) ? (-1863308183) : (-1863308182)); break; } case 2: return; } } } catch (Exception ex) { _206E_206A_206C_200C_200F_206C_202C_206E_206D_202C_200B_202B_202D_206C_202E_206C_200C_200E_206E_200E_202C_206F_202C_200B_202D_200F_200C_200F_202E_200F_200C_200D_206E_202B_200D_202B_202A_202B_200E_202E_202E((ILogger)_logger, ex, global::_003CModule_003E._206E_202B_206C_202A_202A_200E_202B_202B_206D_200B_200C_206B_200B_206D_202E_202D_206C_202B_200B_206A_202D_206C_202A_200F_202D_200C_200B_200B_200B_200D_202C_206E_206D_202E_200C_206B_206A_206D_202D_202C_202E(1309216025), Array.Empty()); return; } } continue; IL_0050: num = -102834730; } } private static nint GetGameIcon(nint hWnd) { nint num = NativeMethods.SendMessage(hWnd, 127u, 1, 0); int num2 = ((num != 0) ? 1006480639 : 1006480632); while (true) { int num3 = num2; int num4 = 1006480638; int num5 = num3; switch ((num5 | num4) - (num5 & num4)) { case 4: num2 = 1006480632; break; case 5: num = NativeMethods.GetClassLongPtr(hWnd, -14); num2 = 1006480637; break; case 1: num2 = ((num != 0) ? 1006480637 : 1006480635); break; case 2: return num; case 0: num = NativeMethods.GetClassLongPtr(hWnd, -34); num2 = 1006480636; break; case 3: num2 = ((num != 0) ? 1006480636 : 1006480638); break; case 6: num = NativeMethods.SendMessage(hWnd, 127u, 0, 0); num2 = 1006480639; break; } } } private static string Truncate(string value, int maxChars) { int num = ((_202C_206C_206F_202B_202E_206A_202C_206B_200F_200E_200F_200C_202E_202E_206C_206D_200C_200D_206A_202D_206B_200B_206E_206F_206F_200E_206B_202C_202A_202D_206C_206B_200D_200D_200E_200B_202A_202C_200D_206D_202E(value) <= maxChars) ? (-362575814) : (-362575815)); while (true) { int num2 = num; int num3 = -362575813; int num4 = num2; switch ((num4 | num3) - (num4 & num3)) { case 0: goto IL_0047; case 2: return _200D_200D_200D_206C_200B_206C_200B_206A_206B_202D_202B_202E_200D_206E_206D_202A_200C_206C_200C_202C_206D_200B_200C_202B_202B_200F_202B_202A_200E_202E_200C_200B_206B_206A_202A_200C_200C_206D_206B_206A_202E(value, 0, maxChars); case 1: return value; } continue; IL_0047: num = -362575815; } } public void Dispose() { int num = ((!_disposed) ? 413573275 : 413573272); while (true) { int num2 = num; int num3 = 413573273; int num4 = num2; switch ((num4 | num3) - (num4 & num3)) { case 0: return; case 1: return; case 4: { NOTIFYICONDATA lpData = new NOTIFYICONDATA { cbSize = (uint)Marshal.SizeOf(), hWnd = _trayHWnd, uID = 176u }; NativeMethods.Shell_NotifyIcon(2u, ref lpData); _trayIconRegistered = false; return; } case 2: _disposed = true; num = (_trayIconRegistered ? 413573277 : 413573273); break; case 3: num = 413573272; break; } } } void IDisposable.Dispose() { //ILSpy generated this explicit interface implementation from .override directive in Dispose this.Dispose(); } static bool _202E_202E_200E_206D_200E_202B_206E_206C_202D_202D_202D_200B_206D_200C_200E_206B_206B_202D_202B_206A_202B_206A_200D_206B_206E_202B_200B_202C_206D_206F_200B_206C_200D_206D_206B_206E_200B_200C_200D_200D_202E(string P_0) { return string.IsNullOrEmpty(P_0); } static bool _200C_200B_202C_206C_206B_202D_206B_202C_202D_206C_202D_200C_206A_200F_206F_206B_202D_200F_206B_202E_206F_202B_206D_200C_202B_206D_202C_200D_200F_202E_202E_200E_206E_200F_200C_206D_200F_202A_200B_200E_202E(string P_0) { return File.Exists(P_0); } static void _200E_200D_202A_200C_206A_206E_200D_202D_206C_202E_202D_202C_202E_200D_200E_206D_206D_200D_200E_206F_206F_200E_202B_202B_200C_200B_200B_200B_206E_200E_206B_206F_200B_206C_200B_202C_206B_200C_200B_206F_202E(ILogger P_0, string P_1, object[] P_2) { P_0.LogTrace(P_1, P_2); } static void _202C_202E_200B_206C_202C_206E_206E_202C_206B_206D_206F_206B_202C_202C_202A_206B_200B_206C_202B_202C_206F_206F_206F_202B_202C_200E_206B_200D_206B_200D_202C_202E_206D_206E_206D_206D_202D_206B_202E_206E_202E(ILogger P_0, string P_1, object[] P_2) { P_0.LogWarning(P_1, P_2); } static void _206E_206A_206C_200C_200F_206C_202C_206E_206D_202C_200B_202B_202D_206C_202E_206C_200C_200E_206E_200E_202C_206F_202C_200B_202D_200F_200C_200F_202E_200F_200C_200D_206E_202B_200D_202B_202A_202B_200E_202E_202E(ILogger P_0, Exception P_1, string P_2, object[] P_3) { P_0.LogError(P_1, P_2, P_3); } static int _202C_206C_206F_202B_202E_206A_202C_206B_200F_200E_200F_200C_202E_202E_206C_206D_200C_200D_206A_202D_206B_200B_206E_206F_206F_200E_206B_202C_202A_202D_206C_206B_200D_200D_200E_200B_202A_202C_200D_206D_202E(string P_0) { return P_0.Length; } static string _200D_200D_200D_206C_200B_206C_200B_206A_206B_202D_202B_202E_200D_206E_206D_202A_200C_206C_200C_202C_206D_200B_200C_202B_202B_200F_202B_202A_200E_202E_200C_200B_206B_206A_202A_200C_200C_206D_206B_206A_202E(string P_0, int P_1, int P_2) { return P_0.Substring(P_1, P_2); } }