0

キーストロークをサードパーティのアプリケーションに送信する必要があるオンスクリーンキーボードを使用しています。それらはWindowsXPで実行されています。米国英語キーボードでは使用できない小さな文字セット(「å」やñなど)をサポートする必要があります。SendInputを確認した後、最も安全なのは、文字の16進Unicode値をキーストロークシーケンスとして送信することであるように思われました。「Alt」および「Add」キーダウンイベントを送信し、続いてAltキーORを使用した4文字のUnicodeシーケンスのキーダウンおよびアップイベントを送信し、最後に「Add」および「Alt」キーアップイベントを送信するコードを作成しました。私のC#テストアプリで。私はKeyPreviewを使用していますが、確かにすべてのイベントが発生していますが、ビープ音だけが鳴り、キャラクターは鳴りません。キーストロークを手動で入力した場合と同じ情報を取得しました。

このようにSendInputを使用することは可能ですか?データを調べるためにフックを使用したことはありませんが、SendInputイベントに何らかの「挿入された」フラグが付加されていることを示す投稿を見ました。これにより、シーケンスが失敗する可能性がありますか?

このデモコードはキーイベントを正常に送信しますが、Unicode文字を生成することを目的とした一連のキーイベントは失敗します。

    private const uint KEYEVENTF_KEYDOWN = 0x0000;
    private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
    private const uint KEYEVENTF_KEYUP = 0x0002;

    private const int INPUT_KEYBOARD = 1;

    [DllImport ("user32.dll", SetLastError = false)]
    static extern IntPtr GetMessageExtraInfo ();

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

    [StructLayout (LayoutKind.Sequential, Size = 24)]
    private struct KEYBDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout (LayoutKind.Explicit)]
    private struct INPUT
    {
        [FieldOffset (0)]
        public int type;
        [FieldOffset (4)]
        public KEYBDINPUT ki;
    }

    private void PressKey (Keys k)
    {
        PressKeyDown (k);
        PressKeyUp (k);
    }

    private void PressKeyDown (Keys k)
    {
        INPUT input = new INPUT ();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (byte)k;
        input.ki.wScan = 0;
        input.ki.time = 0;

        uint flags = KEYEVENTF_KEYDOWN;
        if ((33 <= (byte)k && (byte)k <= 46) || (91 <= (byte)k) && (byte)k <= 93)
            flags |= KEYEVENTF_EXTENDEDKEY;
        input.ki.dwFlags = flags;

        input.ki.dwExtraInfo = GetMessageExtraInfo ();

        Output ("Sending key down {0}. Flags:{1}", k, flags);

        INPUT[] inputs = new INPUT[] { input };
        uint result = SendInput ((uint)inputs.Length, inputs, Marshal.SizeOf (typeof (INPUT)));

        if ((uint)inputs.Length != result)
            MessageBox.Show ("PressKeyDown result = " + Marshal.GetLastWin32Error ());
    }

    private void PressKeyUp (Keys k)
    {
        INPUT input = new INPUT ();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (byte)k;
        input.ki.wScan = 0;
        input.ki.time = 0;

        uint flags = KEYEVENTF_KEYUP;
        if ((33 <= (byte)k && (byte)k <= 46) || (91 <= (byte)k) && (byte)k <= 93)
            flags |= KEYEVENTF_EXTENDEDKEY;
        input.ki.dwFlags = flags;

        input.ki.dwExtraInfo = GetMessageExtraInfo ();

        Output ("Sending key up {0}", k);

        INPUT[] inputs = new INPUT[] { input };
        uint result = SendInput ((uint)inputs.Length, inputs, Marshal.SizeOf (typeof (INPUT)));

        if ((uint)inputs.Length != result)
            MessageBox.Show ("PressKeyUp result = " + Marshal.GetLastWin32Error ());
    }

    private void TestSend ()
    {
        System.Threading.Thread.CurrentThread.Join (1000);

        Keys k = Keys.Menu;
        PressKeyDown (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.Add;
        k |= Keys.Alt;
        PressKeyDown (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad0;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad0;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.E;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad5;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        PressKeyUp (Keys.Add);
        PressKeyUp (Keys.Menu);
    }
4

3 に答える 3

4
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Simulate
{
    public class Simulate
    {
        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] input, Int32 sizeOfInputStructure);

        [StructLayout(LayoutKind.Sequential, Size = 24)]
        struct KEYBDINPUT
        {
            public UInt16 Vk;
            public UInt16 Scan;
            public UInt32 Flags;
            public UInt32 Time;
            public UInt32 ExtraInfo;
        }

        [StructLayout(LayoutKind.Explicit)]
        private struct INPUT
        {
            [FieldOffset(0)]
            public int Type;
            [FieldOffset(4)]
            public KEYBDINPUT ki;
        } 

        public static void TextInput(string text)
        {
            char[] chars = text.ToCharArray();

            for (int i = 0; i < chars.Length; i++)
            {
                UInt16 unicode = chars[i];

                INPUT down = new INPUT();
                down.Type = 1; //INPUT_KEYBOARD
                down.ki.Vk = 0;
                down.ki.Scan = unicode;
                down.ki.Time = 0;
                down.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
                down.ki.ExtraInfo = 0;

                INPUT up = new INPUT();
                up.Type = 1; //INPUT_KEYBOARD
                up.ki.Vk = 0;
                up.ki.Scan = unicode;
                up.ki.Time = 0;
                up.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
                up.ki.ExtraInfo = 0;

                INPUT[] input = new INPUT[2];
                input[0] = down;
                input[1] = up;
                SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
            }
        }
    }
}

// Call the API :
Simulate.TextInput("AbCçDeFgĞhİiJkLmNoÖpQrSşTuÜvXyZ - äÄß_0123456789");
于 2011-12-12T01:18:50.277 に答える
1

Altキーを押しながら、テンキーで4桁のUnicodeコードポイントを入力すると、それらを生成できます。å=Alt+ 0229、ñ=Alt+0241。Charmap.exeアプレットを使用して他のコードを検索します。

于 2010-02-08T21:54:51.970 に答える
0

どうやら、Unicode文字を表すための一連のキー押下の処理は、SendInputを介してアクセスできないレベルで実行されます。コードを変更して、dwFlagsにUnicodeフラグを設定し、wScanデータパラメーターにUnicode値を設定しました。いくつかのヨーロッパとアジアの言語でテストした後、これが複数のキーストロークの方法と同じ結果を生み出すことを私はなんとか確信しました。

于 2010-02-23T13:45:03.427 に答える