web-dev-qa-db-ja.com

user32.dllのSendInputを介してキーを送信する

this board をデモ用のキーボードとして使用しています。

とにかく、長い話を短くすることは、ごくわずかな場合を除いて、すべてうまくいきます。 user32.dllにあるSendInput関数でキーストロークを送信します。

だから私のプログラムは次のようになります:

_static void Main(string[] args)
{
    Console.Write("Press enter an on the next secont the key combination shift+end will be send");
    Console.Read();

    Thread.Sleep(1000);

    SendKeyDown(KeyCode.SHIFT);
    SendKeyPress(KeyCode.END);
    SendKeyUp(KeyCode.SHIFT);

    Console.Read(); 
    Console.Read();
}

[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);

/// <summary>
/// simulate key press
/// </summary>
/// <param name="keyCode"></param>
public static void SendKeyPress(KeyCode keyCode)
{
    INPUT input = new INPUT {
        Type = 1
    };
    input.Data.Keyboard = new KEYBDINPUT() {
        Vk = (ushort)keyCode,
        Scan = 0,
        Flags = 0,
        Time = 0,
        ExtraInfo = IntPtr.Zero,
    };

    INPUT input2 = new INPUT {
        Type = 1
    };
    input2.Data.Keyboard = new KEYBDINPUT() {
        Vk = (ushort)keyCode,
        Scan = 0,
        Flags = 2,
        Time = 0,
        ExtraInfo = IntPtr.Zero
    };
    INPUT[] inputs = new INPUT[] { input, input2 };
    if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
        throw new Exception();            
}

