将密钥发送到 DirectX 游戏
Sending keys to a DirectX Game
我在发送密钥时遇到了一点麻烦。好像什么时候我想发送密钥都行不通。
我正在考虑 sending alphabetic characters 例如 T 从示例中调出聊天,但是如果我将它写入枚举,则无论何时使用它们都不会发生任何事情。有什么想法吗?
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// Virtual Keys
/// </summary>
public enum VirtualKeyStates : int
{
VK_LBUTTON = 0x01,
VK_RBUTTON = 0x02,
VK_CANCEL = 0x03,
VK_MBUTTON = 0x04,
//
VK_XBUTTON1 = 0x05,
VK_XBUTTON2 = 0x06,
//
VK_BACK = 0x08,
VK_TAB = 0x09,
//
VK_CLEAR = 0x0C,
VK_RETURN = 0x0D,
//
VK_SHIFT = 0x10,
VK_CONTROL = 0x11,
VK_MENU = 0x12,
VK_PAUSE = 0x13,
VK_CAPITAL = 0x14,
//
VK_KANA = 0x15,
VK_HANGEUL = 0x15, /* old name - should be here for compatibility */
VK_HANGUL = 0x15,
VK_JUNJA = 0x17,
VK_FINAL = 0x18,
VK_HANJA = 0x19,
VK_KANJI = 0x19,
//
VK_ESCAPE = 0x1B,
//
VK_CONVERT = 0x1C,
VK_NONCONVERT = 0x1D,
VK_ACCEPT = 0x1E,
VK_MODECHANGE = 0x1F,
//
VK_SPACE = 0x20,
VK_PRIOR = 0x21,
VK_NEXT = 0x22,
VK_END = 0x23,
VK_HOME = 0x24,
VK_LEFT = 0x25,
VK_UP = 0x26,
VK_RIGHT = 0x27,
VK_DOWN = 0x28,
VK_SELECT = 0x29,
VK_PRINT = 0x2A,
VK_EXECUTE = 0x2B,
VK_SNAPSHOT = 0x2C,
VK_INSERT = 0x2D,
VK_DELETE = 0x2E,
VK_HELP = 0x2F,
//
VK_LWIN = 0x5B,
VK_RWIN = 0x5C,
VK_APPS = 0x5D,
//
VK_SLEEP = 0x5F,
//
VK_NUMPAD0 = 0x60,
VK_NUMPAD1 = 0x61,
VK_NUMPAD2 = 0x62,
VK_NUMPAD3 = 0x63,
VK_NUMPAD4 = 0x64,
VK_NUMPAD5 = 0x65,
VK_NUMPAD6 = 0x66,
VK_NUMPAD7 = 0x67,
VK_NUMPAD8 = 0x68,
VK_NUMPAD9 = 0x69,
VK_MULTIPLY = 0x6A,
VK_ADD = 0x6B,
VK_SEPARATOR = 0x6C,
VK_SUBTRACT = 0x6D,
VK_DECIMAL = 0x6E,
VK_DIVIDE = 0x6F,
VK_F1 = 0x70,
VK_F2 = 0x71,
VK_F3 = 0x72,
VK_F4 = 0x73,
VK_F5 = 0x74,
VK_F6 = 0x75,
VK_F7 = 0x76,
VK_F8 = 0x77,
VK_F9 = 0x78,
VK_F10 = 0x79,
VK_F11 = 0x7A,
VK_F12 = 0x7B,
VK_F13 = 0x7C,
VK_F14 = 0x7D,
VK_F15 = 0x7E,
VK_F16 = 0x7F,
VK_F17 = 0x80,
VK_F18 = 0x81,
VK_F19 = 0x82,
VK_F20 = 0x83,
VK_F21 = 0x84,
VK_F22 = 0x85,
VK_F23 = 0x86,
VK_F24 = 0x87,
//
VK_NUMLOCK = 0x90,
VK_SCROLL = 0x91,
//
VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad
//
VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key
VK_OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key
VK_OEM_FJ_TOUROKU = 0x94, // 'Register word' key
VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key
VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key
//
VK_LSHIFT = 0xA0,
VK_RSHIFT = 0xA1,
VK_LCONTROL = 0xA2,
VK_RCONTROL = 0xA3,
VK_LMENU = 0xA4,
VK_RMENU = 0xA5,
//
VK_BROWSER_BACK = 0xA6,
VK_BROWSER_FORWARD = 0xA7,
VK_BROWSER_REFRESH = 0xA8,
VK_BROWSER_STOP = 0xA9,
VK_BROWSER_SEARCH = 0xAA,
VK_BROWSER_FAVORITES = 0xAB,
VK_BROWSER_HOME = 0xAC,
//
VK_VOLUME_MUTE = 0xAD,
VK_VOLUME_DOWN = 0xAE,
VK_VOLUME_UP = 0xAF,
VK_MEDIA_NEXT_TRACK = 0xB0,
VK_MEDIA_PREV_TRACK = 0xB1,
VK_MEDIA_STOP = 0xB2,
VK_MEDIA_PLAY_PAUSE = 0xB3,
VK_LAUNCH_MAIL = 0xB4,
VK_LAUNCH_MEDIA_SELECT = 0xB5,
VK_LAUNCH_APP1 = 0xB6,
VK_LAUNCH_APP2 = 0xB7,
//
VK_OEM_1 = 0xBA, // ';:' for US
VK_OEM_PLUS = 0xBB, // '+' any country
VK_OEM_COMMA = 0xBC, // ',' any country
VK_OEM_MINUS = 0xBD, // '-' any country
VK_OEM_PERIOD = 0xBE, // '.' any country
VK_OEM_2 = 0xBF, // '/?' for US
VK_OEM_3 = 0xC0, // '`~' for US
//
VK_OEM_4 = 0xDB, // '[{' for US
VK_OEM_5 = 0xDC, // '|' for US
VK_OEM_6 = 0xDD, // ']}' for US
VK_OEM_7 = 0xDE, // ''"' for US
VK_OEM_8 = 0xDF,
//
VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd
VK_OEM_102 = 0xE2, // "<>" or "|" on RT 102-key kbd.
VK_ICO_HELP = 0xE3, // Help key on ICO
VK_ICO_00 = 0xE4, // 00 key on ICO
//
VK_PROCESSKEY = 0xE5,
//
VK_ICO_CLEAR = 0xE6,
//
VK_PACKET = 0xE7,
//
VK_OEM_RESET = 0xE9,
VK_OEM_JUMP = 0xEA,
VK_OEM_PA1 = 0xEB,
VK_OEM_PA2 = 0xEC,
VK_OEM_PA3 = 0xED,
VK_OEM_WSCTRL = 0xEE,
VK_OEM_CUSEL = 0xEF,
VK_OEM_ATTN = 0xF0,
VK_OEM_FINISH = 0xF1,
VK_OEM_COPY = 0xF2,
VK_OEM_AUTO = 0xF3,
VK_OEM_ENLW = 0xF4,
VK_OEM_BACKTAB = 0xF5,
//
VK_ATTN = 0xF6,
VK_CRSEL = 0xF7,
VK_EXSEL = 0xF8,
VK_EREOF = 0xF9,
VK_PLAY = 0xFA,
VK_ZOOM = 0xFB,
VK_NONAME = 0xFC,
VK_PA1 = 0xFD,
VK_OEM_CLEAR = 0xFE,
//
VK_0 = 0x30,
VK_1 = 0x31,
VK_2 = 0x32,
VK_3 = 0x33,
VK_4 = 0x34,
VK_5 = 0x35,
VK_6 = 0x36,
VK_7 = 0x37,
VK_8 = 0x38,
VK_9 = 0x39
}
///summary>
/// Virtual Messages
/// </summary>
public enum WMessages : int
/// <summary>
/// Sends a message to the specified window
/// </summary>
/// <param name="winTitle">string Title of window</param>
/// <param name="Key">Virtual key code of the key to send</param>
public static void ControlSendMessage(string winTitle, VirtualKeyStates Key, bool shift)
{
IntPtr hWnd = FindWindow(null, winTitle);
if (shift == true)
{
//send shift down
SendMessage(hWnd, 0x100, (int)VirtualKeyStates.VK_SHIFT, 0);
//send key down
SendMessage(hWnd, 0x100, (int)Key, 0);
//sleep 50ms
Thread.Sleep(50);
//send key up
SendMessage(hWnd, 0x101, (int)Key, 0);
//send shift up
SendMessage(hWnd, 0x101, (int)VirtualKeyStates.VK_SHIFT, 0);
}
else
{
//send key down
SendMessage(hWnd, 0x100, (int)Key, 0);
//sleep 50ms
Thread.Sleep(50);
//send key up
SendMessage(hWnd, 0x101, (int)Key, 0);
}
}
/// <summary>
/// Sends a Keydown message(0x100) to the specified window with a Virtual Key
/// </summary>
/// <param name="winTitle">Window Title</param>
/// <param name="Key">Virtual Key to Send</param>
public static void KeyDown(string winTitle, VirtualKeyStates Key)
{
IntPtr hWnd = FindWindow(null, winTitle);
SendMessage(hWnd, 0x100, (int)Key, 0);
}
/// <summary>
/// Sends a Keydup message(0x101) to the specified window with a Virtual Key
/// </summary>
/// <param name="winTitle">Window Title</param>
/// <param name="Key">Virtual Key to Send</param>
public static void KeyUp(string winTitle, VirtualKeyStates Key)
{
IntPtr hWnd = FindWindow(null, winTitle);
SendMessage(hWnd, 0x101, (int)Key, 0);
}
/// <summary>
/// Sends a message to the specified handle
/// </summary>
public void _SendMessage(IntPtr handle, int Msg, int wParam, int lParam)
{
SendMessage(handle, Msg, wParam, lParam);
}
您的代码未发送击键。它发送一条消息,指出密钥已更改,但并未实际发送输入。如果目标 window 只查看消息而忽略实际的键状态,这可能会起作用。 DirectX 应用程序通常会注意实际的键盘状态,并会忽略您发送的消息。
而是使用 SendInput API to inject keys into the input stream. Input injected at this level will go through the normal input processing and act like real keyboard input. Depending on the target app you may need to set the scancode in the KEYBDINPUT 结构而不仅仅是虚拟键。这可能适用于 DX 应用程序。
有关详细信息,请参阅 Simulating Input section in MSDN's keyboard input overview。
看来这个问题引起了很多意见,所以这是我之前做的解决方案(我从一个网站收集了输入,并将其制成枚举以便于使用。):
/// <summary>
/// My own question as reference:
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
public class Keyboard
{
[Flags]
public enum InputType
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
[Flags]
public enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
[DllImport("user32.dll")]
private static extern IntPtr GetMessageExtraInfo();
/// <summary>
/// DirectX key list collected out from the gamespp.com list by me.
/// </summary>
public enum DirectXKeyStrokes
{
DIK_ESCAPE = 0x01,
DIK_1 = 0x02,
DIK_2 = 0x03,
DIK_3 = 0x04,
DIK_4 = 0x05,
DIK_5 = 0x06,
DIK_6 = 0x07,
DIK_7 = 0x08,
DIK_8 = 0x09,
DIK_9 = 0x0A,
DIK_0 = 0x0B,
DIK_MINUS = 0x0C,
DIK_EQUALS = 0x0D,
DIK_BACK = 0x0E,
DIK_TAB = 0x0F,
DIK_Q = 0x10,
DIK_W = 0x11,
DIK_E = 0x12,
DIK_R = 0x13,
DIK_T = 0x14,
DIK_Y = 0x15,
DIK_U = 0x16,
DIK_I = 0x17,
DIK_O = 0x18,
DIK_P = 0x19,
DIK_LBRACKET = 0x1A,
DIK_RBRACKET = 0x1B,
DIK_RETURN = 0x1C,
DIK_LCONTROL = 0x1D,
DIK_A = 0x1E,
DIK_S = 0x1F,
DIK_D = 0x20,
DIK_F = 0x21,
DIK_G = 0x22,
DIK_H = 0x23,
DIK_J = 0x24,
DIK_K = 0x25,
DIK_L = 0x26,
DIK_SEMICOLON = 0x27,
DIK_APOSTROPHE = 0x28,
DIK_GRAVE = 0x29,
DIK_LSHIFT = 0x2A,
DIK_BACKSLASH = 0x2B,
DIK_Z = 0x2C,
DIK_X = 0x2D,
DIK_C = 0x2E,
DIK_V = 0x2F,
DIK_B = 0x30,
DIK_N = 0x31,
DIK_M = 0x32,
DIK_COMMA = 0x33,
DIK_PERIOD = 0x34,
DIK_SLASH = 0x35,
DIK_RSHIFT = 0x36,
DIK_MULTIPLY = 0x37,
DIK_LMENU = 0x38,
DIK_SPACE = 0x39,
DIK_CAPITAL = 0x3A,
DIK_F1 = 0x3B,
DIK_F2 = 0x3C,
DIK_F3 = 0x3D,
DIK_F4 = 0x3E,
DIK_F5 = 0x3F,
DIK_F6 = 0x40,
DIK_F7 = 0x41,
DIK_F8 = 0x42,
DIK_F9 = 0x43,
DIK_F10 = 0x44,
DIK_NUMLOCK = 0x45,
DIK_SCROLL = 0x46,
DIK_NUMPAD7 = 0x47,
DIK_NUMPAD8 = 0x48,
DIK_NUMPAD9 = 0x49,
DIK_SUBTRACT = 0x4A,
DIK_NUMPAD4 = 0x4B,
DIK_NUMPAD5 = 0x4C,
DIK_NUMPAD6 = 0x4D,
DIK_ADD = 0x4E,
DIK_NUMPAD1 = 0x4F,
DIK_NUMPAD2 = 0x50,
DIK_NUMPAD3 = 0x51,
DIK_NUMPAD0 = 0x52,
DIK_DECIMAL = 0x53,
DIK_F11 = 0x57,
DIK_F12 = 0x58,
DIK_F13 = 0x64,
DIK_F14 = 0x65,
DIK_F15 = 0x66,
DIK_KANA = 0x70,
DIK_CONVERT = 0x79,
DIK_NOCONVERT = 0x7B,
DIK_YEN = 0x7D,
DIK_NUMPADEQUALS = 0x8D,
DIK_CIRCUMFLEX = 0x90,
DIK_AT = 0x91,
DIK_COLON = 0x92,
DIK_UNDERLINE = 0x93,
DIK_KANJI = 0x94,
DIK_STOP = 0x95,
DIK_AX = 0x96,
DIK_UNLABELED = 0x97,
DIK_NUMPADENTER = 0x9C,
DIK_RCONTROL = 0x9D,
DIK_NUMPADCOMMA = 0xB3,
DIK_DIVIDE = 0xB5,
DIK_SYSRQ = 0xB7,
DIK_RMENU = 0xB8,
DIK_HOME = 0xC7,
DIK_UP = 0xC8,
DIK_PRIOR = 0xC9,
DIK_LEFT = 0xCB,
DIK_RIGHT = 0xCD,
DIK_END = 0xCF,
DIK_DOWN = 0xD0,
DIK_NEXT = 0xD1,
DIK_INSERT = 0xD2,
DIK_DELETE = 0xD3,
DIK_LWIN = 0xDB,
DIK_RWIN = 0xDC,
DIK_APPS = 0xDD,
DIK_BACKSPACE = DIK_BACK,
DIK_NUMPADSTAR = DIK_MULTIPLY,
DIK_LALT = DIK_LMENU,
DIK_CAPSLOCK = DIK_CAPITAL,
DIK_NUMPADMINUS = DIK_SUBTRACT,
DIK_NUMPADPLUS = DIK_ADD,
DIK_NUMPADPERIOD = DIK_DECIMAL,
DIK_NUMPADSLASH = DIK_DIVIDE,
DIK_RALT = DIK_RMENU,
DIK_UPARROW = DIK_UP,
DIK_PGUP = DIK_PRIOR,
DIK_LEFTARROW = DIK_LEFT,
DIK_RIGHTARROW = DIK_RIGHT,
DIK_DOWNARROW = DIK_DOWN,
DIK_PGDN = DIK_NEXT,
// Mined these out of nowhere.
DIK_LEFTMOUSEBUTTON = 0x100,
DIK_RIGHTMOUSEBUTTON = 0x101,
DIK_MIDDLEWHEELBUTTON = 0x102,
DIK_MOUSEBUTTON3 = 0x103,
DIK_MOUSEBUTTON4 = 0x104,
DIK_MOUSEBUTTON5 = 0x105,
DIK_MOUSEBUTTON6 = 0x106,
DIK_MOUSEBUTTON7 = 0x107,
DIK_MOUSEWHEELUP = 0x108,
DIK_MOUSEWHEELDOWN = 0x109,
}
/// <summary>
/// Sends a directx key.
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
/// <param name="key"></param>
/// <param name="KeyUp"></param>
/// <param name="inputType"></param>
public static void SendKey(DirectXKeyStrokes key, bool KeyUp, InputType inputType)
{
uint flagtosend;
if (KeyUp)
{
flagtosend = (uint) (KeyEventF.KeyUp | KeyEventF.Scancode);
}
else
{
flagtosend = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode);
}
Input[] inputs =
{
new Input
{
type = (int) inputType,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = (ushort) key,
dwFlags = flagtosend,
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SendInput((uint) inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));
}
/// <summary>
/// Sends a directx key.
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
/// <param name="key"></param>
/// <param name="KeyUp"></param>
/// <param name="inputType"></param>
public static void SendKey(ushort key, bool KeyUp, InputType inputType)
{
uint flagtosend;
if (KeyUp)
{
flagtosend = (uint) (KeyEventF.KeyUp | KeyEventF.Scancode);
}
else
{
flagtosend = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode);
}
Input[] inputs =
{
new Input
{
type = (int) inputType,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = key,
dwFlags = flagtosend,
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SendInput((uint) inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));
}
public struct Input
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)] public readonly MouseInput mi;
[FieldOffset(0)] public KeyboardInput ki;
[FieldOffset(0)] public readonly HardwareInput hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
public readonly int dx;
public readonly int dy;
public readonly uint mouseData;
public readonly uint dwFlags;
public readonly uint time;
public readonly IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public readonly uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HardwareInput
{
public readonly uint uMsg;
public readonly ushort wParamL;
public readonly ushort wParamH;
}
}
我在发送密钥时遇到了一点麻烦。好像什么时候我想发送密钥都行不通。
我正在考虑 sending alphabetic characters 例如 T 从示例中调出聊天,但是如果我将它写入枚举,则无论何时使用它们都不会发生任何事情。有什么想法吗?
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
/// <summary>
/// Virtual Keys
/// </summary>
public enum VirtualKeyStates : int
{
VK_LBUTTON = 0x01,
VK_RBUTTON = 0x02,
VK_CANCEL = 0x03,
VK_MBUTTON = 0x04,
//
VK_XBUTTON1 = 0x05,
VK_XBUTTON2 = 0x06,
//
VK_BACK = 0x08,
VK_TAB = 0x09,
//
VK_CLEAR = 0x0C,
VK_RETURN = 0x0D,
//
VK_SHIFT = 0x10,
VK_CONTROL = 0x11,
VK_MENU = 0x12,
VK_PAUSE = 0x13,
VK_CAPITAL = 0x14,
//
VK_KANA = 0x15,
VK_HANGEUL = 0x15, /* old name - should be here for compatibility */
VK_HANGUL = 0x15,
VK_JUNJA = 0x17,
VK_FINAL = 0x18,
VK_HANJA = 0x19,
VK_KANJI = 0x19,
//
VK_ESCAPE = 0x1B,
//
VK_CONVERT = 0x1C,
VK_NONCONVERT = 0x1D,
VK_ACCEPT = 0x1E,
VK_MODECHANGE = 0x1F,
//
VK_SPACE = 0x20,
VK_PRIOR = 0x21,
VK_NEXT = 0x22,
VK_END = 0x23,
VK_HOME = 0x24,
VK_LEFT = 0x25,
VK_UP = 0x26,
VK_RIGHT = 0x27,
VK_DOWN = 0x28,
VK_SELECT = 0x29,
VK_PRINT = 0x2A,
VK_EXECUTE = 0x2B,
VK_SNAPSHOT = 0x2C,
VK_INSERT = 0x2D,
VK_DELETE = 0x2E,
VK_HELP = 0x2F,
//
VK_LWIN = 0x5B,
VK_RWIN = 0x5C,
VK_APPS = 0x5D,
//
VK_SLEEP = 0x5F,
//
VK_NUMPAD0 = 0x60,
VK_NUMPAD1 = 0x61,
VK_NUMPAD2 = 0x62,
VK_NUMPAD3 = 0x63,
VK_NUMPAD4 = 0x64,
VK_NUMPAD5 = 0x65,
VK_NUMPAD6 = 0x66,
VK_NUMPAD7 = 0x67,
VK_NUMPAD8 = 0x68,
VK_NUMPAD9 = 0x69,
VK_MULTIPLY = 0x6A,
VK_ADD = 0x6B,
VK_SEPARATOR = 0x6C,
VK_SUBTRACT = 0x6D,
VK_DECIMAL = 0x6E,
VK_DIVIDE = 0x6F,
VK_F1 = 0x70,
VK_F2 = 0x71,
VK_F3 = 0x72,
VK_F4 = 0x73,
VK_F5 = 0x74,
VK_F6 = 0x75,
VK_F7 = 0x76,
VK_F8 = 0x77,
VK_F9 = 0x78,
VK_F10 = 0x79,
VK_F11 = 0x7A,
VK_F12 = 0x7B,
VK_F13 = 0x7C,
VK_F14 = 0x7D,
VK_F15 = 0x7E,
VK_F16 = 0x7F,
VK_F17 = 0x80,
VK_F18 = 0x81,
VK_F19 = 0x82,
VK_F20 = 0x83,
VK_F21 = 0x84,
VK_F22 = 0x85,
VK_F23 = 0x86,
VK_F24 = 0x87,
//
VK_NUMLOCK = 0x90,
VK_SCROLL = 0x91,
//
VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad
//
VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key
VK_OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key
VK_OEM_FJ_TOUROKU = 0x94, // 'Register word' key
VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key
VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key
//
VK_LSHIFT = 0xA0,
VK_RSHIFT = 0xA1,
VK_LCONTROL = 0xA2,
VK_RCONTROL = 0xA3,
VK_LMENU = 0xA4,
VK_RMENU = 0xA5,
//
VK_BROWSER_BACK = 0xA6,
VK_BROWSER_FORWARD = 0xA7,
VK_BROWSER_REFRESH = 0xA8,
VK_BROWSER_STOP = 0xA9,
VK_BROWSER_SEARCH = 0xAA,
VK_BROWSER_FAVORITES = 0xAB,
VK_BROWSER_HOME = 0xAC,
//
VK_VOLUME_MUTE = 0xAD,
VK_VOLUME_DOWN = 0xAE,
VK_VOLUME_UP = 0xAF,
VK_MEDIA_NEXT_TRACK = 0xB0,
VK_MEDIA_PREV_TRACK = 0xB1,
VK_MEDIA_STOP = 0xB2,
VK_MEDIA_PLAY_PAUSE = 0xB3,
VK_LAUNCH_MAIL = 0xB4,
VK_LAUNCH_MEDIA_SELECT = 0xB5,
VK_LAUNCH_APP1 = 0xB6,
VK_LAUNCH_APP2 = 0xB7,
//
VK_OEM_1 = 0xBA, // ';:' for US
VK_OEM_PLUS = 0xBB, // '+' any country
VK_OEM_COMMA = 0xBC, // ',' any country
VK_OEM_MINUS = 0xBD, // '-' any country
VK_OEM_PERIOD = 0xBE, // '.' any country
VK_OEM_2 = 0xBF, // '/?' for US
VK_OEM_3 = 0xC0, // '`~' for US
//
VK_OEM_4 = 0xDB, // '[{' for US
VK_OEM_5 = 0xDC, // '|' for US
VK_OEM_6 = 0xDD, // ']}' for US
VK_OEM_7 = 0xDE, // ''"' for US
VK_OEM_8 = 0xDF,
//
VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd
VK_OEM_102 = 0xE2, // "<>" or "|" on RT 102-key kbd.
VK_ICO_HELP = 0xE3, // Help key on ICO
VK_ICO_00 = 0xE4, // 00 key on ICO
//
VK_PROCESSKEY = 0xE5,
//
VK_ICO_CLEAR = 0xE6,
//
VK_PACKET = 0xE7,
//
VK_OEM_RESET = 0xE9,
VK_OEM_JUMP = 0xEA,
VK_OEM_PA1 = 0xEB,
VK_OEM_PA2 = 0xEC,
VK_OEM_PA3 = 0xED,
VK_OEM_WSCTRL = 0xEE,
VK_OEM_CUSEL = 0xEF,
VK_OEM_ATTN = 0xF0,
VK_OEM_FINISH = 0xF1,
VK_OEM_COPY = 0xF2,
VK_OEM_AUTO = 0xF3,
VK_OEM_ENLW = 0xF4,
VK_OEM_BACKTAB = 0xF5,
//
VK_ATTN = 0xF6,
VK_CRSEL = 0xF7,
VK_EXSEL = 0xF8,
VK_EREOF = 0xF9,
VK_PLAY = 0xFA,
VK_ZOOM = 0xFB,
VK_NONAME = 0xFC,
VK_PA1 = 0xFD,
VK_OEM_CLEAR = 0xFE,
//
VK_0 = 0x30,
VK_1 = 0x31,
VK_2 = 0x32,
VK_3 = 0x33,
VK_4 = 0x34,
VK_5 = 0x35,
VK_6 = 0x36,
VK_7 = 0x37,
VK_8 = 0x38,
VK_9 = 0x39
}
///summary>
/// Virtual Messages
/// </summary>
public enum WMessages : int
/// <summary>
/// Sends a message to the specified window
/// </summary>
/// <param name="winTitle">string Title of window</param>
/// <param name="Key">Virtual key code of the key to send</param>
public static void ControlSendMessage(string winTitle, VirtualKeyStates Key, bool shift)
{
IntPtr hWnd = FindWindow(null, winTitle);
if (shift == true)
{
//send shift down
SendMessage(hWnd, 0x100, (int)VirtualKeyStates.VK_SHIFT, 0);
//send key down
SendMessage(hWnd, 0x100, (int)Key, 0);
//sleep 50ms
Thread.Sleep(50);
//send key up
SendMessage(hWnd, 0x101, (int)Key, 0);
//send shift up
SendMessage(hWnd, 0x101, (int)VirtualKeyStates.VK_SHIFT, 0);
}
else
{
//send key down
SendMessage(hWnd, 0x100, (int)Key, 0);
//sleep 50ms
Thread.Sleep(50);
//send key up
SendMessage(hWnd, 0x101, (int)Key, 0);
}
}
/// <summary>
/// Sends a Keydown message(0x100) to the specified window with a Virtual Key
/// </summary>
/// <param name="winTitle">Window Title</param>
/// <param name="Key">Virtual Key to Send</param>
public static void KeyDown(string winTitle, VirtualKeyStates Key)
{
IntPtr hWnd = FindWindow(null, winTitle);
SendMessage(hWnd, 0x100, (int)Key, 0);
}
/// <summary>
/// Sends a Keydup message(0x101) to the specified window with a Virtual Key
/// </summary>
/// <param name="winTitle">Window Title</param>
/// <param name="Key">Virtual Key to Send</param>
public static void KeyUp(string winTitle, VirtualKeyStates Key)
{
IntPtr hWnd = FindWindow(null, winTitle);
SendMessage(hWnd, 0x101, (int)Key, 0);
}
/// <summary>
/// Sends a message to the specified handle
/// </summary>
public void _SendMessage(IntPtr handle, int Msg, int wParam, int lParam)
{
SendMessage(handle, Msg, wParam, lParam);
}
您的代码未发送击键。它发送一条消息,指出密钥已更改,但并未实际发送输入。如果目标 window 只查看消息而忽略实际的键状态,这可能会起作用。 DirectX 应用程序通常会注意实际的键盘状态,并会忽略您发送的消息。
而是使用 SendInput API to inject keys into the input stream. Input injected at this level will go through the normal input processing and act like real keyboard input. Depending on the target app you may need to set the scancode in the KEYBDINPUT 结构而不仅仅是虚拟键。这可能适用于 DX 应用程序。
有关详细信息,请参阅 Simulating Input section in MSDN's keyboard input overview。
看来这个问题引起了很多意见,所以这是我之前做的解决方案(我从一个网站收集了输入,并将其制成枚举以便于使用。):
/// <summary>
/// My own question as reference:
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
public class Keyboard
{
[Flags]
public enum InputType
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
[Flags]
public enum KeyEventF
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008,
}
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
[DllImport("user32.dll")]
private static extern IntPtr GetMessageExtraInfo();
/// <summary>
/// DirectX key list collected out from the gamespp.com list by me.
/// </summary>
public enum DirectXKeyStrokes
{
DIK_ESCAPE = 0x01,
DIK_1 = 0x02,
DIK_2 = 0x03,
DIK_3 = 0x04,
DIK_4 = 0x05,
DIK_5 = 0x06,
DIK_6 = 0x07,
DIK_7 = 0x08,
DIK_8 = 0x09,
DIK_9 = 0x0A,
DIK_0 = 0x0B,
DIK_MINUS = 0x0C,
DIK_EQUALS = 0x0D,
DIK_BACK = 0x0E,
DIK_TAB = 0x0F,
DIK_Q = 0x10,
DIK_W = 0x11,
DIK_E = 0x12,
DIK_R = 0x13,
DIK_T = 0x14,
DIK_Y = 0x15,
DIK_U = 0x16,
DIK_I = 0x17,
DIK_O = 0x18,
DIK_P = 0x19,
DIK_LBRACKET = 0x1A,
DIK_RBRACKET = 0x1B,
DIK_RETURN = 0x1C,
DIK_LCONTROL = 0x1D,
DIK_A = 0x1E,
DIK_S = 0x1F,
DIK_D = 0x20,
DIK_F = 0x21,
DIK_G = 0x22,
DIK_H = 0x23,
DIK_J = 0x24,
DIK_K = 0x25,
DIK_L = 0x26,
DIK_SEMICOLON = 0x27,
DIK_APOSTROPHE = 0x28,
DIK_GRAVE = 0x29,
DIK_LSHIFT = 0x2A,
DIK_BACKSLASH = 0x2B,
DIK_Z = 0x2C,
DIK_X = 0x2D,
DIK_C = 0x2E,
DIK_V = 0x2F,
DIK_B = 0x30,
DIK_N = 0x31,
DIK_M = 0x32,
DIK_COMMA = 0x33,
DIK_PERIOD = 0x34,
DIK_SLASH = 0x35,
DIK_RSHIFT = 0x36,
DIK_MULTIPLY = 0x37,
DIK_LMENU = 0x38,
DIK_SPACE = 0x39,
DIK_CAPITAL = 0x3A,
DIK_F1 = 0x3B,
DIK_F2 = 0x3C,
DIK_F3 = 0x3D,
DIK_F4 = 0x3E,
DIK_F5 = 0x3F,
DIK_F6 = 0x40,
DIK_F7 = 0x41,
DIK_F8 = 0x42,
DIK_F9 = 0x43,
DIK_F10 = 0x44,
DIK_NUMLOCK = 0x45,
DIK_SCROLL = 0x46,
DIK_NUMPAD7 = 0x47,
DIK_NUMPAD8 = 0x48,
DIK_NUMPAD9 = 0x49,
DIK_SUBTRACT = 0x4A,
DIK_NUMPAD4 = 0x4B,
DIK_NUMPAD5 = 0x4C,
DIK_NUMPAD6 = 0x4D,
DIK_ADD = 0x4E,
DIK_NUMPAD1 = 0x4F,
DIK_NUMPAD2 = 0x50,
DIK_NUMPAD3 = 0x51,
DIK_NUMPAD0 = 0x52,
DIK_DECIMAL = 0x53,
DIK_F11 = 0x57,
DIK_F12 = 0x58,
DIK_F13 = 0x64,
DIK_F14 = 0x65,
DIK_F15 = 0x66,
DIK_KANA = 0x70,
DIK_CONVERT = 0x79,
DIK_NOCONVERT = 0x7B,
DIK_YEN = 0x7D,
DIK_NUMPADEQUALS = 0x8D,
DIK_CIRCUMFLEX = 0x90,
DIK_AT = 0x91,
DIK_COLON = 0x92,
DIK_UNDERLINE = 0x93,
DIK_KANJI = 0x94,
DIK_STOP = 0x95,
DIK_AX = 0x96,
DIK_UNLABELED = 0x97,
DIK_NUMPADENTER = 0x9C,
DIK_RCONTROL = 0x9D,
DIK_NUMPADCOMMA = 0xB3,
DIK_DIVIDE = 0xB5,
DIK_SYSRQ = 0xB7,
DIK_RMENU = 0xB8,
DIK_HOME = 0xC7,
DIK_UP = 0xC8,
DIK_PRIOR = 0xC9,
DIK_LEFT = 0xCB,
DIK_RIGHT = 0xCD,
DIK_END = 0xCF,
DIK_DOWN = 0xD0,
DIK_NEXT = 0xD1,
DIK_INSERT = 0xD2,
DIK_DELETE = 0xD3,
DIK_LWIN = 0xDB,
DIK_RWIN = 0xDC,
DIK_APPS = 0xDD,
DIK_BACKSPACE = DIK_BACK,
DIK_NUMPADSTAR = DIK_MULTIPLY,
DIK_LALT = DIK_LMENU,
DIK_CAPSLOCK = DIK_CAPITAL,
DIK_NUMPADMINUS = DIK_SUBTRACT,
DIK_NUMPADPLUS = DIK_ADD,
DIK_NUMPADPERIOD = DIK_DECIMAL,
DIK_NUMPADSLASH = DIK_DIVIDE,
DIK_RALT = DIK_RMENU,
DIK_UPARROW = DIK_UP,
DIK_PGUP = DIK_PRIOR,
DIK_LEFTARROW = DIK_LEFT,
DIK_RIGHTARROW = DIK_RIGHT,
DIK_DOWNARROW = DIK_DOWN,
DIK_PGDN = DIK_NEXT,
// Mined these out of nowhere.
DIK_LEFTMOUSEBUTTON = 0x100,
DIK_RIGHTMOUSEBUTTON = 0x101,
DIK_MIDDLEWHEELBUTTON = 0x102,
DIK_MOUSEBUTTON3 = 0x103,
DIK_MOUSEBUTTON4 = 0x104,
DIK_MOUSEBUTTON5 = 0x105,
DIK_MOUSEBUTTON6 = 0x106,
DIK_MOUSEBUTTON7 = 0x107,
DIK_MOUSEWHEELUP = 0x108,
DIK_MOUSEWHEELDOWN = 0x109,
}
/// <summary>
/// Sends a directx key.
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
/// <param name="key"></param>
/// <param name="KeyUp"></param>
/// <param name="inputType"></param>
public static void SendKey(DirectXKeyStrokes key, bool KeyUp, InputType inputType)
{
uint flagtosend;
if (KeyUp)
{
flagtosend = (uint) (KeyEventF.KeyUp | KeyEventF.Scancode);
}
else
{
flagtosend = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode);
}
Input[] inputs =
{
new Input
{
type = (int) inputType,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = (ushort) key,
dwFlags = flagtosend,
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SendInput((uint) inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));
}
/// <summary>
/// Sends a directx key.
/// http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
/// </summary>
/// <param name="key"></param>
/// <param name="KeyUp"></param>
/// <param name="inputType"></param>
public static void SendKey(ushort key, bool KeyUp, InputType inputType)
{
uint flagtosend;
if (KeyUp)
{
flagtosend = (uint) (KeyEventF.KeyUp | KeyEventF.Scancode);
}
else
{
flagtosend = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode);
}
Input[] inputs =
{
new Input
{
type = (int) inputType,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = key,
dwFlags = flagtosend,
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SendInput((uint) inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));
}
public struct Input
{
public int type;
public InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)] public readonly MouseInput mi;
[FieldOffset(0)] public KeyboardInput ki;
[FieldOffset(0)] public readonly HardwareInput hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
public readonly int dx;
public readonly int dy;
public readonly uint mouseData;
public readonly uint dwFlags;
public readonly uint time;
public readonly IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public readonly uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HardwareInput
{
public readonly uint uMsg;
public readonly ushort wParamL;
public readonly ushort wParamH;
}
}