From 6575eb313951e17ef0e7fa53ddf6065067398a9a Mon Sep 17 00:00:00 2001 From: "Valeriano A.R" Date: Sun, 10 Apr 2022 03:39:51 +0200 Subject: [PATCH] VirtualMouse: Allow mouse actions using global keybindings (WIP) --- VAR.Toolbox/Code/GlobalKeyboardHook.cs | 121 ++++++++++++++++++ VAR.Toolbox/Code/Mouse.cs | 4 +- VAR.Toolbox/Code/Windows/User32.cs | 58 +++++++++ .../UI/Tools/FrmVirtualMouse.Designer.cs | 81 ++++++++++++ VAR.Toolbox/UI/Tools/FrmVirtualMouse.cs | 59 +++++++++ VAR.Toolbox/UI/Tools/FrmVirtualMouse.resx | 120 +++++++++++++++++ VAR.Toolbox/VAR.Toolbox.csproj | 15 +++ 7 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 VAR.Toolbox/Code/GlobalKeyboardHook.cs create mode 100644 VAR.Toolbox/UI/Tools/FrmVirtualMouse.Designer.cs create mode 100644 VAR.Toolbox/UI/Tools/FrmVirtualMouse.cs create mode 100644 VAR.Toolbox/UI/Tools/FrmVirtualMouse.resx diff --git a/VAR.Toolbox/Code/GlobalKeyboardHook.cs b/VAR.Toolbox/Code/GlobalKeyboardHook.cs new file mode 100644 index 0000000..5cafd3c --- /dev/null +++ b/VAR.Toolbox/Code/GlobalKeyboardHook.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Windows.Forms; +using VAR.Toolbox.Code.Windows; + +namespace VAR.Toolbox.Code +{ + public class GlobalKeyboardHook + { + #region Declarations + + private bool _capturing = false; + private bool _captureAll = false; + + /// + /// The collections of keys to watch for + /// + private readonly List _hookedKeys = new List(); + + /// + /// Handle to the hook, need this to unhook and call the next hook + /// + private IntPtr _hHook = IntPtr.Zero; + + #endregion Declarations + + #region Private methods + + /// + /// The callback for the keyboard hook + /// + /// The hook code, if it isn't >= 0, the function shouldn't do anyting + /// The event type + /// The keyhook event information + /// + private int HookProc(int code, int wParam, ref User32.keyboardHookStruct lParam) { + try + { + if (code >= 0) + { + Keys key = (Keys)lParam.vkCode; + if (_hookedKeys.Contains(key) || _captureAll) + { + KeyEventArgs kea = new KeyEventArgs(key); + if ((wParam == User32.WM_KEYDOWN || wParam == User32.WM_SYSKEYDOWN) && (KeyDown != null)) + { + KeyDown(this, kea); + } + else if ((wParam == User32.WM_KEYUP || wParam == User32.WM_SYSKEYUP) && (KeyUp != null)) + { + KeyUp(this, kea); + } + + if (kea.Handled) + return 1; + } + } + } + catch (Exception) + { + // ignored + } + + return User32.CallNextHookEx(_hHook, code, wParam, ref lParam); + } + + #endregion Private methods + + #region Public events + + /// + /// Occurs when one of the hooked keys is pressed + /// + public event KeyEventHandler KeyDown; + + /// + /// Occurs when one of the hooked keys is released + /// + public event KeyEventHandler KeyUp; + + #endregion Public events + + #region Public methods + + public void Start(bool all = false) + { + if (_capturing) { return; } + + _captureAll = all; + + //IntPtr hInstance = User32.LoadLibrary("User32"); + //_hHook = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, HookProc, hInstance, 0); + IntPtr iModule = System.Runtime.InteropServices.Marshal.GetHINSTANCE( + System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]); + _hHook = User32.SetWindowsHookEx(User32.WH_KEYBOARD_LL, HookProc, iModule, 0); + + _capturing = true; + } + + public void Stop() + { + if (_capturing == false) { return; } + + User32.UnhookWindowsHookEx(_hHook); + _capturing = false; + } + + public bool IsCapturing() + { + return _capturing; + } + + public void AddHook(Keys key) + { + _hookedKeys.Add(key); + } + + #endregion Public methods + } +} \ No newline at end of file diff --git a/VAR.Toolbox/Code/Mouse.cs b/VAR.Toolbox/Code/Mouse.cs index 7f68bd7..4f1c592 100644 --- a/VAR.Toolbox/Code/Mouse.cs +++ b/VAR.Toolbox/Code/Mouse.cs @@ -15,7 +15,7 @@ namespace VAR.Toolbox.Code input.Data.Mouse.X = dx; input.Data.Mouse.Y = dy; input.Data.Mouse.Flags = User32.MOUSEEVENTF_MOVE; - User32.INPUT[] inputs = new User32.INPUT[] { input }; + User32.INPUT[] inputs = new[] { input }; if (User32.SendInput(1, inputs, Marshal.SizeOf(typeof(User32.INPUT))) == 0) throw new Exception(); } @@ -50,7 +50,7 @@ namespace VAR.Toolbox.Code input.Data.Mouse.Flags = down ? User32.MOUSEEVENTF_RIGHTDOWN : User32.MOUSEEVENTF_RIGHTUP; } - User32.INPUT[] inputs = new User32.INPUT[] { input }; + User32.INPUT[] inputs = new[] { input }; if (User32.SendInput(1, inputs, Marshal.SizeOf(typeof(User32.INPUT))) == 0) throw new Exception(); } diff --git a/VAR.Toolbox/Code/Windows/User32.cs b/VAR.Toolbox/Code/Windows/User32.cs index 5a779cb..2e06aeb 100644 --- a/VAR.Toolbox/Code/Windows/User32.cs +++ b/VAR.Toolbox/Code/Windows/User32.cs @@ -203,5 +203,63 @@ namespace VAR.Toolbox.Code.Windows public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); + + /// + /// defines the callback type for the hook + /// + public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam); + + public struct keyboardHookStruct { + public int vkCode; + public int scanCode; + public int flags; + public int time; + public int dwExtraInfo; + } + + public const int WH_KEYBOARD_LL = 13; + public const int WM_KEYDOWN = 0x100; + public const int WM_KEYUP = 0x101; + public const int WM_SYSKEYDOWN = 0x104; + public const int WM_SYSKEYUP = 0x105; + + /// + /// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null + /// + /// The id of the event you want to hook + /// The callback. + /// The handle you want to attach the event to, can be null + /// The thread you want to attach the event to, can be null + /// a handle to the desired hook + [DllImport("user32.dll")] + public static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId); + + /// + /// Unhooks the windows hook. + /// + /// The hook handle that was returned from SetWindowsHookEx + /// True if successful, false otherwise + [DllImport("user32.dll")] + public static extern bool UnhookWindowsHookEx(IntPtr hInstance); + + /// + /// Calls the next hook. + /// + /// The hook id + /// The hook code + /// The wparam. + /// The lparam. + /// + [DllImport("user32.dll")] + public static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam); + + /// + /// Loads the library. + /// + /// Name of the library + /// A handle to the library + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string lpFileName); + } } \ No newline at end of file diff --git a/VAR.Toolbox/UI/Tools/FrmVirtualMouse.Designer.cs b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.Designer.cs new file mode 100644 index 0000000..32a426c --- /dev/null +++ b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.Designer.cs @@ -0,0 +1,81 @@ +using System.ComponentModel; + +namespace VAR.Toolbox.UI.Tools +{ + partial class FrmVirtualMouse + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnStartStop = new VAR.Toolbox.Controls.CButton(); + this.lsbInputs = new VAR.Toolbox.Controls.ListBoxMonospace(); + this.SuspendLayout(); + // + // btnStartStop + // + this.btnStartStop.Location = new System.Drawing.Point(335, 331); + this.btnStartStop.Name = "btnStartStop"; + this.btnStartStop.Size = new System.Drawing.Size(92, 58); + this.btnStartStop.TabIndex = 0; + this.btnStartStop.Text = "Start"; + this.btnStartStop.UseVisualStyleBackColor = true; + this.btnStartStop.Click += new System.EventHandler(this.btnStartStop_Click); + // + // lsbInputs + // + this.lsbInputs.BackColor = System.Drawing.Color.Black; + this.lsbInputs.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.lsbInputs.Font = new System.Drawing.Font("Consolas", 9F); + this.lsbInputs.ForeColor = System.Drawing.Color.Gray; + this.lsbInputs.FormattingEnabled = true; + this.lsbInputs.ItemHeight = 14; + this.lsbInputs.Location = new System.Drawing.Point(12, 23); + this.lsbInputs.Name = "lsbInputs"; + this.lsbInputs.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; + this.lsbInputs.Size = new System.Drawing.Size(224, 282); + this.lsbInputs.TabIndex = 1; + // + // FrmVirtualMouse + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.lsbInputs); + this.Controls.Add(this.btnStartStop); + this.Location = new System.Drawing.Point(0, 0); + this.Name = "FrmVirtualMouse"; + this.Text = "FrmVirtualMouse"; + this.ResumeLayout(false); + } + + private VAR.Toolbox.Controls.ListBoxMonospace lsbInputs; + + private VAR.Toolbox.Controls.CButton btnStartStop; + + #endregion + } +} \ No newline at end of file diff --git a/VAR.Toolbox/UI/Tools/FrmVirtualMouse.cs b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.cs new file mode 100644 index 0000000..6111fcb --- /dev/null +++ b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.cs @@ -0,0 +1,59 @@ +using System; +using System.Windows.Forms; +using VAR.Toolbox.Code; +using VAR.Toolbox.Controls; + +namespace VAR.Toolbox.UI.Tools +{ + public partial class FrmVirtualMouse : Frame, IToolForm + { + public string ToolName => "VirtualMouse"; + + public bool HasIcon => false; + + private readonly GlobalKeyboardHook _globalKeyboard = new GlobalKeyboardHook(); + + public FrmVirtualMouse() + { + InitializeComponent(); + PostInitializeComponent(); + } + + private void PostInitializeComponent() + { + _globalKeyboard.KeyDown += GlobalKeyboard_OnKeyDown; + } + + private void GlobalKeyboard_OnKeyDown(object sender, KeyEventArgs keyEvent) + { + string key = keyEvent.KeyCode.ToString(); + lsbInputs.Items.Add(key); + + if (key == "F1") + { + Mouse.SetButton(Mouse.MouseButtons.Left, true); + } + if (key == "F2") + { + Mouse.Move(0, -10000); + } + if (key == "F3") + { + Mouse.SetButton(Mouse.MouseButtons.Left, false); + } + } + + private void btnStartStop_Click(object sender, EventArgs e) + { + if (_globalKeyboard.IsCapturing()) + { + _globalKeyboard.Stop(); + btnStartStop.Text = "Start"; + return; + } + + _globalKeyboard.Start(true); + btnStartStop.Text = "Stop"; + } + } +} \ No newline at end of file diff --git a/VAR.Toolbox/UI/Tools/FrmVirtualMouse.resx b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/VAR.Toolbox/UI/Tools/FrmVirtualMouse.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/VAR.Toolbox/VAR.Toolbox.csproj b/VAR.Toolbox/VAR.Toolbox.csproj index 552307f..1d89e68 100644 --- a/VAR.Toolbox/VAR.Toolbox.csproj +++ b/VAR.Toolbox/VAR.Toolbox.csproj @@ -48,6 +48,9 @@ + + bin\Debug\VAR.Toolbox.exe + @@ -83,6 +86,7 @@ + @@ -245,6 +249,12 @@ + + Form + + + FrmVirtualMouse.cs + Form @@ -313,6 +323,11 @@ + + + FrmVirtualMouse.cs + +