1
0
Fork 0
mirror of https://github.com/hawkeye-stan/msfs-popout-panel-manager.git synced 2024-12-01 10:10:11 +00:00
msfs-popout-panel-manager/WindowsAgent/InputEmulationManager.cs

266 lines
11 KiB
C#
Raw Normal View History

2023-07-12 22:41:31 +00:00
using MSFSPopoutPanelManager.DomainModel.Profile;
2022-10-16 13:11:01 +00:00
using System;
2023-07-12 22:41:31 +00:00
using System.Diagnostics;
2022-01-27 13:40:04 +00:00
using System.Drawing;
2021-12-14 05:40:07 +00:00
using System.Threading;
2022-07-23 19:23:32 +00:00
using WindowsInput;
2021-12-14 05:40:07 +00:00
2022-07-23 19:23:32 +00:00
namespace MSFSPopoutPanelManager.WindowsAgent
2021-12-14 05:40:07 +00:00
{
public class InputEmulationManager
{
const uint MOUSEEVENTF_LEFTDOWN = 0x02;
const uint MOUSEEVENTF_LEFTUP = 0x04;
2023-07-12 22:41:31 +00:00
const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
const uint MOUSEEVENTF_RIGHTUP = 0x10;
2021-12-14 05:40:07 +00:00
const uint KEYEVENTF_EXTENDEDKEY = 0x01;
const uint KEYEVENTF_KEYDOWN = 0x0;
const uint KEYEVENTF_KEYUP = 0x2;
const uint VK_RMENU = 0xA5;
const uint VK_LMENU = 0xA4;
const uint VK_LCONTROL = 0xA2;
2022-08-01 23:21:42 +00:00
const uint VK_RCONTROL = 0xA3;
2021-12-14 05:40:07 +00:00
const uint VK_SPACE = 0x20;
2022-04-18 19:52:39 +00:00
const uint VK_ENT = 0x0D;
2021-12-14 05:40:07 +00:00
const uint KEY_0 = 0x30;
2022-07-23 20:04:06 +00:00
private static InputSimulator InputSimulator = new InputSimulator();
2022-07-23 19:23:32 +00:00
2021-12-14 05:40:07 +00:00
public static void LeftClick(int x, int y)
{
PInvoke.SetCursorPos(x, y);
Thread.Sleep(300);
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2023-07-12 22:41:31 +00:00
Thread.Sleep(200);
2021-12-14 05:40:07 +00:00
}
2022-06-13 03:49:56 +00:00
public static void LeftClickFast(int x, int y)
{
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(50);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
}
2023-07-12 22:41:31 +00:00
public static void PopOutPanel(int x, int y, bool useSecondaryKeys)
2022-07-23 19:23:32 +00:00
{
2023-07-12 22:41:31 +00:00
Debug.WriteLine($"Pop out panel at: {x}/{y} ...");
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
PInvoke.SetForegroundWindow(WindowProcessManager.SimulatorProcess.Handle);
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
MoveAppWindowFromLeftClickPoint(x, y);
2022-02-07 03:05:05 +00:00
2023-07-12 22:41:31 +00:00
LeftClick(x, y);
2021-12-14 05:40:07 +00:00
2022-08-18 14:20:12 +00:00
if (useSecondaryKeys)
2022-07-23 19:23:32 +00:00
{
2022-07-23 20:04:06 +00:00
InputSimulator.Keyboard.KeyDown(WindowsInput.Native.VirtualKeyCode.LCONTROL);
InputSimulator.Keyboard.KeyDown(WindowsInput.Native.VirtualKeyCode.RCONTROL);
2022-07-23 19:23:32 +00:00
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2023-07-30 05:43:17 +00:00
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2022-07-23 20:04:06 +00:00
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.RCONTROL);
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.LCONTROL);
2023-07-12 22:41:31 +00:00
Thread.Sleep(100);
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.RCONTROL); // resend to make sure Ctrl key is up
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.LCONTROL);
2022-07-23 19:23:32 +00:00
}
else
{
2023-07-12 22:41:31 +00:00
InputSimulator.Keyboard.KeyDown(WindowsInput.Native.VirtualKeyCode.RMENU);
2022-07-23 19:23:32 +00:00
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2023-07-30 05:43:17 +00:00
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, x, y, 0, 0);
2023-07-12 22:41:31 +00:00
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.RMENU);
Thread.Sleep(100);
InputSimulator.Keyboard.KeyUp(WindowsInput.Native.VirtualKeyCode.RMENU); // resend to make sure Alt key is up
2022-07-23 19:23:32 +00:00
}
2021-12-14 05:40:07 +00:00
}
2022-07-23 19:23:32 +00:00
public static void CenterView()
2021-12-14 05:40:07 +00:00
{
2023-07-12 22:41:31 +00:00
Debug.WriteLine("Centering view......");
2022-05-31 15:45:35 +00:00
2023-07-12 22:41:31 +00:00
var hwnd = WindowProcessManager.SimulatorProcess.Handle;
PInvoke.SetForegroundWindow(hwnd);
Thread.Sleep(200);
2021-12-14 05:40:07 +00:00
// First center view using Ctrl-Space
2022-08-01 23:21:42 +00:00
PInvoke.keybd_event(Convert.ToByte(VK_RCONTROL), 0, KEYEVENTF_KEYDOWN, 0);
2021-12-14 05:40:07 +00:00
PInvoke.keybd_event(Convert.ToByte(VK_SPACE), 0, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(200);
PInvoke.keybd_event(Convert.ToByte(VK_SPACE), 0, KEYEVENTF_KEYUP, 0);
2022-08-01 23:21:42 +00:00
PInvoke.keybd_event(Convert.ToByte(VK_RCONTROL), 0, KEYEVENTF_KEYUP, 0);
2021-12-14 05:40:07 +00:00
Thread.Sleep(200);
}
2022-07-23 19:23:32 +00:00
public static void SaveCustomView(string keybinding)
2021-12-14 05:40:07 +00:00
{
2023-07-12 22:41:31 +00:00
Debug.WriteLine("Saving custom view...");
2022-07-23 19:23:32 +00:00
2023-07-12 22:41:31 +00:00
var hwnd = WindowProcessManager.SimulatorProcess.Handle;
2022-06-30 23:53:08 +00:00
uint customViewKey = (uint)(Convert.ToInt32(keybinding) + KEY_0);
2022-04-18 03:38:33 +00:00
2021-12-14 05:40:07 +00:00
PInvoke.SetForegroundWindow(hwnd);
2023-07-12 22:41:31 +00:00
Thread.Sleep(200);
2021-12-14 05:40:07 +00:00
// Set view using Ctrl-Alt-0
PInvoke.keybd_event(Convert.ToByte(VK_LCONTROL), 0, KEYEVENTF_KEYDOWN, 0);
PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYDOWN, 0);
2022-04-18 03:38:33 +00:00
PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYDOWN, 0);
2021-12-14 05:40:07 +00:00
Thread.Sleep(200);
2022-04-18 03:38:33 +00:00
PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYUP, 0);
2021-12-14 05:40:07 +00:00
PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYUP, 0);
PInvoke.keybd_event(Convert.ToByte(VK_LCONTROL), 0, KEYEVENTF_KEYUP, 0);
2023-07-12 22:41:31 +00:00
Thread.Sleep(200);
2021-12-14 05:40:07 +00:00
}
2022-07-06 18:09:10 +00:00
public static void LoadCustomView(string keybinding)
2021-12-14 05:40:07 +00:00
{
2023-07-12 22:41:31 +00:00
Debug.WriteLine("Loading custom view...");
2021-12-14 05:40:07 +00:00
2022-07-23 19:23:32 +00:00
// First center view to make sure recalling custom camera works on the first press
2023-07-12 22:41:31 +00:00
CenterView();
2021-12-14 05:40:07 +00:00
2022-07-23 19:23:32 +00:00
uint customViewKey = (uint)(Convert.ToInt32(keybinding) + KEY_0);
2022-07-06 18:09:10 +00:00
2022-07-23 19:23:32 +00:00
// Then load view using Alt-0
PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYDOWN, 0);
PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(200);
PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYUP, 0);
PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYUP, 0);
2023-07-12 22:41:31 +00:00
Thread.Sleep(200);
2021-12-14 05:40:07 +00:00
}
2022-01-27 13:40:04 +00:00
2022-04-18 19:52:39 +00:00
public static void ToggleFullScreenPanel(IntPtr hwnd)
{
PInvoke.SetForegroundWindow(hwnd);
2023-07-26 20:22:44 +00:00
Thread.Sleep(200);
2022-04-18 19:52:39 +00:00
PInvoke.keybd_event(Convert.ToByte(VK_RMENU), 0, KEYEVENTF_KEYDOWN, 0);
PInvoke.keybd_event(Convert.ToByte(VK_ENT), 0, KEYEVENTF_KEYDOWN, 0);
Thread.Sleep(200);
PInvoke.keybd_event(Convert.ToByte(VK_ENT), 0, KEYEVENTF_KEYUP, 0);
PInvoke.keybd_event(Convert.ToByte(VK_RMENU), 0, KEYEVENTF_KEYUP, 0);
2023-07-12 22:41:31 +00:00
Thread.Sleep(200);
2022-04-18 19:52:39 +00:00
}
2022-08-08 06:07:24 +00:00
2022-10-16 13:11:01 +00:00
public static void RefocusGameWindow(PanelType panelType)
2022-08-08 06:07:24 +00:00
{
2023-07-12 22:41:31 +00:00
var rect = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
PInvoke.SetCursorPos(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
}
private static (int?, int?) GetGameWindowLeftClickPoint(int x, int y)
{
var applicationRectangle = WindowActionManager.GetWindowRectangle(WindowProcessManager.GetApplicationProcess().Handle);
var applicationRightEdge = applicationRectangle.X + applicationRectangle.Width;
var applicationBottomEdge = applicationRectangle.Y + applicationRectangle.Height;
var gameRectangle = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
int offset = 10;
if (!IsPointWithinRectangle(x, y, applicationRectangle))
return (x, y);
// Try lower right corner (higher than bottom edge)
if (IsPointWithinRectangle(applicationRightEdge + offset, applicationBottomEdge - offset, gameRectangle))
return (applicationRightEdge + offset, applicationBottomEdge - offset);
// Try upper right corner (lower than title bar)
if (IsPointWithinRectangle(applicationRightEdge + offset, applicationRectangle.Top + offset, gameRectangle))
return (applicationRightEdge + offset, applicationRectangle.Top + offset);
// Try lower left corner (higher than bottom edge)
if (IsPointWithinRectangle(applicationRectangle.X - offset, applicationBottomEdge - offset, gameRectangle))
return (applicationRectangle.X - offset, applicationBottomEdge - offset);
// Try upper left corner (lower than title bar)
if (IsPointWithinRectangle(applicationRectangle.X - offset, applicationRectangle.Top + offset, gameRectangle))
return (applicationRectangle.X - offset, applicationRectangle.Top + offset);
// Application window totally overlapping click point
return (null, null);
}
private static void MoveAppWindowFromLeftClickPoint(int x, int y)
{
var appHandle = WindowProcessManager.GetApplicationProcess().Handle;
var applicationRectangle = WindowActionManager.GetWindowRectangle(appHandle);
if (IsPointWithinRectangle(x, y, applicationRectangle))
{
var top = y - applicationRectangle.Height - 50;
WindowActionManager.MoveWindow(appHandle, applicationRectangle.X, top, applicationRectangle.Width, applicationRectangle.Height);
}
}
private static bool IsPointWithinRectangle(int x, int y, Rectangle rect)
{
var rightEdge = rect.X + rect.Width;
var bottomEdge = rect.Y + rect.Height;
return x >= rect.X && x <= rightEdge && y >= rect.Y && y <= bottomEdge;
}
#region Deprecated
public static void RightClickGameWindow()
{
if (WindowProcessManager.SimulatorProcess == null)
2022-08-08 06:07:24 +00:00
return;
2023-07-12 22:41:31 +00:00
var gameRectangle = WindowActionManager.GetWindowRectangle(WindowProcessManager.SimulatorProcess.Handle);
var gameCenterPointX = gameRectangle.X + gameRectangle.Width / 2;
var gameCenterPointY = gameRectangle.Y + gameRectangle.Height / 2;
var (x, y) = GetGameWindowLeftClickPoint(gameCenterPointX, gameCenterPointY);
PInvoke.SetForegroundWindow(WindowProcessManager.SimulatorProcess.Handle);
2022-08-08 06:07:24 +00:00
2023-07-12 22:41:31 +00:00
if (x == null || y == null)
{
int offset = 10;
var applicationRectangle = WindowActionManager.GetWindowRectangle(WindowProcessManager.GetApplicationProcess().Handle);
// Move app to outside game window
WindowActionManager.MoveWindow(WindowProcessManager.GetApplicationProcess().Handle, gameRectangle.X + gameRectangle.Width + offset, gameRectangle.Top + gameRectangle.Height + offset, applicationRectangle.Width, applicationRectangle.Height);
(x, y) = GetGameWindowLeftClickPoint(gameCenterPointX, gameCenterPointY);
RightClick((int)x, (int)y);
WindowActionManager.MoveWindow(WindowProcessManager.GetApplicationProcess().Handle, applicationRectangle);
}
2022-10-16 13:11:01 +00:00
else
2023-07-12 22:41:31 +00:00
{
RightClick((int)x, (int)y);
}
}
public static void RightClick(int x, int y)
{
PInvoke.SetCursorPos(x, y);
Thread.Sleep(300);
PInvoke.mouse_event(MOUSEEVENTF_RIGHTDOWN, x, y, 0, 0);
Thread.Sleep(200);
PInvoke.mouse_event(MOUSEEVENTF_RIGHTUP, x, y, 0, 0);
PInvoke.SetCursorPos(x + 5, y);
2022-08-08 06:07:24 +00:00
}
2023-07-12 22:41:31 +00:00
#endregion
2021-12-14 05:40:07 +00:00
}
}