Отправить ключи через SendInput в user32.dll
я используюэта доска в качестве клавиатуры для демонстрационных целей.
В любом случае, если коротко, все работает хорошо, за исключением очень немногих случаев. Я посылаю нажатия клавиш сSendInput функция находится в user32.dll.
Итак, моя программа выглядит так:
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);
///
/// simulate key press
///
///
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();
}
///
/// Send a key down and hold it down until sendkeyup method is called
///
///
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();
}
}
///
/// Release a key that is being hold down
///
///
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();
}
И вот структуры, которые я нашел в Интернете, которые используют эти методы, а также коды клавиш:(обратите внимание, что это выглядит как много кода и потому, что в Enum много кодов клавиш)
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646270(v=vs.85).aspx
///
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT
{
public uint Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
///
/// http://social.msdn.microsoft.com/Forums/en/csharplanguage/thread/f0e82d6e-4999-4d22-b3d3-32b25f61fb2a
///
[StructLayout(LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public HARDWAREINPUT Hardware;
[FieldOffset(0)]
public KEYBDINPUT Keyboard;
[FieldOffset(0)]
public MOUSEINPUT Mouse;
}
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
///
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
public uint Msg;
public ushort ParamL;
public ushort ParamH;
}
///
/// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
///
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
public ushort Vk;
public ushort Scan;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
///
/// http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/2abc6be8-c593-4686-93d2-89785232dacd
///
[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
///
/// Next track if a song is playing
///
MEDIA_NEXT_TRACK = 0xb0,
///
/// Play pause
///
MEDIA_PLAY_PAUSE = 0xb3,
///
/// Previous track
///
MEDIA_PREV_TRACK = 0xb1,
///
/// Stop
///
MEDIA_STOP = 0xb2,
#endregion
#region math
/// Key "+"
ADD = 0x6b,
///
/// "*" key
///
MULTIPLY = 0x6a,
///
/// "/" key
///
DIVIDE = 0x6f,
///
/// Subtract key "-"
///
SUBTRACT = 0x6d,
#endregion
#region Browser
///
/// Go Back
///
BROWSER_BACK = 0xa6,
///
/// Favorites
///
BROWSER_FAVORITES = 0xab,
///
/// Forward
///
BROWSER_FORWARD = 0xa7,
///
/// Home
///
BROWSER_HOME = 0xac,
///
/// Refresh
///
BROWSER_REFRESH = 0xa8,
///
/// browser search
///
BROWSER_SEARCH = 170,
///
/// Stop
///
BROWSER_STOP = 0xa9,
#endregion
#region Numpad numbers
///
///
///
NUMPAD0 = 0x60,
///
///
///
NUMPAD1 = 0x61,
///
///
///
NUMPAD2 = 0x62,
///
///
///
NUMPAD3 = 0x63,
///
///
///
NUMPAD4 = 100,
///
///
///
NUMPAD5 = 0x65,
///
///
///
NUMPAD6 = 0x66,
///
///
///
NUMPAD7 = 0x67,
///
///
///
NUMPAD8 = 0x68,
///
///
///
NUMPAD9 = 0x69,
#endregion
#region Fkeys
///
/// F1
///
F1 = 0x70,
///
/// F10
///
F10 = 0x79,
///
///
///
F11 = 0x7a,
///
///
///
F12 = 0x7b,
///
///
///
F13 = 0x7c,
///
///
///
F14 = 0x7d,
///
///
///
F15 = 0x7e,
///
///
///
F16 = 0x7f,
///
///
///
F17 = 0x80,
///
///
///
F18 = 0x81,
///
///
///
F19 = 130,
///
///
///
F2 = 0x71,
///
///
///
F20 = 0x83,
///
///
///
F21 = 0x84,
///
///
///
F22 = 0x85,
///
///
///
F23 = 0x86,
///
///
///
F24 = 0x87,
///
///
///
F3 = 0x72,
///
///
///
F4 = 0x73,
///
///
///
F5 = 0x74,
///
///
///
F6 = 0x75,
///
///
///
F7 = 0x76,
///
///
///
F8 = 0x77,
///
///
///
F9 = 120,
#endregion
#region Other
///
///
///
OEM_1 = 0xba,
///
///
///
OEM_102 = 0xe2,
///
///
///
OEM_2 = 0xbf,
///
///
///
OEM_3 = 0xc0,
///
///
///
OEM_4 = 0xdb,
///
///
///
OEM_5 = 220,
///
///
///
OEM_6 = 0xdd,
///
///
///
OEM_7 = 0xde,
///
///
///
OEM_8 = 0xdf,
///
///
///
OEM_CLEAR = 0xfe,
///
///
///
OEM_COMMA = 0xbc,
///
///
///
OEM_MINUS = 0xbd,
///
///
///
OEM_PERIOD = 190,
///
///
///
OEM_PLUS = 0xbb,
#endregion
#region KEYS
///
///
///
KEY_0 = 0x30,
///
///
///
KEY_1 = 0x31,
///
///
///
KEY_2 = 50,
///
///
///
KEY_3 = 0x33,
///
///
///
KEY_4 = 0x34,
///
///
///
KEY_5 = 0x35,
///
///
///
KEY_6 = 0x36,
///
///
///
KEY_7 = 0x37,
///
///
///
KEY_8 = 0x38,
///
///
///
KEY_9 = 0x39,
///
///
///
KEY_A = 0x41,
///
///
///
KEY_B = 0x42,
///
///
///
KEY_C = 0x43,
///
///
///
KEY_D = 0x44,
///
///
///
KEY_E = 0x45,
///
///
///
KEY_F = 70,
///
///
///
KEY_G = 0x47,
///
///
///
KEY_H = 0x48,
///
///
///
KEY_I = 0x49,
///
///
///
KEY_J = 0x4a,
///
///
///
KEY_K = 0x4b,
///
///
///
KEY_L = 0x4c,
///
///
///
KEY_M = 0x4d,
///
///
///
KEY_N = 0x4e,
///
///
///
KEY_O = 0x4f,
///
///
///
KEY_P = 80,
///
///
///
KEY_Q = 0x51,
///
///
///
KEY_R = 0x52,
///
///
///
KEY_S = 0x53,
///
///
///
KEY_T = 0x54,
///
///
///
KEY_U = 0x55,
///
///
///
KEY_V = 0x56,
///
///
///
KEY_W = 0x57,
///
///
///
KEY_X = 0x58,
///
///
///
KEY_Y = 0x59,
///
///
///
KEY_Z = 90,
#endregion
#region volume
///
/// Decrese volume
///
VOLUME_DOWN = 0xae,
///
/// Mute volume
///
VOLUME_MUTE = 0xad,
///
/// Increase volue
///
VOLUME_UP = 0xaf,
#endregion
///
/// Take snapshot of the screen and place it on the clipboard
///
SNAPSHOT = 0x2c,
/// Send right click from keyboard "key that is 2 keys to the right of space bar"
RightClick = 0x5d,
///
/// Go Back or delete
///
BACKSPACE = 8,
///
/// Control + Break "When debuging if you step into an infinite loop this will stop debug"
///
CANCEL = 3,
///
/// Caps lock key to send cappital letters
///
CAPS_LOCK = 20,
///
/// Ctlr key
///
CONTROL = 0x11,
///
/// Alt key
///
ALT = 18,
///
/// "." key
///
DECIMAL = 110,
///
/// Delete Key
///
DELETE = 0x2e,
///
/// Arrow down key
///
DOWN = 40,
///
/// End key
///
END = 0x23,
///
/// Escape key
///
ESC = 0x1b,
///
/// Home key
///
HOME = 0x24,
///
/// Insert key
///
INSERT = 0x2d,
///
/// Open my computer
///
LAUNCH_APP1 = 0xb6,
///
/// Open calculator
///
LAUNCH_APP2 = 0xb7,
///
/// Open default email in my case outlook
///
LAUNCH_MAIL = 180,
///
/// Opend default media player (itunes, winmediaplayer, etc)
///
LAUNCH_MEDIA_SELECT = 0xb5,
///
/// Left control
///
LCONTROL = 0xa2,
///
/// Left arrow
///
LEFT = 0x25,
///
/// Left shift
///
LSHIFT = 160,
///
/// left windows key
///
LWIN = 0x5b,
///
/// Next "page down"
///
PAGEDOWN = 0x22,
///
/// Num lock to enable typing numbers
///
NUMLOCK = 0x90,
///
/// Page up key
///
PAGE_UP = 0x21,
///
/// Right control
///
RCONTROL = 0xa3,
///
/// Return key
///
ENTER = 13,
///
/// Right arrow key
///
RIGHT = 0x27,
///
/// Right shift
///
RSHIFT = 0xa1,
///
/// Right windows key
///
RWIN = 0x5c,
///
/// Shift key
///
SHIFT = 0x10,
///
/// Space back key
///
SPACE_BAR = 0x20,
///
/// Tab key
///
TAB = 9,
///
/// Up arrow key
///
UP = 0x26,
}
Итак, теперь мой вопрос почему, когда я посылаю эту комбинацию клавиш, я не получаю такие же результаты, как когда я делаю это на реальной клавиатуре? 98% вещей работают. Например, я могу сделать:
SendKeyDown(KeyCode.SHIFT);
SendKeyPress(KeyCode.KEY_A );
SendKeyUp(KeyCode.SHIFT);
И это отправит столицу А.
Должен ли я использовать другую библиотеку?
Причина, по которой мне нравится такой подход, заключается в том, что я не знаю заранее, отправит ли пользователь комбинацию клавиш Например в окнах формы Если я делаю:
System.Windows.Forms.SendKeys.SendWait("+{end}");
который отправит shift + end, но, возможно, пользователь просто хочет отправить shift ...