0

システムトレイにあるプログラムを書いています。開いているアプリケーションで、入力されたすべての入力にキーボードフックがあります。入力された入力をインターセプトし、その入力でコードを実行してから、入力する新しい「正しい」文字を送信する必要があります。この新しいキャラクターは、フォーカスのあるアプリに表示されるものになります。

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);
    }
4

2 に答える 2

1

このコードは、この一連のイベントにどのように適合しますか?入力する前に入力文字を読む必要があります。次に、入力を分析して正しい入力を決定するためのコードはどこにありますか?

メソッドは、HookCallbackキーストロークをインターセプトするためにインストールするメソッドです。

最後に、フォーカスのあるアプリに文字を送信するために呼び出す正しい「sendInput()」タイプのコマンドは何ですか?

他のプロセスに渡される文字を変更するには、メソッドに渡す前にパラメーター(、、、および/または)をnCode変更wParamします。lParamCallNextHookEx

于 2010-01-12T08:29:24.990 に答える
1

現時点では、このコードはコンソールに書き込むだけです。これは、HookCallback メソッドの 4 行目で発生します。したがって、その行を独自のコードに置き換える必要があります。

ただし、提供される情報は、C# に適した形式ではありません。LowLevelKeyboardProcの SDK ドキュメントを参照して、展開方法を理解する必要があります。KBDLLHOOKSTRUCT 構造体へのポインタである lParam にすべての良いものが含まれていることがわかります。

したがって、コードはそれを同等の C# にマーシャリングする必要があります。KBDLLHOOKSTRUCT 構造体を宣言するか、pinvoke.net に構造体があるかどうかを確認し、Marshal.PtrToStructure を使用して展開する必要があります。その後、Windows が許可する限り、この構造でパーティを組むことができます。キーボード イベントを強制終了してから新しいイベントをシミュレートするよりも、イベント データを変更する方が良いと思います (最初に、シミュレートされた "キーを送信する" と思います)。 " フック自体に直接実行されます!) -- しかし、これが可能かどうかを確認するためにこれを試したことはありません。SDK 構造体には仮想キー コードとスキャン コードが含まれているため、必要な効果を得るためにそれらを置き換えることができる場合がありますが、これにはおそらく試行錯誤が必要であり、アプリ固有のものになります。

于 2010-01-12T08:41:10.117 に答える