Итак, у меня есть приложение, которое работает с игрой.
На одном из этапов программы он щелкает текстовое поле, вводит некоторый текст и затем щелкает другие элементы.
Теперь проблема в том, что иногда первый набранный символ блокируется.
То есть если я печатаю «Это тест» в текстовое поле появляется следующее «это испытание». Это всегда первый персонаж, который исчезает. После изменения кода для печати только 1 символа, я слышу классический звук «bing» Windows, который вы слышите, когда вводите недопустимые символы в поле ввода Windows. Однако ни один из моих персонажей недействителен.
Так или иначе, все это начало происходить, когда я изменил способ, которым моя программа нажимает на текстовые поля. Прежде чем он будет перемещать курсор, имитируйте щелчок. Теперь он просто имитирует щелчок, не касаясь курсора.
Мне удалось решить эту проблему для всех текстовых полей, кроме следующего сценария: одна часть моего кода повторяется в одном и том же текстовом поле более одного раза (поэтому он нажимает на него, вводит текст, выполняет другие действия, нажимает на одно и то же текстовое поле, вводит текст … и т.д.).
Проблема заключается в том, что при первом вводе текста первый символ никогда не пропускается, последующие записи имеют очень высокий шанс пропустить первый символ (но иногда это не так (возможно, в 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
Задача ещё не решена.