Я создал небольшую программу, которая запускается на новом рабочем столе.
HDESK hDesktop = ::CreateDesktop(strDesktopName.c_str(),
NULL, // Reserved
NULL, // Reserved
0, // DF_ALLOWOTHERACCOUNTHOOK
GENERIC_ALL,
NULL); // lpSecurity
::SetThreadDesktop(hDesktop);
Позже, запустил другое приложение на этом рабочем столе, используя следующие строки:
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
si.lpDesktop = &strDesktop[0];
if (FALSE == ::CreateProcess(pathModuleName.file_string().c_str(), L"abc def", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
return false;
DWORD dwWaitRes = ::WaitForSingleObject(pi.hProcess, INFINITE);
pathModuleName
это собственное местоположение, полученное GetModuleFileName(NULL)
,
Вновь созданное приложение получает HWND в другое окно и отправляет оконные сообщения, используя следующие команды:
// bring window to front
::SetForegroundWindow(hwnd);
// set focus so keyboard inputs will be caught
::SetFocus(hwnd);
::keybd_event(VK_MENU, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
...
Так что в основном приложение A
на рабочем столе DEFAULT запускается приложение B
на рабочем столе X, который получает HWND для другого приложения C
началось на том же рабочем столе X.
Моя проблема в том, что события клавиатуры поступают из приложения B
на рабочем столе X не запускаются в приложении C
, Только если я использую SwitchDesktop(B)
, затем события запускаются и код выполняется правильно.
Что мне не хватает?
Вы пытаетесь смоделировать пользовательский ввод на рабочем столе, который не активен на физической консоли (экран, мышь, клавиатура), который вряд ли будет работать, и почему SwitchDesktop()
заставляет это работать. Согласно документации:
Делает указанный рабочий стол видимым и активирует его. Это позволяет рабочему столу получать входные данные от пользователя.
keybd_event()
, mouse_event()
, SendInput()
все они просто генерируют и сохраняют входные сообщения в той же очереди ввода, в которую физическая мышь / клавиатура публикует свои сообщения. Система ввода не знает разницы между пользовательским вводом и синтезированным вводом при отправке входных сообщений приложениям.
Раймонд Чен затронул это в своем блоге:
Как мне симулировать ввод без SendInput?
SendInput работает на нижнем уровне стека ввода. Это просто бэкдор в тот же механизм ввода, который используют драйверы клавиатуры и мыши, чтобы сообщить диспетчеру окон, что пользователь сгенерировал ввод. Функция SendInput не знает, что будет с входом. Это обрабатывается гораздо более высокими уровнями оконного менеджера, такими как компоненты, которые проверяют ввод мыши, чтобы увидеть, в какое окно сообщение должно быть первоначально доставлено.
Он также опубликовал небольшую диаграмму в другой статье блога, показывающую, где SendInput()
сидит относительно входной очереди:
Когда что-то добавляется в очередь, требуется время, чтобы оно вышло из очереди