【问题标题】:Newly created desktop doesn't receive keyboard events新创建的桌面不接收键盘事件
【发布时间】:2015-01-08 13:47:35
【问题描述】:

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

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);

pathModuleNameGetModuleFileName(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);
...

所以基本上桌面 DEFAULT 上的应用程序 A 是在桌面 X 上启动应用程序 B,它获得另一个应用程序 C 在同一个桌面 X 上启动的 HWND。

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

我错过了什么?

【问题讨论】:

    标签: c++ winapi window-messages


    【解决方案1】:

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

    SwitchDesktop function

    使指定的桌面可见并激活它。 这使桌面能够接收来自用户的输入。

    keybd_event()mouse_event()SendInput(),它们都只是简单地生成输入消息并将其存储到物理鼠标/键盘将消息发送到的相同输入队列中。在将输入消息分派给应用程序时,输入系统不知道用户输入和合成输入之间的区别。

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

    How do I simulate input without SendInput?

    SendInput 在输入堆栈的底层运行。 它只是进入键盘和鼠标驱动程序用来告诉窗口管理器用户已生成输入的相同输入机制的后门。 SendInput 函数不知道输入会发生什么。这是由更高级别的窗口管理器处理的,例如命中测试鼠标输入以查看消息最初应该传递到哪个窗口的组件。

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

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

    【讨论】:

    • 同一问题的另一个例子是,当计算机被锁定时,模拟输入(甚至一些窗口消息)将无法按预期工作。
    • 对,因为当计算机被锁定时,它会向用户显示一个单独的(安全)桌面,因此只有该桌面可以处理输入事件,直到计算机被解锁。
    • 感谢您的详细回复,我听说通过创建带有交互式桌面的非交互式窗口站可以实现这一目标。这样做,我可以在隐藏的桌面上启动一个隐藏的进程。
    • Windows 10 是否有任何改变?如果有一个 API 调用,我们可以将桌面指定为 SendInput 到,那就太好了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多