ドキュメントの多さを期待して古代のもので作ったらハマったのでメモ
環境
- Visual Studio Community 2017 ver.15.7.5
- .NET Framework 4.7.1
使うもの
- マウス:グローバルフック・ザ・マウスより,
MouseHook2.cs
をダウンロード -
MouseHook.cs
にリネームする - キーボード:グローバルフック・ザ・キーボードより,
KeyboardHook3.cs
をダウンロード -
KeyboardHook.cs
にリネームする
コードの書き換え
古代のコード故に今のVSだとそのまま動かないらしいので,上記サイトのコメント欄を参考にし,一部を書き換える必要がある。
※解決法としてあるVSのデバッグオプションの項目はVS2017から消えたらしい(?)
各々,2箇所を以下のように変更する。
MouseHook.csの一部
[DefaultEvent("MouseHooked")]
public class MouseHook : System.ComponentModel.Component {
[DllImport("user32.dll", SetLastError=true)]
private static extern IntPtr SetWindowsHookEx(int hookType, MouseHookDelegate hookDelegate, IntPtr hInstance, uint threadId);
[DllImport("user32.dll", SetLastError=true)]
private static extern int CallNextHookEx(IntPtr hook, int code, MouseMessage message, ref MouseState state);
[DllImport("user32.dll", SetLastError=true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
/* 追加部分 */
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
IntPtr module = LoadLibrary("user32.dll");
/*---------*/
private const int MouseLowLevelHook = 14;
private delegate int MouseHookDelegate(int code, MouseMessage message, ref MouseState state);
private IntPtr hook;
private GCHandle hookDelegate;
private static readonly object EventMouseHooked = new object();
///<summary>マウスが入力されたときに発生する。</summary>
public event MouseHookedEventHandler MouseHooked {
add {base.Events.AddHandler(EventMouseHooked, value);}
remove {base.Events.RemoveHandler(EventMouseHooked, value);}
}
///<summary>
///インスタンスを作成する。
///</summary>
///<exception cref="Win32Exception">フックに失敗しました。原因の詳細はエラーコードを参照してください。</exception>
public MouseHook() {
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
throw new PlatformNotSupportedException("Windows 98/Meではサポートされていません。");
MouseHookDelegate handler = new MouseHookDelegate(CallNextHook);
this.hookDelegate = GCHandle.Alloc(handler);
//IntPtr module = Marshal.GetHINSTANCE(typeof(MouseHook).Assembly.GetModules()[0]); // ここを消すかコメントアウト
this.hook = SetWindowsHookEx(MouseLowLevelHook, handler, module, 0);
if (hook == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
}
KeyboardHook.csの一部
[DefaultEvent("KeyboardHooked")]
public class KeyboardHook : Component {
[DllImport("user32.dll", SetLastError=true)]
private static extern IntPtr SetWindowsHookEx(int hookType, KeyboardHookDelegate hookDelegate, IntPtr hInstance, uint threadId);
[DllImport("user32.dll", SetLastError=true)]
private static extern int CallNextHookEx(IntPtr hook, int code, KeyboardMessage message, ref KeyboardState state);
[DllImport("user32.dll", SetLastError=true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
/* 追加部分 */
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);
IntPtr module = LoadLibrary("user32.dll");
/*---------*/
private delegate int KeyboardHookDelegate(int code, KeyboardMessage message, ref KeyboardState state);
private const int KeyboardHookType = 13;
private GCHandle hookDelegate;
private IntPtr hook;
private static readonly object EventKeyboardHooked = new object();
///<summary>キーボードが操作されたときに発生する。</summary>
public event KeyboardHookedEventHandler KeyboardHooked {
add {base.Events.AddHandler(EventKeyboardHooked, value);}
remove {base.Events.RemoveHandler(EventKeyboardHooked, value);}
}
///<summary>
///KeyboardHookedイベントを発生させる。
///</summary>
///<param name="e">イベントのデータ。</param>
protected virtual void OnKeyboardHooked(KeyboardHookedEventArgs e) {
KeyboardHookedEventHandler handler = base.Events[EventKeyboardHooked] as KeyboardHookedEventHandler;
if (handler != null)
handler(this, e);
}
///<summary>
///新しいインスタンスを作成する。
///</summary>
public KeyboardHook() {
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
throw new PlatformNotSupportedException("Windows 98/Meではサポートされていません。");
KeyboardHookDelegate callback = new KeyboardHookDelegate(CallNextHook);
this.hookDelegate = GCHandle.Alloc(callback);
//IntPtr module = Marshal.GetHINSTANCE(typeof(KeyboardHook).Assembly.GetModules()[0]); // ここを消すかコメントアウト
this.hook = SetWindowsHookEx(KeyboardHookType, callback, module, 0);
}
プロジェクトへの追加
- ファイル→追加→新しいプロジェクト→クラスライブラリ(.NET Framework)を作成
- ソリューションエクスプローラー上で追加したクラスライブラリを右クリック→追加→既存の項目で
MouseHook.cs
とKeyboardHook.cs
を追加 - 同様に右クリック→追加→参照で,
System.Drawing
とSystem.Windows.Forms
にチェックを入れてOK - ソリューションエクスプローラー上でイベントを使うプロジェクト(元のプロジェクト)を右クリック→追加→参照→プロジェクトで今作成したクロスライブラリを追加
- ビルドする
- フォームデザインを開き,ツールボックスをクリック
-
MouseHook
とKeyboardHook
が追加されていればOK
MouseHookとKeyboardHookの利用
- 追加された
MouseHook
とKeyboardHook
をダブルクリックし,フォームに追加する。正しくできていれば,フォームのデザイン画面の下にMouseHook1
とKeyboardHook1
ができているはず - 追加した
MouseHook1
とKeyboardHook1
をダブルクリックすると,Form1.cs上に各々のイベント検知コードが追加される
※ using HongliangSoft.Utilities.Gui;
を書いておくと良い
例
using HongliangSoft.Utilities.Gui;
が書いてある前提
private void mouseHook1_MouseHooked(object sender, MouseHookedEventArgs e) {
if (e.Message == MouseMessage.LDown) {
/* 左クリックを検知したときの動作 */
}
}
private void keyboardHook1_KeyboardHooked(object sender, KeyboardHookedEventArgs e) {
if(e.UpDown == KeyboardUpDown.Down) {
if(e.KeyCode == Keys.Space) {
/* スペースキーが押されたときの動作 */
}
}
}
その他
マウスの座標は特別なことをしなくてもCursor
で取れるっぽい