背景
我正在编写一个32位WPF(C#)应用程序,它可用作屏幕键盘。它将选定的击键发布到聚焦窗口,就像按下了物理键一样,就像微软的屏幕键盘,OSK.exe的行为一样。
问题:
我正在使用InputSimulator库取得了一些成功(代码在这里:InputSimulator class which builds the INPUT array),但发现记事本未按预期识别某些击键,例如箭头键的行为就像CTRL被按下一样。同样,WIN键未按预期工作,如果Windows将输入视为Ctrl + Win,也可以解释。
擅自解决方案:
我将InputSimulator源移植到我的项目中,并根据对OSK.exe发送的SendInput的调用(使用API Monitor捕获)对键盘发送到SendInput的方式进行了一些修改。我在KeyDown / KeyUp中观察到的(并在我的代码中复制)的主要差异是:
我更改代码以复制OSK调用SendInput的方式的结果是,现在更多的键表现得好像我的目标/焦点应用程序(通常是记事本或写字板)正在检测到CTRL。但是,通过直接比较我的应用程序和API监视器中的OSK,我相信我对SendInput的调用与OSK的调用相同。
N.B。 OSK在我的Windows 8.1(64位)笔记本电脑上完美运行。
隔离的问题空间:
为了最大限度地减少问题空间,我模拟了一个单键向下/向上键组合的' S'在我重新启动的PC上使用我的应用程序的密钥(这样我可以确保按键状态没有受到先前运行或物理键击的污染)。目标是记事本,然后写字板 - 两者都打开了“另存为”的反应。对话框,表明他们已将我的击键解释为CTRL + S. API Monitor仅检测到2次SendInput调用(KeyDown然后是KeyUp),这些调用使用OSK匹配相同的实验。这是日志;
2014-12-10 21:29:54,650 Calling native method SendInput with params:
nInputs:1
pInputs[0]:
Type:1(Keyboard)
Data:
MOUSEINPUT:
X:2031699
Y:8
MouseData:0
Flags:0 ()
Time:0
KEYBDINPUT:
KeyCode:83(VK_S)
Scan:31
Flags:8 (KEYEVENTF_SCANCODE)
Time:0
ExtraInfo:0
HARDWAREINPUT:
Msg:2031699
ParamL:8
ParamH:0
cbSize:28
2014-12-10 21:29:54,651 Calling native method SendInput with params:
nInputs:1
pInputs[0]:
Type:1(Keyboard)
Data:
MOUSEINPUT:
X:2031699
Y:10
MouseData:0
Flags:0 ()
Time:0
KEYBDINPUT:
KeyCode:83(VK_S)
Scan:31
Flags:10 (KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE)
Time:0
ExtraInfo:0
HARDWAREINPUT:
Msg:2031699
ParamL:10
ParamH:0
cbSize:28
唯一明显的区别是OSK将cbSize参数传递为40,我无法伪造(如果手动传递40则调用失败)。我的体型是28,通过以下传递我得到的。我不知道为什么大小不同,因为我的结构定义与MSDN文档相匹配(我没有从原始的InputSimulator代码修改它们。)
var cbSize = Marshal.SizeOf(typeof (INPUT));
其他被诱惑的修正:
我已经尝试在指定ScanCode(和ScanCode标志)时将VirtualCode参数留空(0),但这不会改变结果。来自这里的想法:SO question
我尝试过向keybd_event添加尾随调用,但这不会改变结果。来自这里的想法:MSDN thread
(keybd_event(0x41,0,0,0);)
我尝试在每次调用SendInput之间添加线程休眠,即KeyDown和KeyUp调用之间的延迟。
我修改了我的结构和winapi函数定义以匹配PINVOKE.net
我已经将我的应用程序重新编译为64位(在我的64位机器上) - 这将cbSize更正为40,但没有改变行为。
任何帮助都会非常感激。还有关于我可以使用的其他调试工具的建议吗?我试图调试OSK可能正在调用的所有键盘功能(例如,检测对keybd_event的其他调用),但除了调用SendInput之外,没有任何记录。
答案 0 :(得分:1)
是的,问题是PEBCAK。
我错过了可以想象到的最明显的事情 - 我在测试时一直使用的触发信号(即表示我想按下当前聚焦的屏幕键的信号)是左CTRL键。我一直按下CTRL键,然后想知道为什么Windows认为按下了CTRL键。现在拍我。
我已经使用了很长时间,而且一直专注于可能行为不端的WinAPI电话的细节,我错过了最明显的原因。
我会留在这里提醒自己使用奥卡姆的剃刀。
上面的一些调试过程可能对某些人有用;我的InputSimulator代码的更改版本工作正常,原始的,未改变的代码也是如此。