diff --git a/Blish HUD/Common/Gw2/GuildWarsControls.cs b/Blish HUD/Common/Gw2/GuildWarsControls.cs new file mode 100644 index 000000000..357e796d4 --- /dev/null +++ b/Blish HUD/Common/Gw2/GuildWarsControls.cs @@ -0,0 +1,22 @@ +namespace Blish_HUD.Common.Gw2 { + public enum GuildWarsControls { + None, + SwapWeapons, + WeaponSkill1, + WeaponSkill2, + WeaponSkill3, + WeaponSkill4, + WeaponSkill5, + HealingSkill, + UtilitySkill1, + UtilitySkill2, + UtilitySkill3, + EliteSkill, + ProfessionSkill1, + ProfessionSkill2, + ProfessionSkill3, + ProfessionSkill4, + ProfessionSkill5, + SpecialAction + } +} diff --git a/Blish HUD/Controls/Extern/HardwareInput.cs b/Blish HUD/Controls/Extern/HardwareInput.cs index 8e1cde8a0..ee7867a78 100644 --- a/Blish HUD/Controls/Extern/HardwareInput.cs +++ b/Blish HUD/Controls/Extern/HardwareInput.cs @@ -1,7 +1,9 @@ +using System; using System.Runtime.InteropServices; namespace Blish_HUD.Controls.Extern { + [Obsolete("HardwareInput is obsolete.", true)] [StructLayout(LayoutKind.Sequential)] internal struct HardwareInput { diff --git a/Blish HUD/Controls/Extern/Input.cs b/Blish HUD/Controls/Extern/Input.cs index 725b13d9f..6e43bf459 100644 --- a/Blish HUD/Controls/Extern/Input.cs +++ b/Blish HUD/Controls/Extern/Input.cs @@ -1,7 +1,9 @@ +using System; using System.Runtime.InteropServices; namespace Blish_HUD.Controls.Extern { + [Obsolete("Input is obsolete.", true)] [StructLayout(LayoutKind.Sequential)] internal struct Input { diff --git a/Blish HUD/Controls/Extern/InputType.cs b/Blish HUD/Controls/Extern/InputType.cs index 1a1f62bb9..6387a147c 100644 --- a/Blish HUD/Controls/Extern/InputType.cs +++ b/Blish HUD/Controls/Extern/InputType.cs @@ -1,5 +1,8 @@ +using System; + namespace Blish_HUD.Controls.Extern { + [Obsolete("InputType is obsolete.", true)] internal enum InputType : uint { MOUSE = 0, diff --git a/Blish HUD/Controls/Extern/InputUnion.cs b/Blish HUD/Controls/Extern/InputUnion.cs index 98f0e8e6d..3bdaeec7d 100644 --- a/Blish HUD/Controls/Extern/InputUnion.cs +++ b/Blish HUD/Controls/Extern/InputUnion.cs @@ -1,7 +1,9 @@ +using System; using System.Runtime.InteropServices; namespace Blish_HUD.Controls.Extern { + [Obsolete("InputUnion is obsolete.", true)] [StructLayout(LayoutKind.Explicit)] internal struct InputUnion { diff --git a/Blish HUD/Controls/Extern/KeyEventF.cs b/Blish HUD/Controls/Extern/KeyEventF.cs index a67fee9d4..4219b8c2f 100644 --- a/Blish HUD/Controls/Extern/KeyEventF.cs +++ b/Blish HUD/Controls/Extern/KeyEventF.cs @@ -2,6 +2,7 @@ namespace Blish_HUD.Controls.Extern { + [Obsolete("KeyEventF is obsolete.", true)] [Flags] internal enum KeyEventF : uint { diff --git a/Blish HUD/Controls/Extern/KeybdInput.cs b/Blish HUD/Controls/Extern/KeybdInput.cs index 210869522..4521f1965 100644 --- a/Blish HUD/Controls/Extern/KeybdInput.cs +++ b/Blish HUD/Controls/Extern/KeybdInput.cs @@ -3,6 +3,7 @@ namespace Blish_HUD.Controls.Extern { + [Obsolete("KeybdInput is obsolete.", true)] [StructLayout(LayoutKind.Sequential)] internal struct KeybdInput { diff --git a/Blish HUD/Controls/Extern/MouseEventF.cs b/Blish HUD/Controls/Extern/MouseEventF.cs index 12fa652bd..e59262ff2 100644 --- a/Blish HUD/Controls/Extern/MouseEventF.cs +++ b/Blish HUD/Controls/Extern/MouseEventF.cs @@ -2,6 +2,7 @@ namespace Blish_HUD.Controls.Extern { + [Obsolete("MouseEventF is obsolete.", true)] [Flags] internal enum MouseEventF : uint { diff --git a/Blish HUD/Controls/Extern/MouseInput.cs b/Blish HUD/Controls/Extern/MouseInput.cs index f78710cf7..643b730f1 100644 --- a/Blish HUD/Controls/Extern/MouseInput.cs +++ b/Blish HUD/Controls/Extern/MouseInput.cs @@ -3,6 +3,7 @@ namespace Blish_HUD.Controls.Extern { + [Obsolete("MouseInput is obsolete.", true)] [StructLayout(LayoutKind.Sequential)] internal struct MouseInput { diff --git a/Blish HUD/Controls/Extern/PInvoke.cs b/Blish HUD/Controls/Extern/PInvoke.cs index fcec25d84..9fae08d7f 100644 --- a/Blish HUD/Controls/Extern/PInvoke.cs +++ b/Blish HUD/Controls/Extern/PInvoke.cs @@ -4,6 +4,7 @@ namespace Blish_HUD.Controls.Extern { + [Obsolete("POINT is obsolete.", true)] /// /// Struct representing a point. /// @@ -16,7 +17,7 @@ public static implicit operator Point(POINT point) { return new Point(point.X, point.Y); } } - + [Obsolete("PInvoke is obsolete.", true)] internal static class PInvoke { [DllImport("user32.dll")] internal static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] Input[] pInputs, int cbSize); diff --git a/Blish HUD/Controls/Extern/ScanCodeShort.cs b/Blish HUD/Controls/Extern/ScanCodeShort.cs index 23650a3e6..882524bd2 100644 --- a/Blish HUD/Controls/Extern/ScanCodeShort.cs +++ b/Blish HUD/Controls/Extern/ScanCodeShort.cs @@ -1,5 +1,8 @@ +using System; + namespace Blish_HUD.Controls.Extern { + [Obsolete("ScanCodeShort is obsolete.", true)] internal enum ScanCodeShort : short { LBUTTON = 0, diff --git a/Blish HUD/Controls/Extern/VirtualKeyShort.cs b/Blish HUD/Controls/Extern/VirtualKeyShort.cs index 9a8ac9652..5e98e24ec 100644 --- a/Blish HUD/Controls/Extern/VirtualKeyShort.cs +++ b/Blish HUD/Controls/Extern/VirtualKeyShort.cs @@ -1,5 +1,8 @@ +using System; + namespace Blish_HUD.Controls.Extern { + [Obsolete("VirtualKeyShort is obsolete. Please use Keys instead.", true)] public enum VirtualKeyShort : short { /// diff --git a/Blish HUD/Controls/Intern/GuildWarsControls.cs b/Blish HUD/Controls/Intern/GuildWarsControls.cs index f87b3fc38..f44a5d308 100644 --- a/Blish HUD/Controls/Intern/GuildWarsControls.cs +++ b/Blish HUD/Controls/Intern/GuildWarsControls.cs @@ -1,5 +1,8 @@ -namespace Blish_HUD.Controls.Intern +using System; + +namespace Blish_HUD.Controls.Intern { + [Obsolete("Controls.Intern.GuildWarsControls is obsolete. Please use Common.Gw2.GuildWarsControls instead.", true)] public enum GuildWarsControls { None, diff --git a/Blish HUD/Controls/Intern/Keyboard.cs b/Blish HUD/Controls/Intern/Keyboard.cs index 512b422d4..203ba66d4 100644 --- a/Blish HUD/Controls/Intern/Keyboard.cs +++ b/Blish HUD/Controls/Intern/Keyboard.cs @@ -3,6 +3,7 @@ using Blish_HUD.Controls.Extern; namespace Blish_HUD.Controls.Intern { + [Obsolete("Keyboard is obsolete. Please use KeyboardUtil instead.", true)] public static class Keyboard { private const uint WM_KEYDOWN = 0x0100; @@ -179,6 +180,7 @@ public static void Stroke(VirtualKeyShort key, bool sendToSystem = false) Release(key, sendToSystem); } } + [Obsolete("Controls.Intern.ExtraKeyInfo is obsolete. Please use ExtraKeyInfo instead.", true)] class ExtraKeyInfo { public ushort repeatCount; diff --git a/Blish HUD/Controls/Intern/Mouse.cs b/Blish HUD/Controls/Intern/Mouse.cs index 951bab83a..a7d8c881a 100644 --- a/Blish HUD/Controls/Intern/Mouse.cs +++ b/Blish HUD/Controls/Intern/Mouse.cs @@ -4,6 +4,7 @@ using Blish_HUD.Controls.Extern; namespace Blish_HUD.Controls.Intern { + [Obsolete("Controls.Intern.MouseButton is obsolete. Please use MouseButton instead.", true)] public enum MouseButton { LEFT, @@ -11,6 +12,7 @@ public enum MouseButton MIDDLE, XBUTTON } + [Obsolete("Mouse is obsolete. Please use MouseUtil instead.", true)] public static class Mouse { private const uint WM_MOUSEWHEEL = 0x020A; diff --git a/Blish HUD/GameServices/GameIntegrationService.cs b/Blish HUD/GameServices/GameIntegrationService.cs index 4a0c1c790..24764657c 100644 --- a/Blish HUD/GameServices/GameIntegrationService.cs +++ b/Blish HUD/GameServices/GameIntegrationService.cs @@ -2,8 +2,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using Blish_HUD.Controls.Extern; -using Blish_HUD.Controls.Intern; using Blish_HUD.GameIntegration; using Blish_HUD.Settings; using Microsoft.Xna.Framework; @@ -164,11 +162,11 @@ await ClipboardUtil.WindowsClipboardService.SetTextAsync(message) else Task.Run(() => { Focus(); - Keyboard.Press(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.KEY_V, true); + KeyboardUtil.Press(0xA2, true); + KeyboardUtil.Stroke(0x56, true); Thread.Sleep(50); - Keyboard.Release(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.RETURN); + KeyboardUtil.Release(0xA2, true); + KeyboardUtil.Stroke(0x0D); }).ContinueWith(result => { if (result.IsFaulted) { Logger.Warn(result.Exception, "Failed to send message {message}", message); @@ -191,10 +189,10 @@ await ClipboardUtil.WindowsClipboardService.SetTextAsync(text) else Task.Run(() => { Focus(); - Keyboard.Press(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.KEY_V, true); + KeyboardUtil.Press(0xA2, true); + KeyboardUtil.Stroke(0x56, true); Thread.Sleep(50); - Keyboard.Release(VirtualKeyShort.LCONTROL, true); + KeyboardUtil.Release(0xA2, true); }).ContinueWith(result => { if (result.IsFaulted) { Logger.Warn(result.Exception, "Failed to paste {text}", text); @@ -210,11 +208,11 @@ public async Task GetInputText() { byte[] prevClipboardContent = await ClipboardUtil.WindowsClipboardService.GetAsUnicodeBytesAsync(); await Task.Run(() => { Focus(); - Keyboard.Press(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.KEY_A, true); - Keyboard.Stroke(VirtualKeyShort.KEY_C, true); + KeyboardUtil.Press(0xA2, true); + KeyboardUtil.Stroke(0x41, true); + KeyboardUtil.Stroke(0x43, true); Thread.Sleep(50); - Keyboard.Release(VirtualKeyShort.LCONTROL, true); + KeyboardUtil.Release(0xA2, true); Unfocus(); }); string inputText = await ClipboardUtil.WindowsClipboardService.GetTextAsync() @@ -231,22 +229,22 @@ public void Clear() { if (IsBusy()) return; Task.Run(() => { Focus(); - Keyboard.Press(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.KEY_A, true); + KeyboardUtil.Press(0xA2, true); + KeyboardUtil.Stroke(0x41, true); Thread.Sleep(50); - Keyboard.Release(VirtualKeyShort.LCONTROL, true); - Keyboard.Stroke(VirtualKeyShort.BACK); + KeyboardUtil.Release(0xA2, true); + KeyboardUtil.Stroke(0x08); Unfocus(); }); } private void Focus() { Unfocus(); - Keyboard.Stroke(VirtualKeyShort.RETURN); + KeyboardUtil.Stroke(0x0D); } private void Unfocus() { - Mouse.Click(MouseButton.LEFT, Graphics.GraphicsDevice.Viewport.Width / 2, 0); + MouseUtil.Click(0, Graphics.GraphicsDevice.Viewport.Width / 2, 0); } private bool IsTextValid(string text) { diff --git a/Blish HUD/GameServices/Input/WinApi/Input.cs b/Blish HUD/GameServices/Input/WinApi/Input.cs new file mode 100644 index 000000000..ed0432578 --- /dev/null +++ b/Blish HUD/GameServices/Input/WinApi/Input.cs @@ -0,0 +1,32 @@ +using System.Runtime.InteropServices; +namespace Blish_HUD.Input.WinApi { + [StructLayout(LayoutKind.Sequential)] + internal struct Input { + internal InputType type; + internal InputUnion U; + internal static int Size => Marshal.SizeOf(typeof(Input)); + } + + internal enum InputType : uint { + MOUSE = 0, + KEYBOARD = 1, + HARDWARE = 2 + } + + [StructLayout(LayoutKind.Explicit)] + internal struct InputUnion { + [FieldOffset(0)] + internal MouseUtil.MouseInput mi; + [FieldOffset(0)] + internal KeyboardUtil.KeybdInput ki; + [FieldOffset(0)] + internal HardwareInput hi; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HardwareInput { + internal int uMsg; + internal short wParamL; + internal short wParamH; + } +} \ No newline at end of file diff --git a/Blish HUD/_Utils/KeyboardUtil.cs b/Blish HUD/_Utils/KeyboardUtil.cs new file mode 100644 index 000000000..cd6e8c119 --- /dev/null +++ b/Blish HUD/_Utils/KeyboardUtil.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using InputType = Blish_HUD.Input.WinApi.InputType; +using InputUnion = Blish_HUD.Input.WinApi.InputUnion; +namespace Blish_HUD { + public static class KeyboardUtil { + private const uint WM_KEYDOWN = 0x0100; + private const uint WM_KEYUP = 0x0101; + private const uint WM_CHAR = 0x0102; + private const uint MAPVK_VK_TO_VSC = 0x00; + private const uint MAPVK_VSC_TO_VK = 0x01; + private const uint MAPVK_VK_TO_CHAR = 0x02; + private const uint MAPVK_VSC_TO_VK_EX = 0x03; + private const uint MAPVK_VK_TO_VSC_EX = 0x04; + + [Flags] + internal enum KeyEventF : uint { + EXTENDEDKEY = 0x0001, + KEYUP = 0x0002, + SCANCODE = 0x0008, + UNICODE = 0x0004 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct KeybdInput { + internal short wVk; + internal short wScan; + internal KeyEventF dwFlags; + internal int time; + internal UIntPtr dwExtraInfo; + } + + private static List ExtendedKeys = new List { + 0x2D, 0x24, 0x22, + 0x2E, 0x23, 0x21, + 0xA5, 0xA1, 0xA3, + 0x26, 0x28, 0x25, + 0x27, 0x90, 0x2A + }; + + [DllImport("user32.dll")] + private static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("user32.dll")] + private static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] Input.WinApi.Input[] pInputs, int cbSize); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern bool PostMessage(IntPtr hWnd, uint msg, uint wParam, int lParam); // sends a message asynchronously. + /// + /// Presses a key. + /// + /// Virtual key code of the key to press. + /// Set if key message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Press(int keyCode, bool sendToSystem = false) { + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + Input.WinApi.Input[] nInputs; + if (ExtendedKeys.Contains(keyCode)) { + nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = 224, + wVk = 0, + dwFlags = 0 + } + } + }, + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = (short)MapVirtualKey((uint)keyCode, MAPVK_VK_TO_VSC), + wVk = (short)keyCode, + dwFlags = KeyEventF.EXTENDEDKEY + } + } + } + }; + } else { + nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = (short)MapVirtualKey((uint)keyCode, MAPVK_VK_TO_VSC), + wVk = (short)keyCode + } + } + } + }; + } + SendInput((uint)nInputs.Length, nInputs, Input.WinApi.Input.Size); + } else { + uint vkCode = (uint)keyCode; + ExtraKeyInfo lParam = new ExtraKeyInfo { + scanCode = (char)MapVirtualKey(vkCode, MAPVK_VK_TO_VSC) + }; + + if (ExtendedKeys.Contains(keyCode)) + lParam.extendedKey = 1; + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_KEYDOWN, vkCode, lParam.GetInt()); + } + } + + /// + /// Releases a key. + /// + /// Virtual key code of the key to release. + /// Set if key message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Release(int keyCode, bool sendToSystem = false) { + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + Input.WinApi.Input[] nInputs; + if (ExtendedKeys.Contains(keyCode)) { + nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = 224, + wVk = 0, + dwFlags = 0 + } + } + }, + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = (short)MapVirtualKey((uint)keyCode, MAPVK_VK_TO_VSC), + wVk = (short)keyCode, + dwFlags = KeyEventF.EXTENDEDKEY | KeyEventF.KEYUP + } + } + } + }; + } else { + nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.KEYBOARD, + U = new InputUnion + { + ki = new KeybdInput + { + wScan = (short)MapVirtualKey((uint)keyCode, MAPVK_VK_TO_VSC), + wVk = (short)keyCode, + dwFlags = KeyEventF.KEYUP + } + } + } + }; + } + SendInput((uint)nInputs.Length, nInputs, Input.WinApi.Input.Size); + } else { + uint vkCode = (uint)keyCode; + ExtraKeyInfo lParam = new ExtraKeyInfo { + scanCode = (char)MapVirtualKey(vkCode, MAPVK_VK_TO_VSC), + repeatCount = 1, + prevKeyState = 1, + transitionState = 1 + }; + + if (ExtendedKeys.Contains(keyCode)) + lParam.extendedKey = 1; + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_KEYUP, vkCode, lParam.GetInt()); + } + } + + /// + /// Performs a keystroke inwhich a key is pressed and immediately released once. + /// + /// Virtual key code of the key to stroke. + /// Set if key message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Stroke(int keyCode, bool sendToSystem = false) { + Press(keyCode, sendToSystem); + Release(keyCode, sendToSystem); + } + + private class ExtraKeyInfo { + public ushort repeatCount; + public char scanCode; + public ushort extendedKey, prevKeyState, transitionState; + + public int GetInt() { + return repeatCount | (scanCode << 16) | (extendedKey << 24) | + (prevKeyState << 30) | (transitionState << 31); + } + } + } +} \ No newline at end of file diff --git a/Blish HUD/_Utils/MouseUtil.cs b/Blish HUD/_Utils/MouseUtil.cs new file mode 100644 index 000000000..14e69832a --- /dev/null +++ b/Blish HUD/_Utils/MouseUtil.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using Blish_HUD.Input.WinApi; +namespace Blish_HUD { + public static class MouseUtil { + public enum MouseButton { + LEFT, + RIGHT, + MIDDLE, + XBUTTON + } + + [Flags] + internal enum MouseEventF : uint { + ABSOLUTE = 0x8000, + HWHEEL = 0x01000, + MOVE = 0x0001, + MOVE_NOCOALESCE = 0x2000, + LEFTDOWN = 0x0002, + LEFTUP = 0x0004, + RIGHTDOWN = 0x0008, + RIGHTUP = 0x0010, + MIDDLEDOWN = 0x0020, + MIDDLEUP = 0x0040, + VIRTUALDESK = 0x4000, + WHEEL = 0x0800, + XDOWN = 0x0080, + XUP = 0x0100 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MouseInput { + internal int dx; + internal int dy; + internal int mouseData; + internal MouseEventF dwFlags; + internal uint time; + internal UIntPtr dwExtraInfo; + } + + private const uint WM_MOUSEWHEEL = 0x020A; + private const uint WM_MOUSEHWHEEL = 0x020E; + private const int WHEEL_DELTA = 120; + private const uint WM_MOUSEMOVE = 0x0200; + + private static Dictionary ButtonPress = new Dictionary() + { + { MouseButton.LEFT, MouseEventF.LEFTDOWN }, + { MouseButton.RIGHT, MouseEventF.RIGHTDOWN }, + { MouseButton.MIDDLE, MouseEventF.MIDDLEDOWN }, + { MouseButton.XBUTTON, MouseEventF.XDOWN } + }; + + private static Dictionary ButtonRelease = new Dictionary() + { + { MouseButton.LEFT, MouseEventF.LEFTUP }, + { MouseButton.RIGHT, MouseEventF.RIGHTUP }, + { MouseButton.MIDDLE, MouseEventF.MIDDLEUP }, + { MouseButton.XBUTTON, MouseEventF.XUP } + }; + + private static Dictionary VirtualButtonShort = new Dictionary() + { + { MouseButton.LEFT, 0x01 }, + { MouseButton.RIGHT, 0x02 }, + { MouseButton.MIDDLE, 0x04 }, + { MouseButton.XBUTTON, 0x05 } + }; + + private static Dictionary WM_BUTTONDOWN = new Dictionary() + { + { MouseButton.LEFT, 0x0201 }, + { MouseButton.RIGHT, 0x0204 }, + { MouseButton.MIDDLE, 0x0207 }, + { MouseButton.XBUTTON, 0x020B } + }; + + private static Dictionary WM_BUTTONUP = new Dictionary() + { + { MouseButton.LEFT, 0x0202 }, + { MouseButton.RIGHT, 0x0205 }, + { MouseButton.MIDDLE, 0x0208 }, + { MouseButton.XBUTTON, 0x020C } + }; + + private static Dictionary WM_BUTTONDBLCLK = new Dictionary() + { + { MouseButton.LEFT, 0x0203 }, + { MouseButton.RIGHT, 0x0206 }, + { MouseButton.MIDDLE, 0x0209 }, + { MouseButton.XBUTTON, 0x020D } + }; + + /// + /// Struct representing a point. + /// + [StructLayout(LayoutKind.Sequential)] + private struct POINT { + public int X; + public int Y; + + public static implicit operator Point(POINT point) { + return new Point(point.X, point.Y); + } + } + + [DllImport("user32.Dll", SetLastError = true)] + private static extern long SetCursorPos(int x, int y); + + [DllImport("user32.dll")] + private static extern bool GetCursorPos(out POINT lpPoint); + + [DllImport("user32.dll")] + private static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] Input.WinApi.Input[] pInputs, int cbSize); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern bool PostMessage(IntPtr hWnd, uint msg, uint wParam, int lParam); // sends a message asynchronously. + + /// + /// Presses a mouse button. + /// + /// The mouse button to press. + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Press(MouseButton button, int xPos = -1, int yPos = -1, bool sendToSystem = false) { + if (xPos == -1 || yPos == -1) { + var pos = GetPosition(); + xPos = pos.X; + yPos = pos.Y; + } + + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + var nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.MOUSE, + U = new InputUnion + { + mi = new MouseInput + { + dx = xPos, + dy = yPos, + mouseData = 0, + dwFlags = ButtonPress[button], + time = 0 + } + } + } + }; + SendInput((uint)nInputs.Length, nInputs, Input.WinApi.Input.Size); + } else { + uint wParam = (uint)VirtualButtonShort[button]; + int lParam = xPos | (yPos << 16); + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_BUTTONDOWN[button], wParam, lParam); + } + } + + /// + /// Releases a mouse button. + /// + /// The mouse button to release. + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Release(MouseButton button, int xPos = -1, int yPos = -1, bool sendToSystem = false) { + if (xPos == -1 || yPos == -1) { + var pos = GetPosition(); + xPos = pos.X; + yPos = pos.Y; + } + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + var nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.MOUSE, + U = new InputUnion + { + mi = new MouseInput + { + dx = xPos, + dy = yPos, + mouseData = 0, + dwFlags = ButtonRelease[button], + time = 0 + } + } + } + }; + SendInput((uint)nInputs.Length, nInputs, Input.WinApi.Input.Size); + } else { + uint wParam = (uint)VirtualButtonShort[button]; + int lParam = xPos | (yPos << 16); + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_BUTTONUP[button], wParam, lParam); + } + } + + /// + /// Rotates the mouse wheel. + /// + /// Distance of movement by multiples or divisions of 120 (WHEEL_DELTA). A positive value indicates the wheel to rotate forward, away from the user; a negative value indicates the wheel to rotate backward, toward the user. + /// Indicates the wheel to rotate horizontally. + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void RotateWheel(int wheelDistance, bool horizontalWheel = false, int xPos = -1, int yPos = -1, bool sendToSystem = false) { + wheelDistance = wheelDistance % WHEEL_DELTA; + if (wheelDistance == 0) return; + + if (xPos == -1 || yPos == -1) { + var pos = GetPosition(); + xPos = pos.X; + yPos = pos.Y; + } + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + var nInputs = new[] + { + new Input.WinApi.Input + { + type = InputType.MOUSE, + U = new InputUnion + { + mi = new MouseInput + { + dx = xPos, + dy = yPos, + mouseData = wheelDistance, + dwFlags = horizontalWheel ? MouseEventF.HWHEEL : MouseEventF.WHEEL, + time = 0 + } + } + } + }; + SendInput((uint)nInputs.Length, nInputs, Input.WinApi.Input.Size); + } else { + uint wParam = (uint)(0 | wheelDistance << 16); + int lParam = xPos | (yPos << 16); + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, horizontalWheel ? WM_MOUSEHWHEEL : WM_MOUSEWHEEL, wParam, lParam); + } + } + + /// + /// Sets the cursors absolute screen position. + /// + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void SetPosition(int xPos, int yPos, bool sendToSystem = false) { + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + SetCursorPos(xPos, yPos); + } else { + int lParam = xPos | (yPos << 16); + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_MOUSEMOVE, 0, lParam); + } + } + + /// + /// Gets the cursors absolute screen position. + /// + public static Point GetPosition() { + POINT lpPoint; + GetCursorPos(out lpPoint); + return lpPoint; + } + + /// + /// Presses and immediately releases a mouse button ONCE. + /// + /// The mouse button to click. + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void Click(MouseButton button, int xPos = -1, int yPos = -1, bool sendToSystem = false) { + Press(button, xPos, yPos, sendToSystem); + Release(button, xPos, yPos, sendToSystem); + } + + /// + /// Performs a double click of a mouse button. + /// + /// The mouse button to click. + /// The X coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current X coordinate. + /// The Y coodinate where this action takes place. Relative to the game client window if sendToSystem is not set. Default: current Y coordinate. + /// Set if button message (or a combination of such) cannot be correctly interpreted by the game client. + public static void DoubleClick(MouseButton button, int xPos = -1, int yPos = -1, bool sendToSystem = false) { + if (!GameService.GameIntegration.Gw2Instance.Gw2IsRunning || sendToSystem) { + for (int i = 0; i <= 1; i++) { + Press(button, xPos, yPos, sendToSystem); + Release(button, xPos, yPos, sendToSystem); + } + } else { + if (xPos == -1 || yPos == -1) { + var pos = GetPosition(); + xPos = pos.X; + yPos = pos.Y; + } + uint wParam = (uint)VirtualButtonShort[button]; + int lParam = xPos | (yPos << 16); + PostMessage(GameService.GameIntegration.Gw2Instance.Gw2WindowHandle, WM_BUTTONDBLCLK[button], wParam, lParam); + } + } + } +} \ No newline at end of file