我正在尝试将简单的键序列(ctrl-p、shift-p)发送到前台应用程序(恰好是 Visual Studio 编辑器单元测试缓冲区)。无论我尝试什么,我都无法让我的 control-p 或 shift-p 测试键序列正常工作。'p' 出现在缓冲区中,但不与控制/移位部分一起出现。
我已经从 SO 和网络轻松阅读了十几个代码示例,阅读了文档并尝试了太多无法计算的变体。但没有成功。我在标准的 Windows10x64 系统上,将代码作为单元测试运行。
下面的代码设置了修饰键的虚拟键和扫描码,这在实践中可能是错误的。我尝试了两种方法都没有成功。我包含了设置两者的代码,以便您可以看到我用于这两个字段的代码。
有谁知道我做错了什么?谢谢你。
** 更新 ** 我的代码没有失败。我在 Visual Studio 中的单元测试中运行它,它阻止了修改键。当我在单元测试之外运行相同的代码(没有所有调试层等)时,代码运行良好。
教训:不要尝试在单元测试中调试您的 SendInput 代码修饰键!
[DllImport("user32.dll", SetLastError = true)]
public static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, KeyInput[] pInputs, int cbSize);
[Flags]
public enum KeyEventFlag
{
KeyDown = 0x0000,
ExtendedKey = 0x0001,
KeyUp = 0x0002,
Unicode = 0x0004,
Scancode = 0x0008
}
[Flags]
public enum InputType : int
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
public struct KeyInput
{
public int type;
public WinSend.InputUnion u;
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)] public MouseInput mi;
[FieldOffset(0)] public KeyboardInput ki;
[FieldOffset(0)] public HardwareInput hi;
}
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
const uint MAPVK_VK_TO_VSC = 0x00;
const uint MAPVK_VSC_TO_VK = 0x01;
const uint MAPVK_VK_TO_CHAR = 0x02;
const uint MAPVK_VSC_TO_VK_EX = 0x03;
const uint MAPVK_VK_TO_VSC_EX = 0x04;
[TestMethod()]
public void SendControlKeyTest() {
DebugOn = true;
const uint VK_CONTROL = 0x11;
const uint VK_LCONTROL = 0xA2;
const uint VK_LSHIFT = 0xA0;
var keyList = new List<KeyInput>();
// wVk = A virtual-key code. The code must be a value in the range 1 to 254.
// If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0.
// wScan = A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE,
// wScan specifies a Unicode char to send to the foreground application.
// the MapVirtualKey calls return successfully
var scanControl = MapVirtualKey((uint) VK_CONTROL, (uint) MAPVK_VK_TO_VSC);
if (scanControl == 0) Dprint("MapVirtualKey for VK_CONTROL failed.p");
var scanShift = MapVirtualKey((uint) VK_LSHIFT, (uint) MAPVK_VK_TO_VSC);
if (scanShift == 0) Dprint("MapVirtualKey for VK_LSHIFT failed.");
// this fails as is, fails with Flag.Unicode, and fails with no XXcode set
// this also fails with either VK_CONTROL or 0 in the wVk field
var vkdown = new KeyInput();
vkdown.type = (int) InputType.Keyboard;
vkdown.u.ki.wVk = (ushort) VK_CONTROL; // also fails with 0x0
vkdown.u.ki.dwFlags = (uint) (KeyEventFlag.Scancode | KeyEventFlag.KeyDown);
vkdown.u.ki.wScan = (ushort) scanControl;
keyList.Add(vkdown);
// this works - I see the 'p' when it runs
var keydown = new KeyInput();
keydown.type = (int) InputType.Keyboard;
keydown.u.ki.wVk = 0; // must be zero if Flag.Unicode is set
keydown.u.ki.dwFlags = (uint) (KeyEventFlag.Unicode | KeyEventFlag.KeyDown);
keydown.u.ki.wScan = (ushort) 'p';
keyList.Add(keydown);
// this works - I see the 'p' when it runs
var keyup = new KeyInput();
keyup.type = (int) InputType.Keyboard;
keyup.u.ki.wVk = 0; // must be zero if Flag.Unicode is set
keyup.u.ki.dwFlags = (uint) (KeyEventFlag.Unicode | KeyEventFlag.KeyUp);
keyup.u.ki.wScan = (ushort) 'p';
keyList.Add(keyup);
// this fails as is, fails with Flag.Unicode, and fails with no XXcode set
// this also fails with either VK_CONTROL or 0 in the wVk field
var vkup = new KeyInput();
vkup.type = (int) InputType.Keyboard;
vkup.u.ki.wVk = (ushort) VK_CONTROL; // also fails with 0x0
vkup.u.ki.dwFlags = (uint) (KeyEventFlag.Scancode| KeyEventFlag.KeyUp);
vkup.u.ki.wScan = (ushort) scanControl;
keyList.Add(vkup);
// SendInput returns 4, which means it sent 4 events successfully
var keycount = SendInput((uint) keyList.Count, keyList.ToArray(),
Marshal.SizeOf(typeof(KeyInput)));
Dprint($"Sent {keycount} keys to the system.");
// The Control-P should move my caret up one line, but it does not.
// Shift should create a capital P in the buffer, but it does not.
// All I see is a 'p' in the Visual studio buffer
}