新建桌面收不到键盘事件

Newly created desktop doesn't receive keyboard events

我创建了一个可以在新桌面上自行启动的小程序。

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)获得的自身位置。

新创建的应用程序获取另一个 window 的 HWND 并使用以下命令发送 window 消息:

// 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 默认启动桌面 X 上的应用程序 B,它获得另一个应用程序 C 在同一个桌面 X 上启动的 HWND。

我的问题是桌面 X 上来自应用程序 B 的键盘事件没有在应用程序 C 中触发。只有当我使用 SwitchDesktop(B) 时,才会触发事件并正确执行代码。

我错过了什么?

您正在尝试在物理控制台(屏幕、鼠标、键盘)上未激活的桌面上模拟用户输入,这不太可能起作用,以及为什么 SwitchDesktop() 使其起作用。根据文档:

SwitchDesktop function

Makes the specified desktop visible and activates it. This enables the desktop to receive input from the user.

keybd_event()mouse_event()SendInput(),它们都简单地生成输入消息并将其存储到物理 mouse/keyboard post 它们的同一个输入队列中消息到。在将输入消息分派给应用程序时,输入系统不知道用户输入和合成输入之间的区别。

Raymond Chen 在他的博客中谈到了这一点:

How do I simulate input without SendInput?

SendInput operates at the bottom level of the input stack. It is just a backdoor into the same input mechanism that the keyboard and mouse drivers use to tell the window manager that the user has generated input. The SendInput function doesn't know what will happen to the input. That is handled by much higher levels of the window manager, like the components which hit-test mouse input to see which window the message should initially be delivered to.

他还在另一篇博客文章中 post 绘制了一个漂亮的小图表,显示 SendInput() 相对于输入队列的位置:

When something gets added to a queue, it takes time for it to come out the front of the queue