/// <summary>
/// Send a key down and hold it down until sendkeyup method is called
/// </summary>
/// <param name="keyCode"></param>
public static void SendKeyDown(KeyCode keyCode)
{
    INPUT input = new INPUT{
        Type = 1
    };
    input.Data.Keyboard = new KEYBDINPUT();
    input.Data.Keyboard.Vk = (ushort)keyCode;
    input.Data.Keyboard.Scan = 0;
    input.Data.Keyboard.Flags = 0;
    input.Data.Keyboard.Time = 0;
    input.Data.Keyboard.ExtraInfo = IntPtr.Zero;
    INPUT[] inputs = new INPUT[] { input };
    if (SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
    {
        throw new Exception();
    }
}

/// <summary>
/// Release a key that is being hold down
/// </summary>
/// <param name="keyCode"></param>
public static void SendKeyUp(KeyCode keyCode)
{
    INPUT input = new INPUT {
        Type = 1
    };
    input.Data.Keyboard = new KEYBDINPUT();
    input.Data.Keyboard.Vk = (ushort)keyCode;
    input.Data.Keyboard.Scan = 0;
    input.Data.Keyboard.Flags = 2;
    input.Data.Keyboard.Time = 0;
    input.Data.Keyboard.ExtraInfo = IntPtr.Zero;
    INPUT[] inputs = new INPUT[] { input };
    if (SendInput(1, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
        throw new Exception();

}
_

そして、これらのメソッドが使用するオンラインで見つけた構造体とキーコードは次のとおりです:

_    /// <summary>
    /// http://msdn.Microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct INPUT
    {
        public uint Type;
        public MOUSEKEYBDHARDWAREINPUT Data;
    }

    /// <summary>
    /// http://social.msdn.Microsoft.com/Forums/en/csharplanguage/thread/f0e82d6e-4999-4d22-b3d3-32b25f61fb2a
    /// </summary>
    [StructLayout(LayoutKind.Explicit)]
    internal struct MOUSEKEYBDHARDWAREINPUT
    {
        [FieldOffset(0)]
        public HARDWAREINPUT Hardware;
        [FieldOffset(0)]
        public KEYBDINPUT Keyboard;
        [FieldOffset(0)]
        public MOUSEINPUT Mouse;
    }

    /// <summary>
    /// http://msdn.Microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct HARDWAREINPUT
    {
        public uint Msg;
        public ushort ParamL;
        public ushort ParamH;
    }

    /// <summary>
    /// http://msdn.Microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct KEYBDINPUT
    {
        public ushort Vk;
        public ushort Scan;
        public uint Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    /// <summary>
    /// http://social.msdn.Microsoft.com/forums/en-US/netfxbcl/thread/2abc6be8-c593-4686-93d2-89785232dacd
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    internal struct MOUSEINPUT
    {
        public int X;
        public int Y;
        public uint MouseData;
        public uint Flags;
        public uint Time;
        public IntPtr ExtraInfo;
    }

    public enum KeyCode : ushort
    {
        #region Media

        /// <summary>
        /// Next track if a song is playing
        /// </summary>
        MEDIA_NEXT_TRACK = 0xb0,

        /// <summary>
        /// Play pause
        /// </summary>
        MEDIA_PLAY_PAUSE = 0xb3,

        /// <summary>
        /// Previous track
        /// </summary>
        MEDIA_PREV_TRACK = 0xb1,

        /// <summary>
        /// Stop
        /// </summary>
        MEDIA_STOP = 0xb2,

        #endregion

        #region math

        /// <summary>Key "+"</summary>
        ADD = 0x6b,
        /// <summary>
        /// "*" key
        /// </summary>
        MULTIPLY = 0x6a,

        /// <summary>
        /// "/" key
        /// </summary>
        DIVIDE = 0x6f,

        /// <summary>
        /// Subtract key "-"
        /// </summary>
        SUBTRACT = 0x6d,

        #endregion

        #region Browser
        /// <summary>
        /// Go Back
        /// </summary>
        BROWSER_BACK = 0xa6,
        /// <summary>
        /// Favorites
        /// </summary>
        BROWSER_FAVORITES = 0xab,
        /// <summary>
        /// Forward
        /// </summary>
        BROWSER_FORWARD = 0xa7,
        /// <summary>
        /// Home
        /// </summary>
        BROWSER_HOME = 0xac,
        /// <summary>
        /// Refresh
        /// </summary>
        BROWSER_REFRESH = 0xa8,
        /// <summary>
        /// browser search
        /// </summary>
        BROWSER_SEARCH = 170,
        /// <summary>
        /// Stop
        /// </summary>
        BROWSER_STOP = 0xa9,
        #endregion

        #region Numpad numbers
        /// <summary>
        /// 
        /// </summary>
        NUMPAD0 = 0x60,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD1 = 0x61,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD2 = 0x62,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD3 = 0x63,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD4 = 100,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD5 = 0x65,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD6 = 0x66,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD7 = 0x67,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD8 = 0x68,
        /// <summary>
        /// 
        /// </summary>
        NUMPAD9 = 0x69,

        #endregion

        #region Fkeys
        /// <summary>
        /// F1
        /// </summary>
        F1 = 0x70,
        /// <summary>
        /// F10
        /// </summary>
        F10 = 0x79,
        /// <summary>
        /// 
        /// </summary>
        F11 = 0x7a,
        /// <summary>
        /// 
        /// </summary>
        F12 = 0x7b,
        /// <summary>
        /// 
        /// </summary>
        F13 = 0x7c,
        /// <summary>
        /// 
        /// </summary>
        F14 = 0x7d,
        /// <summary>
        /// 
        /// </summary>
        F15 = 0x7e,
        /// <summary>
        /// 
        /// </summary>
        F16 = 0x7f,
        /// <summary>
        /// 
        /// </summary>
        F17 = 0x80,
        /// <summary>
        /// 
        /// </summary>
        F18 = 0x81,
        /// <summary>
        /// 
        /// </summary>
        F19 = 130,
        /// <summary>
        /// 
        /// </summary>
        F2 = 0x71,
        /// <summary>
        /// 
        /// </summary>
        F20 = 0x83,
        /// <summary>
        /// 
        /// </summary>
        F21 = 0x84,
        /// <summary>
        /// 
        /// </summary>
        F22 = 0x85,
        /// <summary>
        /// 
        /// </summary>
        F23 = 0x86,
        /// <summary>
        /// 
        /// </summary>
        F24 = 0x87,
        /// <summary>
        /// 
        /// </summary>
        F3 = 0x72,
        /// <summary>
        /// 
        /// </summary>
        F4 = 0x73,
        /// <summary>
        /// 
        /// </summary>
        F5 = 0x74,
        /// <summary>
        /// 
        /// </summary>
        F6 = 0x75,
        /// <summary>
        /// 
        /// </summary>
        F7 = 0x76,
        /// <summary>
        /// 
        /// </summary>
        F8 = 0x77,
        /// <summary>
        /// 
        /// </summary>
        F9 = 120,

        #endregion

        #region Other
        /// <summary>
        /// 
        /// </summary>
        OEM_1 = 0xba,
        /// <summary>
        /// 
        /// </summary>
        OEM_102 = 0xe2,
        /// <summary>
        /// 
        /// </summary>
        OEM_2 = 0xbf,
        /// <summary>
        /// 
        /// </summary>
        OEM_3 = 0xc0,
        /// <summary>
        /// 
        /// </summary>
        OEM_4 = 0xdb,
        /// <summary>
        /// 
        /// </summary>
        OEM_5 = 220,
        /// <summary>
        /// 
        /// </summary>
        OEM_6 = 0xdd,
        /// <summary>
        /// 
        /// </summary>
        OEM_7 = 0xde,
        /// <summary>
        /// 
        /// </summary>
        OEM_8 = 0xdf,
        /// <summary>
        /// 
        /// </summary>
        OEM_CLEAR = 0xfe,
        /// <summary>
        /// 
        /// </summary>
        OEM_COMMA = 0xbc,
        /// <summary>
        /// 
        /// </summary>
        OEM_MINUS = 0xbd,
        /// <summary>
        /// 
        /// </summary>
        OEM_PERIOD = 190,
        /// <summary>
        /// 
        /// </summary>
        OEM_PLUS = 0xbb,

        #endregion

        #region KEYS

        /// <summary>
        /// 
        /// </summary>
        KEY_0 = 0x30,
        /// <summary>
        /// 
        /// </summary>
        KEY_1 = 0x31,
        /// <summary>
        /// 
        /// </summary>
        KEY_2 = 50,
        /// <summary>
        /// 
        /// </summary>
        KEY_3 = 0x33,
        /// <summary>
        /// 
        /// </summary>
        KEY_4 = 0x34,
        /// <summary>
        /// 
        /// </summary>
        KEY_5 = 0x35,
        /// <summary>
        /// 
        /// </summary>
        KEY_6 = 0x36,
        /// <summary>
        /// 
        /// </summary>
        KEY_7 = 0x37,
        /// <summary>
        /// 
        /// </summary>
        KEY_8 = 0x38,
        /// <summary>
        /// 
        /// </summary>
        KEY_9 = 0x39,
        /// <summary>
        /// 
        /// </summary>
        KEY_A = 0x41,
        /// <summary>
        /// 
        /// </summary>
        KEY_B = 0x42,
        /// <summary>
        /// 
        /// </summary>
        KEY_C = 0x43,
        /// <summary>
        /// 
        /// </summary>
        KEY_D = 0x44,
        /// <summary>
        /// 
        /// </summary>
        KEY_E = 0x45,
        /// <summary>
        /// 
        /// </summary>
        KEY_F = 70,
        /// <summary>
        /// 
        /// </summary>
        KEY_G = 0x47,
        /// <summary>
        /// 
        /// </summary>
        KEY_H = 0x48,
        /// <summary>
        /// 
        /// </summary>
        KEY_I = 0x49,
        /// <summary>
        /// 
        /// </summary>
        KEY_J = 0x4a,
        /// <summary>
        /// 
        /// </summary>
        KEY_K = 0x4b,
        /// <summary>
        /// 
        /// </summary>
        KEY_L = 0x4c,
        /// <summary>
        /// 
        /// </summary>
        KEY_M = 0x4d,
        /// <summary>
        /// 
        /// </summary>
        KEY_N = 0x4e,
        /// <summary>
        /// 
        /// </summary>
        KEY_O = 0x4f,
        /// <summary>
        /// 
        /// </summary>
        KEY_P = 80,
        /// <summary>
        /// 
        /// </summary>
        KEY_Q = 0x51,
        /// <summary>
        /// 
        /// </summary>
        KEY_R = 0x52,
        /// <summary>
        /// 
        /// </summary>
        KEY_S = 0x53,
        /// <summary>
        /// 
        /// </summary>
        KEY_T = 0x54,
        /// <summary>
        /// 
        /// </summary>
        KEY_U = 0x55,
        /// <summary>
        /// 
        /// </summary>
        KEY_V = 0x56,
        /// <summary>
        /// 
        /// </summary>
        KEY_W = 0x57,
        /// <summary>
        /// 
        /// </summary>
        KEY_X = 0x58,
        /// <summary>
        /// 
        /// </summary>
        KEY_Y = 0x59,
        /// <summary>
        /// 
        /// </summary>
        KEY_Z = 90,

        #endregion

        #region volume
        /// <summary>
        /// Decrese volume
        /// </summary>
        VOLUME_DOWN = 0xae,

        /// <summary>
        /// Mute volume
        /// </summary>
        VOLUME_MUTE = 0xad,

        /// <summary>
        /// Increase volue
        /// </summary>
        VOLUME_UP = 0xaf,

        #endregion


        /// <summary>
        /// Take snapshot of the screen and place it on the clipboard
        /// </summary>
        SNAPSHOT = 0x2c,

        /// <summary>Send right click from keyboard "key that is 2 keys to the right of space bar"</summary>
        RightClick = 0x5d,

        /// <summary>
        /// Go Back or delete
        /// </summary>
        BACKSPACE = 8,

        /// <summary>
        /// Control + Break "When debuging if you step into an infinite loop this will stop debug"
        /// </summary>
        CANCEL = 3,
        /// <summary>
        /// Caps lock key to send cappital letters
        /// </summary>
        CAPS_LOCK = 20,
        /// <summary>
        /// Ctlr key
        /// </summary>
        CONTROL = 0x11,

        /// <summary>
        /// Alt key
        /// </summary>
        ALT = 18,

        /// <summary>
        /// "." key
        /// </summary>
        DECIMAL = 110,

        /// <summary>
        /// Delete Key
        /// </summary>
        DELETE = 0x2e,


        /// <summary>
        /// Arrow down key
        /// </summary>
        DOWN = 40,

        /// <summary>
        /// End key
        /// </summary>
        END = 0x23,

        /// <summary>
        /// Escape key
        /// </summary>
        ESC = 0x1b,

        /// <summary>
        /// Home key
        /// </summary>
        HOME = 0x24,

        /// <summary>
        /// Insert key
        /// </summary>
        INSERT = 0x2d,

        /// <summary>
        /// Open my computer
        /// </summary>
        LAUNCH_APP1 = 0xb6,
        /// <summary>
        /// Open calculator
        /// </summary>
        LAUNCH_APP2 = 0xb7,

        /// <summary>
        /// Open default email in my case Outlook
        /// </summary>
        LAUNCH_MAIL = 180,

        /// <summary>
        /// Opend default media player (iTunes, winmediaplayer, etc)
        /// </summary>
        LAUNCH_MEDIA_SELECT = 0xb5,

        /// <summary>
        /// Left control
        /// </summary>
        LCONTROL = 0xa2,

        /// <summary>
        /// Left arrow
        /// </summary>
        LEFT = 0x25,

        /// <summary>
        /// Left shift
        /// </summary>
        LSHIFT = 160,

        /// <summary>
        /// left windows key
        /// </summary>
        LWIN = 0x5b,


        /// <summary>
        /// Next "page down"
        /// </summary>
        PAGEDOWN = 0x22,

        /// <summary>
        /// Num lock to enable typing numbers
        /// </summary>
        NUMLOCK = 0x90,

        /// <summary>
        /// Page up key
        /// </summary>
        PAGE_UP = 0x21,

        /// <summary>
        /// Right control
        /// </summary>
        RCONTROL = 0xa3,

        /// <summary>
        /// Return key
        /// </summary>
        ENTER = 13,

        /// <summary>
        /// Right arrow key
        /// </summary>
        RIGHT = 0x27,

        /// <summary>
        /// Right shift
        /// </summary>
        RSHIFT = 0xa1,

        /// <summary>
        /// Right windows key
        /// </summary>
        RWIN = 0x5c,

        /// <summary>
        /// Shift key
        /// </summary>
        SHIFT = 0x10,

        /// <summary>
        /// Space back key
        /// </summary>
        SPACE_BAR = 0x20,

        /// <summary>
        /// Tab key
        /// </summary>
        TAB = 9,

        /// <summary>
        /// Up arrow key
        /// </summary>
        UP = 0x26,

    }
_

だから私の質問はなぜそのキーの組み合わせを送信しても、実際のキーボードで実行したときと同じ結果が得られないのはなぜですか?物事の98%が機能します。たとえば、私は次のことができます:

_    SendKeyDown(KeyCode.SHIFT);
    SendKeyPress(KeyCode.KEY_A );
    SendKeyUp(KeyCode.SHIFT);
_

そして、それは首都Aを送信します.

別のライブラリを使用する必要がありますか?

このアプローチが好きな理由は、ユーザーがキーの組み合わせを送信するかどうかを事前に知らないためですたとえば、Windowsフォームの場合:

System.Windows.Forms.SendKeys.SendWait("+{end}");は、shift + endを送信しますが、ユーザーはshiftを送信したいだけかもしれません...

26
Tono Nam

必要なキーストロークに応じて、フラグとスキャンフィールドを設定していません。OSにキーを正しく認識させるには、これらを正しく設定する必要があります。

Input Simulator ライブラリを使用することを検討してください。これは既に必要な処理を実行しており、ホイールを再作成する必要がないためです。著者が2009年にプロジェクトを放棄したため、設定する必要のあるいくつかの良いパッチがあるので、フォーラムを必ず確認してください。それにもかかわらず、良いライブラリです。

20
Kevin Cook

キーボード入力をウィンドウに送信する別の方法(私はこれをUIテストに使用します)は、 [〜#〜] keybdinput [〜#〜] でUnicodeの代替を使用することです。仮想キー:

public static void SendString(string inputStr)
{
    var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
    WinAPI.SetForegroundWindow(hWnd);           
    List<WinAPI.INPUT> keyList = new List<WinAPI.INPUT>();
    foreach (short c in inputStr)
    {
        switch (c)
        {
            case 8: // Translate \t to VK_TAB
                {
                    WinAPI.INPUT keyDown = new WinAPI.INPUT();
                    keyDown.type = 1; //Keyboard
                    keyDown.union.keyboardInput.wVk = (short)WinAPI.WindowsVirtualKey.VK_TAB;
                    keyDown.union.keyboardInput.dwFlags = 0;
                    keyDown.union.keyboardInput.wScan = 0; //use VirtualKey
                    keyList.Add(keyDown);
                    WinAPI.INPUT keyUp = new WinAPI.INPUT();
                    keyUp.type = 1; //Keyboard
                    keyUp.union.keyboardInput.wVk = (short)WinAPI.WindowsVirtualKey.VK_TAB;
                    keyUp.union.keyboardInput.dwFlags = 0x0002;
                    keyUp.union.keyboardInput.wScan = 0; //use VirtualKey
                    keyList.Add(keyUp);
                }
                break;
            case 10: // Translate \n to VK_RETURN
                {
                    WinAPI.INPUT keyDown = new WinAPI.INPUT();
                    keyDown.type = 1; //Keyboard
                    keyDown.union.keyboardInput.wVk = (short)WinAPI.WindowsVirtualKey.VK_RETURN;
                    keyDown.union.keyboardInput.dwFlags = 0;
                    keyDown.union.keyboardInput.wScan = 0; //use VirtualKey
                    keyList.Add(keyDown);
                    WinAPI.INPUT keyUp = new WinAPI.INPUT();
                    keyUp.type = 1; //Keyboard
                    keyUp.union.keyboardInput.wVk = (short)WinAPI.WindowsVirtualKey.VK_RETURN;
                    keyUp.union.keyboardInput.dwFlags = 0x0002; 
                    keyUp.union.keyboardInput.wScan = 0; //use VirtualKey
                    keyList.Add(keyUp);
                }
                break;                  
            default:
                {
                    WinAPI.INPUT keyDown = new WinAPI.INPUT();
                    keyDown.type = 1; //Keyboard
                    keyDown.union.keyboardInput.wVk = 0; //Use unicode
                    keyDown.union.keyboardInput.dwFlags = 0x0004; //Unicode Key Down
                    keyDown.union.keyboardInput.wScan = c;
                    keyList.Add(keyDown);
                    WinAPI.INPUT keyUp = new WinAPI.INPUT();
                    keyUp.type = 1; //Keyboard
                    keyUp.union.keyboardInput.wVk = 0; //Use unicode
                    keyUp.union.keyboardInput.dwFlags = 0x0004 | 0x0002; //Unicode Key Up
                    keyUp.union.keyboardInput.wScan = c;
                    keyList.Add(keyUp);
                }
                break;
        }
    }
    WinAPI.SendInput((uint)keyList.Count, keyList.ToArray(), Marshal.SizeOf(typeof(WinAPI.INPUT)));             
}
1
user3902302