我正在编写一个 C++ Windows 程序,它使用 Win32 窗口和 DirectX11 渲染器显示游戏的游戏统计信息/好友信息。 (呈现一个用鼠标和键盘控制的用户界面)
窗口覆盖在游戏窗口的顶部,并设置了标志 WS_EX_TRANSPARENT 和 WS_POPUP。 当窗口被激活时,我设置 WS_EX_LAYERED 来捕获输入。
如果GetWindow(target_, GW_HWNDPREV) 与创建窗口的句柄不同,则创建窗口位于目标窗口之上。 通过使用 SWP_NOACTIVATE | 调用 SetWindowPos 将其放置在其之上。 SWP_NOMOVE | SWP_NOSIZE | SWP_ASYNCWINDOWPOS.
我已经仔细检查了标志设置是否正确以及函数是否被调用。 我也尝试使用带有 SW_SHOW 标志的 ShowWindow,但结果保持不变。
我目前正在 Portal 2 上运行我的测试,但理想情况下,我希望它适用于大多数游戏。 (使用的操作系统是Windows 11 22H2)
为了激活窗口并从游戏中释放鼠标捕获,我调用了 SetForegroundWindow、SetActiveWindow 和 SetFocus,所有这些都带有我窗口的 HWND。 当我从 Visual Studio 运行程序时,这种方法工作正常,但是当我运行编译后的可执行文件时,鼠标在游戏中保持锁定状态。
两个版本都在调试和发布模式下进行了测试,我真的不明白为什么会这样。
LRESULT Renderer::WndProc(...) {
switch (message) {
case WM_SIZE:
// resize buffers and recreate render target view
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(handle, message, w_param, l_param);
}
bool Window::Create(...) {
// ...
hwnd_ = CreateWindowEx(
wndclass,
class_name_.c_str(),
title_.c_str(),
WS_POPUP,
0, 0, 10, 10,
nullptr,
nullptr,
nullptr,
nullptr
);
SetLayeredWindowAttributes(hwnd_, 0, 255, LWA_ALPHA);
UpdateWindow(hwnd_);
constexpr MARGINS margin = {-1, -1, -1, -1};
const auto result = DwmExtendFrameIntoClientArea(hwnd_, &margin);
// ...
}
void Window::Activate() {
// Remove the WS_EX_LAYERED attribute.
SetClickThrough(false);
SetForegroundWindow(hwnd_);
SetActiveWindow(hwnd_);
SetFocus(hwnd_);
}
// ----------------------
// Sample main routine pseudocode:
// ----------------------
renderer->window.Create(...);
while (renderer->is_running()) {
renderer->BeginFrame();
// Position the window on top of the game found.
renderer->window().FollowTarget();
// Toggle the visibility using the F2 key.
// If transitioning from hidden to visible, call the window
// activation routine.
if (utils::KeyPressed(VK_F2)) {
if (ui->is_visible()) {
// .. window deactivation not included
ui->set_visible(false);
}
else {
renderer->window().Activate();
ui->set_visible(true);
}
}
ui->Draw(renderer);
renderer->Present();
}
我考虑过使用低级键盘/鼠标钩子来捕获输入,或使用 DirectX 钩子进行屏幕外渲染并在游戏中呈现它,但我宁愿避免使用它,因为它需要许多游戏手动将其列入白名单。
还有什么我想念的或者我应该采取不同的方法吗?