using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace HongliangSoft.Utilities.Gui {
///キーボードが操作されたときに実行されるメソッドを表すイベントハンドラ。
public delegate void KeyboardHookedEventHandler(object sender, KeyboardHookedEventArgs e);
///KeyboardHookedイベントのデータを提供する。
public class KeyboardHookedEventArgs : CancelEventArgs {
///新しいインスタンスを作成する。
internal KeyboardHookedEventArgs(KeyboardMessage message, ref KeyboardState state) {
this.message = message;
this.state = state;
}
private KeyboardMessage message;
private KeyboardState state;
///キーボードが押されたか放されたかを表す値を取得する。
public KeyboardUpDown UpDown {
get {
return (message == KeyboardMessage.KeyDown || message == KeyboardMessage.SysKeyDown) ?
KeyboardUpDown.Down : KeyboardUpDown.Up;
}
}
///操作されたキーの仮想キーコードを表す値を取得する。
public Keys KeyCode {get {return state.KeyCode;}}
///操作されたキーのスキャンコードを表す値を取得する。
public int ScanCode {get {return state.ScanCode;}}
///操作されたキーがテンキーなどの拡張キーかどうかを表す値を取得する。
public bool IsExtendedKey {get {return state.Flag.IsExtended;}}
///ALTキーが押されているかどうかを表す値を取得する。
public bool AltDown {get {return state.Flag.AltDown;}}
}
///キーボードが押されているか放されているかを表す。
public enum KeyboardUpDown {
///キーは押されている。
Down,
///キーは放されている。
Up,
}
///メッセージコードを表す。
internal enum KeyboardMessage {
///キーが押された。
KeyDown = 0x100,
///キーが放された。
KeyUp = 0x101,
///システムキーが押された。
SysKeyDown = 0x104,
///システムキーが放された。
SysKeyUp = 0x105,
}
///キーボードの状態を表す。
internal struct KeyboardState {
///仮想キーコード。
public Keys KeyCode;
///スキャンコード。
public int ScanCode;
///各種特殊フラグ。
public KeyboardStateFlag Flag;
///このメッセージが送られたときの時間。
public int Time;
///メッセージに関連づけられた拡張情報。
public IntPtr ExtraInfo;
}
///キーボードの状態を補足する。
internal struct KeyboardStateFlag {
private int flag;
private bool IsFlagging(int value) {
return (flag & value) != 0;
}
private void Flag(bool value, int digit) {
flag = value ? (flag | digit) : (flag & ~digit);
}
///キーがテンキー上のキーのような拡張キーかどうかを表す。
public bool IsExtended {get {return IsFlagging(0x01);} set {Flag(value, 0x01);}}
///イベントがインジェクトされたかどうかを表す。
public bool IsInjected {get {return IsFlagging(0x10);} set {Flag(value, 0x10);}}
///ALTキーが押されているかどうかを表す。
public bool AltDown {get {return IsFlagging(0x20);} set {Flag(value, 0x20);}}
///キーが放されたどうかを表す。
public bool IsUp {get {return IsFlagging(0x80);} set {Flag(value, 0x80);}}
}
///キーボードの操作をフックし、任意のメソッドを挿入する。
[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);
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();
///キーボードが操作されたときに発生する。
public event KeyboardHookedEventHandler KeyboardHooked {
add {base.Events.AddHandler(EventKeyboardHooked, value);}
remove {base.Events.RemoveHandler(EventKeyboardHooked, value);}
}
///
///KeyboardHookedイベントを発生させる。
///
///イベントのデータ。
protected virtual void OnKeyboardHooked(KeyboardHookedEventArgs e) {
KeyboardHookedEventHandler handler = base.Events[EventKeyboardHooked] as KeyboardHookedEventHandler;
if (handler != null)
handler(this, e);
}
///
///新しいインスタンスを作成する。
///
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);
}
///
///キーボードが操作されたときに実行するデリゲートを指定してインスタンスを作成する。
///
///キーボードが操作されたときに実行するメソッドを表すイベントハンドラ。
public KeyboardHook(KeyboardHookedEventHandler handler) : this() {
this.KeyboardHooked += handler;
}
private int CallNextHook(int code, KeyboardMessage message, ref KeyboardState state) {
if (code >= 0) {
KeyboardHookedEventArgs e = new KeyboardHookedEventArgs(message, ref state);
OnKeyboardHooked(e);
if (e.Cancel) {
return -1;
}
}
return CallNextHookEx(IntPtr.Zero, code, message, ref state);
}
///
///使用されているアンマネージリソースを解放し、オプションでマネージリソースも解放する。
///
///マネージリソースも解放する場合はtrue。
protected override void Dispose(bool disposing) {
if (this.hookDelegate.IsAllocated) {
UnhookWindowsHookEx(hook);
this.hook = IntPtr.Zero;
this.hookDelegate.Free();
}
base.Dispose(disposing);
}
}
}