如何仅在目标游戏窗口处于顶层时渲染透明点击穿透覆盖层?
如何仅在目标游戏窗口处于顶层时渲染透明点击穿透覆盖层?
我之前做游戏悬浮层时也踩过一模一样的坑——子窗口模式虽然能自动跟着游戏状态走,但直接废掉了点击穿透;独立窗口又会在切窗口后还尬在那儿。给你几个亲测有效的解决办法:
核心思路:保持独立窗口+监听窗口激活状态
不把悬浮层设为游戏的子窗口,用独立窗口保留WS_EX_TRANSPARENT的点击穿透能力,同时通过系统事件监听来控制悬浮层的显示/渲染时机。
1. 用窗口事件钩子监听前台窗口切换
这比定时轮询效率高多了,能实时感知哪个窗口拿到焦点:
- 调用
SetWinEventHook注册EVENT_SYSTEM_FOREGROUND事件的钩子,回调函数里能拿到当前前台窗口的HWND。 - 在回调里对比这个HWND是不是你的目标游戏窗口:
- 如果是,就显示悬浮层(
ShowWindow(hOverlay, SW_SHOW)),并且同步游戏窗口的位置和大小到悬浮层(用GetWindowRect拿游戏窗口的RECT,再SetWindowPos设置悬浮层的位置大小)。 - 如果不是,就隐藏悬浮层(
ShowWindow(hOverlay, SW_HIDE))或者暂停渲染逻辑,避免无效绘制。
- 如果是,就显示悬浮层(
2. 确保悬浮层的窗口样式配置正确
要同时满足透明、点击穿透、不抢焦点这几个要求,窗口的扩展样式得配全:
DWORD exStyle = WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_NOACTIVATE; SetWindowLongPtr(hOverlay, GWL_EXSTYLE, exStyle);
WS_EX_LAYERED:支持分层透明,配合SetLayeredWindowAttributes还能调整透明度。WS_EX_TRANSPARENT:让窗口忽略鼠标点击,直接穿透到下层窗口。WS_EX_NOACTIVATE:悬浮层永远不会成为前台窗口,避免切窗口时抢占焦点。
3. 同步游戏窗口的位置和大小变化
光监听焦点切换还不够,游戏窗口移动、拉伸时悬浮层也得跟着动:
- 可以再注册
EVENT_OBJECT_LOCATIONCHANGE事件钩子,当游戏窗口的位置或大小改变时,自动同步悬浮层的参数。 - 或者在焦点切换的回调里,每次显示悬浮层时都做一次位置大小同步,简单粗暴但有效。
4. 处理游戏窗口最小化的情况
之前你说最小化时停止渲染是完美的,这个可以在监听里加上:用IsIconic判断游戏窗口状态,如果是最小化状态,直接隐藏悬浮层就行。
额外小技巧
- 在悬浮层的窗口过程里,处理
WM_NCHITTEST消息返回HTTRANSPARENT,双重保险确保点击穿透:
case WM_NCHITTEST: return HTTRANSPARENT;
- 不要让悬浮层接收任何键盘或鼠标消息,避免干扰游戏的输入。
这样一套下来,悬浮层既能保持点击穿透的能力,又能精准地只在游戏窗口处于顶层时显示/渲染,完美解决你的矛盾点~




