RDP只发送鼠标的绝对位置, 这导致在远程桌面中, 像《原神》这样依赖于鼠标的相对位移的3D游戏无法操作(无法转动视角)。
本项目通过两个hook,实现了在远程桌面中输入相对位移,从而可以在远程桌面中玩一些游戏。在《原神》中的测试体验良好。
-
原理
使用远程桌面时,当本地鼠标的位置发生变化时,远程主机会收到包含绝对位置信息的输入。本项目通过鼠标钩子在远程主机上拦截此输入,并生成包含相对位移的输入,从而可以控制游戏。由于只有本地鼠标位置发生变化时,远程主机才收到输入,如果鼠标位于边界/角落,即使移动了鼠标,鼠标的位置没有发送变化,远程主机也不会收到输入。为了解决这一问题,又在本地计算机运行了一个鼠标钩子,当鼠标移动到屏幕边界时,使其出现在屏幕的另一边,循环往复,从而保证本地鼠标的位置始终可以变化。
-
使用
编译两个可执行程序,并且在不同的计算机上运行:
MouseLoop.exe
在本地计算机上运行。运行后,当鼠标移动到屏幕边界时,会从另一边出来。RelativeMove.exe
在远程主机上运行,需要以管理员权限运行,运行后,就可以控制像《原神》这样的游戏了。使用不同的客户端连接到远程主机后,应该重启此程序,以保证获取到的屏幕分辨率正确。
-
一些实现细节
- 程序中用到了
MSLLHOOKSTRUCT
和GetCursorPos/SetCursorPos
,它们所使用的鼠标坐标的尺度(屏幕的分辨率)不同,分别是通过GetDeviceCaps
和GetSystemMetrics
获取的,前者是显示器的物理分辨率,后者是应用程序感知到的分辨率,二者之间相差的倍数为系统的缩放倍数。 - 远程主机上使用
SendInput
函数发送相对移动信息,这一信息同样会被鼠标钩子拦截,可以通过flag的值判断是否为SendInput
发送。并且,即使不把这一信息传递给下一个钩子,《原神》依然能够读取到这一输入。所以在实现时,没有把这一信息传递给下一个钩子,避免了本地鼠标和远程鼠标错位的情况。而且,没有传递给下一个钩子,将不会对其他大多数程序产生影响,保证了其他大多数程序仍可正常使用。
- 程序中用到了