2023-07-12 22:41:31 +00:00
|
|
|
|
using MSFSPopoutPanelManager.DomainModel.Profile;
|
|
|
|
|
using MSFSPopoutPanelManager.DomainModel.Setting;
|
2022-07-25 12:40:21 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace MSFSPopoutPanelManager.WindowsAgent
|
|
|
|
|
{
|
|
|
|
|
public class TouchEventManager
|
|
|
|
|
{
|
|
|
|
|
private static IntPtr _hHook = IntPtr.Zero;
|
2024-02-28 02:44:21 +00:00
|
|
|
|
private static readonly PInvoke.WindowsHookExProc CallbackDelegate = HookCallBack;
|
2023-11-19 03:28:32 +00:00
|
|
|
|
private static bool _isTouchDownCompleted = true;
|
|
|
|
|
private static bool _isTouchUpCompleted = true;
|
2024-02-28 02:44:21 +00:00
|
|
|
|
private static bool _isDragged;
|
|
|
|
|
private static int _refocusedTaskIndex;
|
2022-07-25 12:40:21 +00:00
|
|
|
|
|
2024-02-28 02:44:21 +00:00
|
|
|
|
private static object _lock = new();
|
2023-11-19 03:28:32 +00:00
|
|
|
|
|
2022-07-25 12:40:21 +00:00
|
|
|
|
private const int PANEL_MENUBAR_HEIGHT = 31;
|
|
|
|
|
private const uint TOUCH_FLAG = 0xFF515700;
|
|
|
|
|
private const uint WM_MOUSEMOVE = 0x0200;
|
|
|
|
|
private const uint WM_LBUTTONDOWN = 0x0201;
|
|
|
|
|
private const uint WM_LBUTTONUP = 0x0202;
|
|
|
|
|
private const uint WM_RBUTTONDOWN = 0x0204;
|
|
|
|
|
private const uint WM_RBUTTONUP = 0x0205;
|
|
|
|
|
private const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
|
|
|
|
|
private const uint MOUSEEVENTF_LEFTUP = 0x0004;
|
|
|
|
|
|
2023-07-12 22:41:31 +00:00
|
|
|
|
public static UserProfile ActiveProfile { private get; set; }
|
2022-07-25 12:40:21 +00:00
|
|
|
|
|
2023-07-12 22:41:31 +00:00
|
|
|
|
public static ApplicationSetting ApplicationSetting { private get; set; }
|
2022-07-25 12:40:21 +00:00
|
|
|
|
|
|
|
|
|
public static void Hook()
|
|
|
|
|
{
|
2023-07-12 22:41:31 +00:00
|
|
|
|
Debug.WriteLine("Executing touch event manager mouse hook...");
|
2022-07-25 12:40:21 +00:00
|
|
|
|
|
2024-02-28 02:44:21 +00:00
|
|
|
|
var curProcess = Process.GetCurrentProcess();
|
|
|
|
|
var curModule = curProcess.MainModule;
|
2022-09-25 14:49:49 +00:00
|
|
|
|
|
2024-02-28 02:44:21 +00:00
|
|
|
|
if (curModule == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
var hookWindowPtr = PInvoke.GetModuleHandle(curModule.ModuleName);
|
|
|
|
|
_hHook = PInvoke.SetWindowsHookEx(HookType.WH_MOUSE_LL, CallbackDelegate, hookWindowPtr, 0);
|
2022-07-25 12:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void UnHook()
|
|
|
|
|
{
|
2022-09-25 14:49:49 +00:00
|
|
|
|
if (_hHook != IntPtr.Zero)
|
|
|
|
|
{
|
2023-07-12 22:41:31 +00:00
|
|
|
|
Debug.WriteLine("Executing touch event manager mouse unhook...");
|
|
|
|
|
|
2022-09-25 14:49:49 +00:00
|
|
|
|
PInvoke.UnhookWindowsHookEx(_hHook);
|
|
|
|
|
_hHook = IntPtr.Zero;
|
|
|
|
|
}
|
2022-07-25 12:40:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-28 02:44:21 +00:00
|
|
|
|
public static bool IsHooked => _hHook != IntPtr.Zero;
|
2022-07-25 12:40:21 +00:00
|
|
|
|
|
|
|
|
|
private static int HookCallBack(int code, IntPtr wParam, IntPtr lParam)
|
|
|
|
|
{
|
|
|
|
|
if (code != 0)
|
|
|
|
|
return PInvoke.CallNextHookEx(_hHook, code, wParam, lParam);
|
|
|
|
|
|
2024-02-28 02:44:21 +00:00
|
|
|
|
var ptrToStructure = Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
|
|
|
|
|
|
|
|
|
if (ptrToStructure == null)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
var info = (MSLLHOOKSTRUCT) ptrToStructure;
|
2022-07-25 12:40:21 +00:00
|
|
|
|
var extraInfo = (uint)info.dwExtraInfo;
|
|
|
|
|
var isTouched = (extraInfo & TOUCH_FLAG) == TOUCH_FLAG;
|
|
|
|
|
|
|
|
|
|
// Mouse Click
|
|
|
|
|
if (!isTouched)
|
|
|
|
|
{
|
|
|
|
|
switch ((uint)wParam)
|
|
|
|
|
{
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
case WM_LBUTTONUP:
|
2023-11-19 03:28:32 +00:00
|
|
|
|
if (!_isTouchDownCompleted)
|
2022-07-25 12:40:21 +00:00
|
|
|
|
return 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PInvoke.CallNextHookEx(_hHook, code, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If touch point is within pop out panel boundaries and have touch enabled
|
2022-09-11 13:50:04 +00:00
|
|
|
|
var panelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(p => p.TouchEnabled &&
|
2023-07-12 22:41:31 +00:00
|
|
|
|
(info.pt.X > p.Left
|
2022-07-25 12:40:21 +00:00
|
|
|
|
&& info.pt.X < p.Left + p.Width
|
2022-09-11 13:50:04 +00:00
|
|
|
|
&& info.pt.Y > p.Top + (p.HideTitlebar ? 5 : PANEL_MENUBAR_HEIGHT)
|
2023-07-12 22:41:31 +00:00
|
|
|
|
&& info.pt.Y < p.Top + p.Height));
|
2022-07-30 02:29:20 +00:00
|
|
|
|
|
|
|
|
|
if (panelConfig == null)
|
2022-07-25 12:40:21 +00:00
|
|
|
|
return PInvoke.CallNextHookEx(_hHook, code, wParam, lParam);
|
|
|
|
|
|
|
|
|
|
switch ((uint)wParam)
|
|
|
|
|
{
|
|
|
|
|
case WM_RBUTTONDOWN:
|
|
|
|
|
case WM_RBUTTONUP:
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
2023-11-19 03:28:32 +00:00
|
|
|
|
if (_isTouchDownCompleted && _isTouchUpCompleted)
|
2022-07-25 12:40:21 +00:00
|
|
|
|
{
|
2023-07-12 22:41:31 +00:00
|
|
|
|
_refocusedTaskIndex++;
|
2023-07-23 05:13:23 +00:00
|
|
|
|
if (panelConfig.PanelType == PanelType.RefocusDisplay)
|
|
|
|
|
return 1;
|
|
|
|
|
|
2023-11-19 03:28:32 +00:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_isTouchDownCompleted = false;
|
|
|
|
|
_isTouchUpCompleted = false;
|
|
|
|
|
}
|
2023-07-27 14:50:57 +00:00
|
|
|
|
|
2023-07-12 22:41:31 +00:00
|
|
|
|
Task.Run(() =>
|
2022-07-25 12:40:21 +00:00
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X + 1, info.pt.Y + 1, 0, 0); // focus window
|
|
|
|
|
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay + 10);
|
|
|
|
|
|
2023-07-12 22:41:31 +00:00
|
|
|
|
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, info.pt.X, info.pt.Y, 0, 0);
|
2023-11-05 02:16:41 +00:00
|
|
|
|
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay + 25);
|
2023-11-19 03:28:32 +00:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_isTouchDownCompleted = true;
|
|
|
|
|
}
|
2023-07-12 22:41:31 +00:00
|
|
|
|
});
|
2022-07-25 12:40:21 +00:00
|
|
|
|
}
|
2022-07-30 02:29:20 +00:00
|
|
|
|
return 1;
|
2022-07-25 12:40:21 +00:00
|
|
|
|
case WM_LBUTTONUP:
|
2023-11-19 03:28:32 +00:00
|
|
|
|
|
2023-07-27 14:50:57 +00:00
|
|
|
|
if (panelConfig.PanelType == PanelType.RefocusDisplay)
|
2022-07-25 12:40:21 +00:00
|
|
|
|
{
|
2023-07-27 14:50:57 +00:00
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_isTouchDownCompleted = true;
|
|
|
|
|
_isDragged = false;
|
|
|
|
|
_isTouchUpCompleted = true;
|
|
|
|
|
}
|
2023-07-27 14:50:57 +00:00
|
|
|
|
|
|
|
|
|
// Refocus game window
|
|
|
|
|
if (ApplicationSetting.RefocusSetting.RefocusGameWindow.IsEnabled && panelConfig.AutoGameRefocus)
|
|
|
|
|
{
|
|
|
|
|
var currentRefocusIndex = _refocusedTaskIndex;
|
|
|
|
|
|
|
|
|
|
Thread.Sleep(Convert.ToInt32(ApplicationSetting.RefocusSetting.RefocusGameWindow.Delay * 1000));
|
|
|
|
|
|
|
|
|
|
if (currentRefocusIndex == _refocusedTaskIndex)
|
|
|
|
|
{
|
|
|
|
|
var rect = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
|
|
|
|
|
InputEmulationManager.LeftClick(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Task.Run(() =>
|
2022-07-25 12:40:21 +00:00
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
SpinWait.SpinUntil(() => _isTouchDownCompleted, TimeSpan.FromSeconds(0.25));
|
|
|
|
|
|
2023-07-23 05:13:23 +00:00
|
|
|
|
if (_isDragged)
|
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
// Need this for PMS GTN750
|
2023-11-05 02:16:41 +00:00
|
|
|
|
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
|
|
|
|
|
Thread.Sleep(ApplicationSetting.TouchSetting.TouchDownUpDelay + 25);
|
2023-07-23 05:13:23 +00:00
|
|
|
|
}
|
2023-11-19 03:28:32 +00:00
|
|
|
|
|
|
|
|
|
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
|
|
|
|
|
|
|
|
|
|
lock (_lock)
|
2023-07-23 05:13:23 +00:00
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
_isDragged = false;
|
|
|
|
|
_isTouchDownCompleted = true;
|
|
|
|
|
_isTouchUpCompleted = true;
|
2023-07-23 05:13:23 +00:00
|
|
|
|
}
|
2023-07-12 22:41:31 +00:00
|
|
|
|
|
2023-07-27 14:50:57 +00:00
|
|
|
|
// Refocus game window
|
|
|
|
|
if (ApplicationSetting.RefocusSetting.RefocusGameWindow.IsEnabled && panelConfig.AutoGameRefocus)
|
2022-09-25 14:49:49 +00:00
|
|
|
|
{
|
2023-07-27 14:50:57 +00:00
|
|
|
|
var currentRefocusIndex = _refocusedTaskIndex;
|
2023-07-23 05:13:23 +00:00
|
|
|
|
|
2023-07-27 14:50:57 +00:00
|
|
|
|
Thread.Sleep(Convert.ToInt32(ApplicationSetting.RefocusSetting.RefocusGameWindow.Delay * 1000));
|
|
|
|
|
|
|
|
|
|
if (currentRefocusIndex == _refocusedTaskIndex)
|
|
|
|
|
{
|
2024-03-15 12:55:55 +00:00
|
|
|
|
PInvoke.SetForegroundWindow(WindowProcessManager.SimulatorProcess.Handle);
|
|
|
|
|
|
2023-07-27 14:50:57 +00:00
|
|
|
|
var rect = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
|
|
|
|
|
PInvoke.SetCursorPos(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
|
|
|
|
|
}
|
2022-09-25 14:49:49 +00:00
|
|
|
|
}
|
2023-07-27 14:50:57 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
2023-11-19 03:28:32 +00:00
|
|
|
|
|
2022-07-25 12:40:21 +00:00
|
|
|
|
return 1;
|
|
|
|
|
case WM_MOUSEMOVE:
|
2023-11-19 03:28:32 +00:00
|
|
|
|
if (!_isTouchDownCompleted)
|
2023-07-12 22:41:31 +00:00
|
|
|
|
{
|
2023-11-19 03:28:32 +00:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_isDragged = true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-30 02:29:20 +00:00
|
|
|
|
return 1;
|
2023-07-12 22:41:31 +00:00
|
|
|
|
}
|
2023-11-19 03:28:32 +00:00
|
|
|
|
|
2022-07-25 12:40:21 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PInvoke.CallNextHookEx(_hHook, code, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|