Windowsサービスからキープレスイベントをグローバルに検出するためにどのwin32呼び出しを使用できますか(1つのウィンドウだけでなく、キーが押されるたびにメッセージを取得したい)?
5 に答える
Win32 フックを使用したい。特にキーボードフック。
必要なフックのタイプは WH_KEYBOARD で、Win32 API SetWindowsHookEx を介して設定できます。
基本的に、ウィンドウは、アプリケーション システム全体でキーが押されるたびに、作成した dll 内の関数を呼び出します。
フックは、次のインターフェイスを持つ関数を呼び出します。
LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
);
Windows フックを使用すると、すべてのプロセスにわたってシステム全体のイベントを追跡できるだけでなく、それらをフィルター処理して完全に停止することもできます。
SetWindowHookEx で設定できるフックを見てみましょう。
http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx
ただし、「対話型」サービスを実行していない限り、デスクトップにアクセスすることはできません (また、新しいバージョンの Windows では正しく動作しないため、対話型サービスを実行するべきではありません)。デスクトップ/コンソールにアクセスするには、セッションおよびデスクトップ管理 API を調べる必要があります。
MSDN で Raw Input API を確認してください。
http://msdn.microsoft.com/en-us/library/ms645536(VS.85).aspx
これにより、グローバル フックをいじることなく、キーボードからの入力を (とりわけ) 取得できます。グローバル フックは、意図しない結果をもたらす可能性があるため、最後の手段としてのみ使用してください。
Raw Input を使用する唯一の欠点は、ソフトウェアによって生成されたキーストロークを適切に受信できない可能性があることです。
user32 DLL のネイティブ関数 GetKeyState、GetAsyncKeyState、または GetKeyboardState を使用するだけです。
上記の各関数については、msdn サイトで読むことができます。
h ttp://msdn.microsoft.com/en-us/library/windows/desktop/ms646301(v=vs.85).aspx
GetKeyStateの場合、および
h ttp://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
GetAsyncKeyStateの場合、および
h ttp://msdn.microsoft.com/en-us/library/windows/desktop/ms646299(v=vs.85).aspx
GetKeyboardStateの場合。
C# でプログラミングする場合:
コードには、クラス、構造体、または列挙型の宣言から次の行を含める必要があります。
using System.Runtime.InteropServices;
次に、キーを検出するメソッドを含むクラスで、上記の 3 つの関数のいずれかを選択して、または何が機能し、何が機能しないかを定義します。
[DllImport("user32.dll")]
static uint GetKeyState(byte virtualKeyCode);
//or
[DllImport("user32.dll")]
static uint GetAsyncKeyState(byte virtualKeyCode);
//or
[DllImport("user32.dll")]
static uint GetKeyboardState(byte[] virtualKeyCodes);
//NOTE: The length of the byte array parameter must be always 256 bytes!
戻り値の型をuintにしたくない場合は、 intに変更することもできます。
ネイティブ関数が常に 1 を true として、または 0 を false として返す場合は、代わりに戻り値の型をboolに変更できますが、そうする場合は、ネイティブ関数の定義の上に別のコード行を追加する必要があると思います。
[MarshalAs(UnmanagedType.Bool)]
または、次の行をネイティブ関数定義の途中 (DllImport という単語がある行の下、および「extern」という単語がある行の上) に追加できます。
[return: MarshalAs(UnmanagedType.Bool)]
Pinvoke サイトでは、これらの関数のより良い定義が提供されているため、キーボードの特定のキーに言及するために整数を使用する必要はありませんが、よりわかりやすい列挙型を使用できます。
次のリンクは、C#でのGetKeyStateの定義につながります。
h ttp://www.pinvoke.net/default.aspx/user32.getkeystate
次のリンクは、C#でのGetAsyncKeyStateの定義につながります。
h ttp://www.pinvoke.net/default.aspx/user32.getasynckeystate
次のリンクは、C#でのGetKeyboardStateの定義につながります。
h ttp://www.pinvoke.net/default.aspx/user32.getkeyboardstate
(いつでもどこでも) どのキーが押されているかを検出するには、 GetKeyState または GetAsyncKeyState 関数を呼び出します。単一のパラメーターで、検出するキーを指定し、呼び出しの後に& 0x8000または& 0x80を追加します。上記のキーが押されている場合、式の戻り値はゼロではありませんが、それ以外の場合はゼロです。返された式の整数に応じて、どのキーが押されたかどうかを判断できます。ループ内にある式 != 0 を入力条件として if ステートメント内にコードを配置すると、そのキーを押したときにその if ステートメント内のコードが複数回、実際には何度も実行されることに注意してください。コードを一度だけ実行したい場合キーを押して離すと、次のコードはこの目標を達成するためのトリックです。
while (boolean exression that will return false when you want to quit this loop)
{
if (boolean expression that will return true when particular key is **held down**) //This boolean expression calls either GetKeyState or GetAsyncKeyState with the & 0x8000 or & 0x80 after the call, and then != 0 to check for **held down** key
while (true) //It's purpose is to wait for the same key that was held down to be released. After code execution, it will encounter the break keyword that will finish him, even though that his enter condition is true.
if (boolean expression that will return true when the **same** particular key is **NOT** held down! (NOT held down, means that at that time, that key was released). You can copy the same condition from the first if statement, and just change **!=**, which is next to 0, to **==**, or instead add brackets to the condition '(' and ')', and in left of '(' add '!').
{
//Put here the code that you want to execute once, when paticular key was pressed and then released.
break; //the while (true), which is the only way to get out of it
}
}
これを .net アプリケーションに実装する場合は、GlobalKeyboardHookをお勧めします。それ以外の場合は、上記の DLLImport 関数を実装しているため、ソースを見て必要なものを取得します。