システムトレイにあるプログラムを書いています。開いているアプリケーションで、入力されたすべての入力にキーボードフックがあります。入力された入力をインターセプトし、その入力でコードを実行してから、入力する新しい「正しい」文字を送信する必要があります。この新しいキャラクターは、フォーカスのあるアプリに表示されるものになります。
StackOverflow に関する別の質問でこのコードを見つけましたが、良さそうです。 http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx
ソリューションにクラスとして追加し、Form1 コンストラクターで新しいインスタンスを作成すると、コンパイルされます。任意のアプリへの型指定された入力は、一度に 1 文字ずつ Visual Studio の出力ペインに表示されます。
問題は、このコードが私の頭をはるかに超えていることです。これが、キーボード フックにこの非常に簡潔なコードを使用することの欠点です。使用方法を教えてくれる試行錯誤がありませんでした。
このプログラムが次のように機能することを想定しました。
key is pressed, triggers an event
get key information from the event
do computation on the key information, pick the character to be typed
send that key to the relevant program
my character is typed rather than the original keypress character
このコードは、この一連のイベントにどのように適合しますか? 入力する前に入力文字を読み取る必要があります。では、入力を分析して正しい入力をライブで決定するコードはどこにあるのでしょうか? 最後に、フォーカスのあるアプリに文字を送信するために呼び出す正しい「sendInput()」タイプのコマンドは何ですか?
参照用の完全なコードは次のとおりです。
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(
int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
アドバイスありがとうございます!または、これについてもっと良い方法はありますか?
ありがとう!
アップデート
私の HookCallback メソッドは次のようになります。
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
//Console.WriteLine((Keys)vkCode);
KBDLLHOOKSTRUCT replacementKey = new KBDLLHOOKSTRUCT();
Marshal.PtrToStructure(lParam, replacementKey);
replacementKey.vkCode = 90; // char 'Z'
Marshal.StructureToPtr(replacementKey, lParam, true);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
シュート...追加Marshal.StructureToPtr
は近いですが、A first chance exception of type 'System.ArgumentException' occurred in foobar.exe
エラーになります。
アンセーフ コード、マーシャリングなしなどのバージョン (まだ「Z」は出力されません!)
unsafe private static IntPtr HookCallback(int nCode, IntPtr wParam, void* lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
KBDLLHOOKSTRUCT* replacementKey = (KBDLLHOOKSTRUCT*)lParam;
replacementKey->vkCode = 90;
}
return CallNextHookEx(_hookID, nCode, wParam, (IntPtr) lParam);
}