#region Copyright /// /// Copyright (c) 2011 Ramunas Geciauskas, http://geciauskas.com /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights /// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell /// copies of the Software, and to permit persons to whom the Software is /// furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, /// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN /// THE SOFTWARE. /// /// Ramunas Geciauskas /// Contains a MouseHook class for setting up low level Windows mouse hooks. #endregion using System; using System.Runtime.InteropServices; using System.Diagnostics; namespace RamGecTools { /// /// Class for intercepting low level Windows mouse hooks. /// class MouseHook { /// /// Internal callback processing function /// private delegate IntPtr MouseHookHandler(int nCode, IntPtr wParam, IntPtr lParam); private MouseHookHandler hookHandler; /// /// Function to be called when defined even occurs /// /// MSLLHOOKSTRUCT mouse structure public delegate void MouseHookCallback(MSLLHOOKSTRUCT mouseStruct); #region Events public event MouseHookCallback LeftButtonDown; public event MouseHookCallback LeftButtonUp; public event MouseHookCallback RightButtonDown; public event MouseHookCallback RightButtonUp; public event MouseHookCallback MouseMove; public event MouseHookCallback MouseWheel; public event MouseHookCallback DoubleClick; public event MouseHookCallback MiddleButtonDown; public event MouseHookCallback MiddleButtonUp; #endregion /// /// Low level mouse hook's ID /// private IntPtr hookID = IntPtr.Zero; /// /// Install low level mouse hook /// /// Callback function public void Install() { hookHandler = HookFunc; hookID = SetHook(hookHandler); } /// /// Remove low level mouse hook /// public void Uninstall() { if (hookID == IntPtr.Zero) return; UnhookWindowsHookEx(hookID); hookID = IntPtr.Zero; } /// /// Destructor. Unhook current hook /// ~MouseHook() { Uninstall(); } /// /// Sets hook and assigns its ID for tracking /// /// Internal callback function /// Hook ID private IntPtr SetHook(MouseHookHandler proc) { using (ProcessModule module = Process.GetCurrentProcess().MainModule) return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(module.ModuleName), 0); } /// /// Callback function /// private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam) { // parse system messages if (nCode >= 0) { if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam) if (LeftButtonDown != null) LeftButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam) if (LeftButtonUp != null) LeftButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_RBUTTONDOWN == (MouseMessages)wParam) if (RightButtonDown != null) RightButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_RBUTTONUP == (MouseMessages)wParam) if (RightButtonUp != null) RightButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam) if (MouseMove != null) MouseMove((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_MOUSEWHEEL == (MouseMessages)wParam) if (MouseWheel != null) MouseWheel((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_LBUTTONDBLCLK == (MouseMessages)wParam) if (DoubleClick != null) DoubleClick((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_MBUTTONDOWN == (MouseMessages)wParam) if (MiddleButtonDown != null) MiddleButtonDown((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); if (MouseMessages.WM_MBUTTONUP == (MouseMessages)wParam) if (MiddleButtonUp != null) MiddleButtonUp((MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT))); } return CallNextHookEx(hookID, nCode, wParam, lParam); } #region WinAPI private const int WH_MOUSE_LL = 14; private enum MouseMessages { WM_LBUTTONDOWN = 0x0201, WM_LBUTTONUP = 0x0202, WM_MOUSEMOVE = 0x0200, WM_MOUSEWHEEL = 0x020A, WM_RBUTTONDOWN = 0x0204, WM_RBUTTONUP = 0x0205, WM_LBUTTONDBLCLK = 0x0203, WM_MBUTTONDOWN = 0x0207, WM_MBUTTONUP = 0x0208 } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public struct MSLLHOOKSTRUCT { public POINT pt; public uint mouseData; public uint flags; public uint time; public IntPtr dwExtraInfo; } [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, MouseHookHandler lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); #endregion } }