3

このスレッドからのアドバイスに従って:キーボードの実際のキーと仮想のキーの押下を区別します

SendInput()メソッドを使用してキーボードのキー押下イベントを送信するプログラムを作成しようとしています。

ただし、問題は、キーを押すイベントをシミュレートしようとすると、何も起こらないことです。これまでのところ、これが私のコードです。

    [DllImport("user32.dll")]
    static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);

    [StructLayout(LayoutKind.Sequential)]
    struct KEYBDINPUT
    {
        public short wScan; public int dwFlags;
        public int time; public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Explicit)]
    struct INPUT
    {
        [FieldOffset(0)] public int type;
        [FieldOffset(8)]  public KEYBDINPUT ki; //x64 - 8, x32 - 4
    }

    const int KEYEVENTF_DOWN = 0; //key UP
    const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    const int KEYEVENTF_KEYUP = 0x0002; //key UP
    const int KEYEVENTF_UNICODE = 0x0004;
    const int KEYEVENTF_SCANCODE = 0x0008; // scancode

    public void Send_Key(short Keycode)
    {
        INPUT[] InputData = new INPUT[1];
        InputData[0].type = 1;
        InputData[0].ki.wScan = Keycode;
        InputData[0].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
        InputData[0].ki.time = 0;
        InputData[0].ki.dwExtraInfo = IntPtr.Zero;
        SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
    }

スキャンコードを解読するために、このスレッドで提案されたプログラムをダウンロードしました。

https://superuser.com/questions/293609/windows-7-tool-to-capture-keyboard-scan-codes

このプログラムによると、キーボードの「a」キーのコードは「65」です。

私のプログラムは、テキストボックスのテキストが変更されたときにキーを押すイベントをトリガーすることになっているので、「q」と入力すると、テキストは「q」にsend_key()の結果、つまり「qa」を加えたものに変更されます。

    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        Send_Key(0x0065); // nothing happens (0x65 also fails)
    }

私は何が間違っているのですか?将来的には、このコードを変更して、キー保持時間を指定できるようにします(DOWNイベントとUPイベントの間)。ただし、現時点では、テストの目的で、keyUPイベントのみをシミュレートしています。

編集:ハンス、あなたのアドバイスによると、ここに編集があります-しかし、残念ながら、それは機能しません。

 public void Send_Key(short Keycode)
        {
            INPUT[] InputData = new INPUT[1];
            InputData[0].type = 1;
            InputData[0].ki.wScan = Keycode;
            InputData[0].ki.dwFlags = KEYEVENTF_DOWN;
            InputData[0].ki.time = 0;
            InputData[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn = SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn == 0) //!=1
            {
                throw new Exception("Could not send keyDOWN: " + Keycode);
            }

            INPUT[] InputData2 = new INPUT[1];
            InputData2[0].type = 1;
            InputData2[0].ki.wScan = Keycode;
            InputData2[0].mi.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE;
            InputData2[0].ki.time = 0;
            InputData2[0].ki.dwExtraInfo = IntPtr.Zero;

            uint intReturn2 = SendInput(1, InputData2, Marshal.SizeOf(typeof(INPUT)));

            if (intReturn2 == 0) //!=1
            {
                throw new Exception("Could not send keyUP: " + Keycode);
            }
        }

エラーなし..および出力なし。

4

1 に答える 1

2

しかし今のところ、テストの目的で、keyUPイベントのみをシミュレートしています

これは大丈夫だと思いますが、それではWindowsに何も実行されません。キーストロークを生成するには、最初にKEYDOWNを送信する必要があります。「ホールドタイム」は有用な効果がないため、2つのSendInput呼び出しを同じメソッドに入れるだけです。

エラーチェックを追加する必要があります。winapi呼び出しは例外を生成しません。関数が0を返す場合は、Win32Exceptionをスローします。そして[DllImport]宣言をSetLastError=trueで修正します。

代わりにki.wVkフィールドを設定し、KEYEVENTF_SCANCODEフラグを省略することにより、superuser.comで見つけたそのプログラムの使用を回避できます。そのため、スキャンコードの代わりに仮想キーを指定します。.NET Keys列挙型は、必要な値を提供します。Keys.Aと同様に、Aキーのキー押下を生成します。

于 2012-04-29T19:54:02.610 に答える