在我的程序中,我想模拟按键。例如,我想说Press(KeyA,1000),其中第一个参数是KeyCode,第二个参数是以毫秒为单位的时间。 KeyA等都是typedef,这些方法只需按一下按钮就可以正常工作。
void PressKey(INPUT &ip, int keycode, int ms)
{
// Press the key
ip.ki.wVk = keycode; // virtual-key code for the key
ip.ki.dwFlags = 0; // 0 for key press
SendInput(1, &ip, sizeof(INPUT));
sleep(ms);
// Release the key
ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
SendInput(1, &ip, sizeof(INPUT));
}
int main()
{
// input event
INPUT ip;
INPUT ipMouse;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0; // hardware scan code for key
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
PressKey(ip, KeyM, 1000);
我以为按下该键,然后等到松开该键时,将被视为按住该按钮,但并非如此。我也不想只是说一千遍PressKey(ip,KeyM)来获得与按住按钮5秒钟相同的输入。是否有人现在如何使程序模拟更长的输入?
我将回答一个更笼统的问题:“如何使用特定输入重播我的游戏?”
重放输入,进行概要分析,检查确定性或进行一般质量检查的技巧是从游戏过程中分离出两个元素:
如果您的游戏编写良好(没有未定义的行为),并且具有给定的一组输入和相关的时间安排,则其行为应始终相同。相同的输入同时产生相同的输出。
因此,将TimeGetTime(),std :: clock,rdtsc或其他用于将时间读取到您自己的getTime()函数中的东西包装起来。同样,将win32输入读数和/或scancode读数包装到您自己的getInputs()中。
运行游戏,但除了使用它们之外,还将所有输入和时间戳保存到文件中。 Log.txt或其他内容。理想情况下,您的游戏应该每帧只询问一次时间,但是,嘿,我看过一些查询每帧数千次的当前时间的游戏。
现在,修改您的游戏,以便它从日志文件中获取值,而不是获取真实的输入或真实的挂钟。如果您的游戏是确定性的,则现在应该可以重播相同的事件序列。
您可以对其进行概要分析。请注意,由于从文件中读取了时间,所以如果游戏在播放时碰巧变慢了,那就不是问题了。您的角色会跳相同的长度,落在相同的位置,等等。。。看起来会慢一些。这使您可以使用最密集的性能分析设置,即使游戏的播放速度慢10倍,它也可以完全一样,并且可以有效地计算出花费的时间。
它还为您准备好设置,让质量检查人员可以保存重播并进行调试。
要记录所有这一切需要做更多的工作,并且需要格外小心,以确保没有任何不确定性。
但是,另一方面,如果您接受原始建议,则输入注入将不会完全同时发生。您将失去一些QA再现能力。从运行到运行,行为会有所不同。
探查器开销也将影响时序,使测量有时无效。
所以,我的建议:
要具体解决问题的框架:游戏不是通过win32系统提供输入,而是调用您自己的getInput()并在重播时获取存储的输入,从而绕过整个win32系统。
但是没有这种用于模拟按键的API。
测试窗口应用程序时,按住键盘上的一个键,它将连续收到WM_KEYDOWN
消息。
[如果您的应用程序是窗口应用程序而不是控制台应用程序,则可以检测到WM_KEYDOWN
中的第一个low level keyboard hook并启动5秒钟的计时器,当计时器超时时,发送WM_KEYUP
消息,以便模拟按住压力。您只能拨打SendInput
一次并发送一键按下消息。
对于控制台应用程序,它不能被挂接,在指定时间内重复调用SendInput是您的解决方案。您对此有任何担忧吗?