Обработка событий вне формы (глобальный перехват клавиш) - C#
Формулировка задачи:
Здравствуйте!
В процессе обучения у меня возникли 2 вопроса:
1. Можно ли написать приложение для обработки нажатия кнопок клавиатуры, которое будет работать вне формы? К примеру, мне нужно чтобы при нажатии какой-нибудь кнопки курсор перемещался в заданную точку рабочего стола.
2. Можно ли отдельно обработать событие перемещения курсора(мышь неподвижна) и перемещение мыши. В первом случае подразумевается, что курсор перемещается программным путем. К примеру:
Cursor.Position = new Point(150,150);
Решение задачи: «Обработка событий вне формы (глобальный перехват клавиш)»
textual
Листинг программы
public static class MouseHook
{
#region Declarations
public static event MouseEventHandler MouseDown;
public static event MouseEventHandler MouseUp;
public static event MouseEventHandler MouseMove;
[StructLayout( LayoutKind.Sequential )]
struct MOUSEHOOKSTRUCT
{
public POINT pt;
public IntPtr hwnd;
public int wHitTestCode;
public IntPtr dwExtraInfo;
}
[StructLayout( LayoutKind.Sequential )]
struct MSLLHOOKSTRUCT
{
public POINT pt;
public int mouseData;
public int flags;
public int time;
public IntPtr dwExtraInfo;
}
[StructLayout( LayoutKind.Sequential )]
struct POINT
{
public int X;
public int Y;
public POINT ( int x, int y )
{
this.X = x;
this.Y = y;
}
public static implicit operator Point ( POINT p )
{
return new Point( p.X, p.Y );
}
public static implicit operator POINT ( Point p )
{
return new POINT( p.X, p.Y );
}
}
const int WM_LBUTTONDOWN = 0x201;
const int WM_LBUTTONUP = 0x202;
const int WM_MOUSEMOVE = 0x0200;
const int WM_MOUSEWHEEL = 0x020A;
const int WM_RBUTTONDOWN = 0x0204;
const int WM_RBUTTONUP = 0x0205;
const int WM_MBUTTONUP = 0x208;
const int WM_MBUTTONDOWN = 0x207;
const int WM_XBUTTONDOWN = 0x20B;
const int WM_XBUTTONUP = 0x20C;
static IntPtr hHook = IntPtr.Zero;
static IntPtr hModule = IntPtr.Zero;
static bool hookInstall = false;
static bool localHook = true;
static API.HookProc hookDel;
#endregion
/// <summary>
/// Hook install method.
/// </summary>
public static void InstallHook ( )
{
if ( IsHookInstalled )
return;
hModule = Marshal.GetHINSTANCE( AppDomain.CurrentDomain.GetAssemblies()[0].GetModules()[0] );
hookDel = new API.HookProc( HookProcFunction );
if ( localHook )
hHook = API.SetWindowsHookEx( API.HookType.WH_MOUSE,
hookDel, IntPtr.Zero, AppDomain.GetCurrentThreadId() ); // Если подчеркивает необращай внимание, так надо.
else
hHook = API.SetWindowsHookEx( API.HookType.WH_MOUSE_LL,
hookDel, hModule, 0 );
if ( hHook != IntPtr.Zero )
hookInstall = true;
else
throw new Win32Exception( "Can't install low level keyboard hook!" );
}
/// <summary>
/// If hook installed return true, either false.
/// </summary>
public static bool IsHookInstalled
{
get { return hookInstall && hHook != IntPtr.Zero; }
}
/// <summary>
/// Module handle in which hook was installed.
/// </summary>
public static IntPtr ModuleHandle
{
get { return hModule; }
}
/// <summary>
/// If true local hook will installed, either global.
/// </summary>
public static bool LocalHook
{
get { return localHook; }
set
{
if ( value != localHook )
{
if ( IsHookInstalled )
throw new Win32Exception( "Can't change type of hook than it install!" );
localHook = value;
}
}
}
/// <summary>
/// Uninstall hook method.
/// </summary>
public static void UnInstallHook ( )
{
if ( IsHookInstalled )
{
if ( !API.UnhookWindowsHookEx( hHook ) )
throw new Win32Exception( "Can't uninstall low level keyboard hook!" );
hHook = IntPtr.Zero;
hModule = IntPtr.Zero;
hookInstall = false;
}
}
/// <summary>
/// Hook process messages.
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
static IntPtr HookProcFunction ( int nCode, IntPtr wParam, [In] IntPtr lParam )
{
if ( nCode == 0 )
{
if ( localHook )
{
MOUSEHOOKSTRUCT mhs = (MOUSEHOOKSTRUCT)Marshal.PtrToStructure( lParam, typeof( MOUSEHOOKSTRUCT ) );
#region switch
switch ( wParam.ToInt32() )
{
case WM_LBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Left,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_LBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Left,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Middle,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Middle,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MOUSEMOVE:
if ( MouseMove != null )
MouseMove( null,
new MouseEventArgs( MouseButtons.None,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MOUSEWHEEL:
// Данный хук не позволяет узнать куда вращается колесо мыши.
break;
case WM_RBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Right,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_RBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Right,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
default:
//Debug.WriteLine(string.Format("X:{0}; Y:{1}; Handle:{2}; HitTest:{3}; EI:{4}; wParam:{5}; lParam:{6}",
// mhs.pt.X, mhs.pt.Y, mhs.hwnd, mhs.wHitTestCode, mhs.dwExtraInfo, wParam.ToString(), lParam.ToString()));
break;
}
#endregion
}
else
{
MSLLHOOKSTRUCT mhs = (MSLLHOOKSTRUCT)Marshal.PtrToStructure( lParam, typeof( MSLLHOOKSTRUCT ) );
#region switch
switch ( wParam.ToInt32() )
{
case WM_LBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Left,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_LBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Left,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Middle,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Middle,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MOUSEMOVE:
if ( MouseMove != null )
MouseMove( null,
new MouseEventArgs( MouseButtons.None,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_MOUSEWHEEL:
if ( MouseMove != null )
MouseMove( null,
new MouseEventArgs( MouseButtons.None, mhs.time,
mhs.pt.X, mhs.pt.Y, mhs.mouseData >> 16 ) );
//Debug.WriteLine(string.Format("X:{0}; Y:{1}; MD:{2}; Time:{3}; EI:{4}; wParam:{5}; lParam:{6}",
// mhs.pt.X, mhs.pt.Y, mhs.mouseData, mhs.time, mhs.dwExtraInfo, wParam.ToString(), lParam.ToString()));
break;
case WM_RBUTTONDOWN:
if ( MouseDown != null )
MouseDown( null,
new MouseEventArgs( MouseButtons.Right,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
case WM_RBUTTONUP:
if ( MouseUp != null )
MouseUp( null,
new MouseEventArgs( MouseButtons.Right,
1,
mhs.pt.X,
mhs.pt.Y,
0 ) );
break;
default:
break;
}
#endregion
}
}
return API.CallNextHookEx( hHook, nCode, wParam, lParam );
}
}
static class API
{
public delegate IntPtr HookProc ( int nCode, IntPtr wParam, [In] IntPtr lParam );
[DllImport( "user32.dll" )]
public static extern IntPtr CallNextHookEx ( IntPtr hhk, int nCode, IntPtr wParam, [In] IntPtr lParam );
[DllImport( "user32.dll", SetLastError = true )]
public static extern IntPtr SetWindowsHookEx ( HookType hookType, HookProc lpfn,
IntPtr hMod, int dwThreadId );
[DllImport( "user32.dll", SetLastError = true )]
public static extern bool UnhookWindowsHookEx ( IntPtr hhk );
[DllImport( "kernel32.dll", CharSet = CharSet.Auto, SetLastError = true )]
public static extern IntPtr GetModuleHandle ( string lpModuleName );
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
}