所以我有一个适用于游戏的应用程序。在程序的一个阶段,它单击文本字段,输入一些文本,然后单击其他一些内容。
现在的问题是,有时输入的第一个字符被阻止。也就是说,如果我在文本字段中输入"This is a test" ,则会出现以下内容"his is a test"。它总是第一个消失的字符。将代码更改为仅打印 1 个字符后,当您在 windows 输入字段中输入无效字符时,我会听到经典的 windows 'bing' 声音。然而,我的所有角色都不是无效的。
无论如何,当我改变程序点击文本字段的方式时,这一切都开始发生了。在它移动光标之前,然后模拟一次点击。现在它只是模拟点击而不接触光标。
我设法为所有文本框解决了这个问题,除了以下情况:我的代码的一部分多次重新点击同一个文本框(所以它点击它,输入文本,做其他事情,点击同一个文本框,输入文字...等)。问题是第一次输入文本时,第一个字符永远不会丢失,随后的条目很有可能丢失第一个字符(但有时它们不是(可能有 5% 的时间))。
在每次点击和输入文本之间,会有延迟,我已经做了很长时间的实验(这涉及在 TypeInfo 中发送的击键之间的延迟)。这似乎不是时间问题。
以下是所有相关代码:
//Types string to stdout as physical keyboard strokes
void TypeInfo(const string info) {
breakableSleep(250);
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.time = 0;
ip.ki.wVk = 0;
ip.ki.dwExtraInfo = 0;
//Loop through champion name and type it out
for (size_t i = 0; i < info.length(); ++i) {
ip.ki.dwFlags = KEYEVENTF_UNICODE;
ip.ki.wScan = info[i];
SendInput(1, &ip, sizeof(INPUT));
//Prepare a keyup event
ip.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
}
breakableSleep(250);
}
在以下代码中,xPos 和 yPos 是相对于我希望单击的屏幕的坐标。同时删除SetForegroundWindowInternal(ctrl_handle)导致第一个字符始终不会出现在所有文本字段中。代码取自:http ://www.cplusplus.com/forum/windows/63948/
// Clicks target
void ClickTarget(HWND hwnd, int x, int y, int cols, int rows, int xoffset, int yoffset) {
//X and Y positions to click
int xPos = x + (cols / 2) + xoffset;
int yPos = y + (rows / 2) + yoffset;
POINT win_coords = { xPos, yPos };
POINT ctrl_coords = { xPos, yPos };
ScreenToClient(hwnd, &win_coords);
HWND ctrl_handle = hwnd;
ScreenToClient(ctrl_handle, &ctrl_coords);
//Before we click, set foreground window to object we want to click
SetForegroundWindowInternal(ctrl_handle);
LPARAM lParam = MAKELPARAM(ctrl_coords.x, ctrl_coords.y);
SendMessage(ctrl_handle, WM_LBUTTONDOWN, MK_LBUTTON, lParam);
SendMessage(ctrl_handle, WM_LBUTTONUP, 0, lParam);
}
//Use 'hack' to set foreground window of another process
void SetForegroundWindowInternal(HWND hWnd) {
if (!::IsWindow(hWnd)) return;
BYTE keyState[256] = { 0 };
//to unlock SetForegroundWindow we need to imitate Alt pressing
if (::GetKeyboardState((LPBYTE)&keyState))
{
if (!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
}
}
::SetForegroundWindow(hWnd);
if (::GetKeyboardState((LPBYTE)&keyState))
{
if (!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
}
这是在 main 中调用上述代码的方式:
ClickTarget(hwnd, ....);
TypeInfo("This is a test");
Sleep(...); //Some sleep or delay here