通过user32.dll中的SendInput发送密钥

我正在使用此板作为演示目的的键盘。

无论如何,使长话短说一切正常,除了极less数情况下。 我用位于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(); } 

这里是我在网上find的结构,这些方法使用,也是关键代码:( 注意它看起来像很多代码,因为有很多关键代码在一个枚举)

  /// <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 …

您不设置标志和扫描字段,具体取决于所需的按键,您需要正确设置这些以使操作系统正确识别这些键。

你可能会考虑使用input模拟器库,因为它已经做了你想要的,你不必重新创build轮子。 只要确保浏览论坛,因为作者在2009年放弃了这个项目,所以需要设置一些好的补丁。这是一个很好的图书馆。

将键盘input发送到窗口的另一种方法是使用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))); }