193 lines
6.0 KiB
C#
193 lines
6.0 KiB
C#
#define NO_UNSAFE
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms;
|
|
|
|
namespace DevComponents.DotNetBar
|
|
{
|
|
/// <summary>
|
|
/// Summary description for Hook.
|
|
/// </summary>
|
|
internal class Hook : IDisposable
|
|
{
|
|
private const int WH_MOUSE = 7;
|
|
private const int HC_ACTION = 0;
|
|
private const int WM_MOUSEMOVE = 0x0200;
|
|
private const int WH_KEYBOARD = 2;
|
|
|
|
private const int KF_EXTENDED=0x0100;
|
|
private const int KF_DLGMODE=0x0800;
|
|
private const int KF_MENUMODE=0x1000;
|
|
private const int KF_ALTDOWN=0x2000;
|
|
private const int KF_REPEAT=0x4000;
|
|
private const int KF_UP=0x8000;
|
|
|
|
private IntPtr m_hMouseHook=IntPtr.Zero;
|
|
private IntPtr m_hKeyboardHook=IntPtr.Zero;
|
|
private MouseProc m_mouseHook;
|
|
private KeyboardProc m_keyboardHook;
|
|
private IMessageHandlerClient m_Client=null;
|
|
|
|
public Hook(IMessageHandlerClient client)
|
|
{
|
|
m_Client=client;
|
|
m_mouseHook = new MouseProc(OnMouseHook);
|
|
m_keyboardHook=new KeyboardProc(OnKeyboardHook);
|
|
m_hMouseHook = SetWindowsHookEx(WH_MOUSE, m_mouseHook, IntPtr.Zero, GetCurrentThreadId());
|
|
m_hKeyboardHook=SetWindowsHookExKeyboard(WH_KEYBOARD,m_keyboardHook,IntPtr.Zero,GetCurrentThreadId());
|
|
if (m_hMouseHook == IntPtr.Zero || m_hKeyboardHook==IntPtr.Zero)
|
|
{
|
|
throw new Win32Exception();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (m_hMouseHook != IntPtr.Zero)
|
|
{
|
|
IntPtr h = m_hMouseHook;
|
|
m_hMouseHook = IntPtr.Zero;
|
|
UnhookWindowsHookEx(h);
|
|
}
|
|
if (m_hKeyboardHook != IntPtr.Zero)
|
|
{
|
|
IntPtr h = m_hKeyboardHook;
|
|
m_hKeyboardHook = IntPtr.Zero;
|
|
UnhookWindowsHookEx(h);
|
|
}
|
|
}
|
|
|
|
// A note on using unsafe code:
|
|
//
|
|
// When taking a native pointer and converting it into a structure pointer,
|
|
// if you only need to examine the contents of the structure then it is very
|
|
// wasteful to use Marshal.PtrToStructure. Structures are very efficient
|
|
// because they are stack allocated, but by converting them to an object
|
|
// to be returned, Marshal causes a boxing operation to happen which
|
|
// allocates an object on the heap. This normally isn't a big deal
|
|
// but for window messages that occur with a high frequency you can
|
|
// see a spike of many hundreds of objects being allocated. Using
|
|
// unsafe blocks are great when you are writing an EXE that runs on a
|
|
// user's local machine. If you are writing a library that can be downloaded
|
|
// over the internet you should not use them, because they require elevated
|
|
// security permissions. That's not a big deal for this sample because
|
|
// we already need unmanaged code permission to create the hook.
|
|
|
|
#if NO_UNSAFE
|
|
private IntPtr OnMouseHook(int nCode, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
if (nCode == HC_ACTION)
|
|
{
|
|
int msg=WinApi.ToInt(wParam);
|
|
if(msg == NativeFunctions.WM_LBUTTONDOWN || msg==NativeFunctions.WM_NCLBUTTONDOWN ||
|
|
msg==NativeFunctions.WM_RBUTTONDOWN || msg==NativeFunctions.WM_MBUTTONDOWN ||
|
|
msg==NativeFunctions.WM_NCMBUTTONDOWN || msg==NativeFunctions.WM_NCRBUTTONDOWN)
|
|
{
|
|
MOUSEHOOKSTRUCT mhs = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MOUSEHOOKSTRUCT));
|
|
|
|
m_Client.OnMouseDown(mhs.hwnd,IntPtr.Zero,lParam);
|
|
}
|
|
}
|
|
|
|
return CallNextHookEx(m_hMouseHook, nCode, wParam, lParam);
|
|
}
|
|
private IntPtr OnKeyboardHook(int nCode, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
if (nCode == HC_ACTION)
|
|
{
|
|
int ilParam=WinApi.ToInt(lParam);
|
|
int iwParam=WinApi.ToInt(wParam);
|
|
int iCode=ilParam>>16;
|
|
if((iCode & KF_ALTDOWN)!=0)
|
|
{
|
|
if((iCode & KF_UP)!=0)
|
|
{
|
|
if(m_Client.OnSysKeyUp(IntPtr.Zero,wParam,lParam))
|
|
return (IntPtr)1;
|
|
}
|
|
else //if((ilParam & KF_REPEAT)==0)
|
|
{
|
|
if(m_Client.OnSysKeyDown(IntPtr.Zero,wParam,lParam))
|
|
return (IntPtr)1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((iCode & KF_UP)==0)
|
|
{
|
|
if(m_Client.OnKeyDown(IntPtr.Zero,wParam,lParam))
|
|
return (IntPtr)1;
|
|
}
|
|
else if(iwParam==18 || iwParam==121)
|
|
{
|
|
if(m_Client.OnSysKeyUp(IntPtr.Zero,wParam,lParam))
|
|
return (IntPtr)1;
|
|
}
|
|
}
|
|
}
|
|
return CallNextHookEx(m_hKeyboardHook, nCode, wParam, lParam);
|
|
}
|
|
#else
|
|
private unsafe IntPtr OnMouseHook(int nCode, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
if (nCode == HC_ACTION && MouseEvent != null)
|
|
{
|
|
if (wParam == (IntPtr)WM_MOUSEMOVE)
|
|
{
|
|
MOUSEHOOKSTRUCT* pmhs = (MOUSEHOOKSTRUCT*)lParam;
|
|
MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, pmhs->pt.x, pmhs->pt.y, 0);
|
|
MouseEvent(this, e);
|
|
}
|
|
}
|
|
|
|
return CallNextHookEx(_hHook, nCode, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
private delegate IntPtr MouseProc(int nCode, IntPtr wParam, IntPtr lParam);
|
|
private delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
|
|
|
|
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
|
|
private static extern IntPtr SetWindowsHookEx(int hookid, MouseProc pfnhook, IntPtr hinst, int threadid);
|
|
|
|
[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true, EntryPoint="SetWindowsHookEx")]
|
|
private static extern IntPtr SetWindowsHookExKeyboard(int hookid, KeyboardProc pfnhook, IntPtr hinst, int threadid);
|
|
|
|
[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
|
|
private static extern bool UnhookWindowsHookEx(IntPtr hhook);
|
|
|
|
[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
|
|
private static extern IntPtr CallNextHookEx(IntPtr hhook, int code, IntPtr wparam, IntPtr lparam);
|
|
|
|
[DllImport("kernel32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
|
|
private static extern int GetCurrentThreadId();
|
|
|
|
private struct POINT
|
|
{
|
|
public POINT(int x, int y)
|
|
{
|
|
this.x=x;
|
|
this.y=y;
|
|
}
|
|
public int x;
|
|
public int y;
|
|
}
|
|
|
|
private struct MOUSEHOOKSTRUCT
|
|
{
|
|
public MOUSEHOOKSTRUCT(POINT pt, IntPtr hwnd, ushort wHitTestCode, IntPtr dwExtraInfo)
|
|
{
|
|
this.pt=pt;
|
|
this.hwnd=hwnd;
|
|
this.wHitTestCode=wHitTestCode;
|
|
this.dwExtraInfo=dwExtraInfo;
|
|
}
|
|
public POINT pt;
|
|
public IntPtr hwnd;
|
|
public ushort wHitTestCode;
|
|
public IntPtr dwExtraInfo;
|
|
}
|
|
}
|
|
}
|