[英]MOUSEEVENTF_MOVE doesn't move to correct coordinates in-game
Feel like I am bashing my head against the wall here so wanted to reach out and see if there is some easy solution I am missing first before I go crazy.感觉就像我在这里用头撞墙,所以想伸出手看看是否有一些简单的解决方案,在我 go 发疯之前先错过。
The problem:问题:
Code:代码:
#include <iostream>
#include <Windows.h>
using namespace std;
//Magic number defines
const float constant = 0.116f;
float mouseSensitivity = 10.0f;
float modifier = mouseSensitivity * constant;
int centerScreenX = GetSystemMetrics(SM_CXSCREEN) / 2;
int centerScreenY = GetSystemMetrics(SM_CYSCREEN) / 2;
//Move mouse to center of screen
void centerMouse() {
SetCursorPos(centerScreenX, centerScreenY);
cout << "Moving to center of screen at(" << centerScreenX << ", " << centerScreenY << ")" << endl;
}
//Calculates actual coordinates for mouse movement based on sensitivity and a constant.
void calibrateCoordinates(int& x, int& y)
{
if (abs(x) < 5)
x = 0;
else {
x = x - centerScreenX;
x = (int)((float)x / modifier);
}
if (abs(y) < 5)
y = 0;
else
{
y = y - centerScreenY;
y = (int)((float)y / modifier);
}
cout << "Coordinates needed to move by (" << x << ", " << y << ")" << endl;
}
// Moves to x,y coordinates after processed into actual coordinates based on sensitivity and a constant.
void moveTo(int x, int y)
{
SetProcessDPIAware();
calibrateCoordinates(x, y);
mouse_event(MOUSEEVENTF_MOVE, x, y, 0, 0);
//Sanity check where the mouse ended up at
POINT p;
if (GetCursorPos(&p))
{
cout << "Mouse ended up at (" << p.x << ", " << p.y << ")" << endl;
}
}
int main() {
while (true) {
// Check if the F19 button is pressed
if (GetAsyncKeyState(VK_F19) & 0x8000) {
//Hardcoded values of pixel we need to move to. Handled automatically via OpenCV in the real code. Simplified here
int xTo = 784;
int yTo = 686;
//Centers mouse to line up cursor with crosshair
centerMouse();
//Tries to move to coords
moveTo(xTo, yTo);
}
}
return 0;
}
Output: Output:
Matched pixel found at (784, 686)[4, 20, 222, 255] Moving to center of screen at (1280, 720) Coordinates needed to move by (-271, -20) Mouse ended up at (1009, 700)
匹配像素位于 (784, 686)[4, 20, 222, 255] 移动到屏幕中心 (1280, 720) 坐标需要移动 (-271, -20) 鼠标最终位于 (1009, 700)
The mouse should have ended up at (1012, 649) for the cross-hair to line up with the pixel I want.鼠标应该在 (1012, 649) 结束,以便十字准线与我想要的像素对齐。 Do I just need to keep experimenting to find the magic number that it works with?
我是否只需要继续试验以找到它适用的神奇数字? Or is there any easier way to do this?
还是有更简单的方法来做到这一点? Thanks
谢谢
GetSystemMetrics
function is not DPI aware. GetSystemMetrics
function 不支持 DPI。 Use GetSystemMetricsForDpi instead to get a correct result.请改用GetSystemMetricsForDpi以获得正确的结果。
Disclaimer: Sorry if this isn't an answer but I can't comment yet because of my low rep.免责声明:抱歉,如果这不是答案,但由于我的代表率低,我还不能发表评论。
mouse_event(MOUSEEVENTF_MOVE, coordinates.x - interfaceinfo->D3D9Viewport.Width * 0.5f, coordinates.y - interfaceinfo->D3D9Viewport.Height * 0.5f, 0, 0);
The coordinates
is the target's position, while interfaceinfo->D3D9Viewport.Width/Height
is the screen info given by the DX9, in this case using **IDirect3DDevice9::GetViewport**
coordinates
是目标的 position,而interfaceinfo->D3D9Viewport.Width/Height
是 DX9 给出的屏幕信息,在这种情况下使用**IDirect3DDevice9::GetViewport**
HRESULT WINAPI Renderer::hkPresent(LPDIRECT3DDEVICE9 pDevice, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
renderer->Device_D3D9 = pDevice;
Device_D3D9->GetViewport(&interfaceinfo->D3D9Viewport);
return renderer->oPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
HRESULT WINAPI Renderer::hkGetDeviceState(IDirectInputDevice8A* DIDevice, DWORD cbData, LPVOID *lpvData) {
HRESULT hResult = renderer->oGetDeviceState(DIDevice, cbData, lpvData);
if (interfaceinfo->bCurrentWindow >= 1) {
if (hResult == DI_OK) {
for (auto i = 0; i < cbData; i++) {
lpvData[i] = 0;
}
}
}
static BYTE buffer[256];
if (true) {
buffer[DIK_W] = LOBYTE(0x80);
buffer['w'] = LOBYTE(0x80);
buffer['W'] = LOBYTE(0x80);
cbData = 256;
memcpy(lpvData, buffer, cbData);
}
else {
hResult = renderer->oGetDeviceState(DIDevice, cbData, lpvData);
}
return hResult;
}
HRESULT WINAPI Renderer::hkGetDeviceData(IDirectInputDevice8A* DIDevice, DWORD cbObjectData, LPDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, DWORD dwFlags) {
HRESULT ret = renderer->oGetDeviceData(DIDevice, cbObjectData, rgdod, pdwInOut, dwFlags);
if (ret == DI_OK) {
for (DWORD i = 0; i < *pdwInOut; ++i) {
if (interfaceinfo->bCurrentWindow >= 1) {
*pdwInOut = 0;
}
else {
switch (rgdod[i].dwOfs) {
case DIK_W:
rgdod[i].dwData = LOBYTE(0x80);
break;
case DIK_SPACE: {
static byte last_written = 0;
rgdod[i].dwData = HIBYTE(last_written ? 0x01 : 0x00);
last_written = last_written ? 0x00 : 0x01;
break;
}
}
}
}
}
return ret;
}
First of all, you appear to be passing absolute coordinates to the function mouse_event
, but that function is interpreting them as coordinates relative to the last mouse position, because you are not passing the MOUSEEVENTF_ABSOLUTE
flag to mouse_event
.首先,您似乎将绝对坐标传递给 function
mouse_event
,但 function 将它们解释为相对于最后一个鼠标 position 的坐标,因为您没有将MOUSEEVENTF_ABSOLUTE
标志传递给mouse_event
。 Therefore, if you want to pass absolute coordinates, you should also pass that flag.因此,如果你想传递绝对坐标,你也应该传递那个标志。 Also, Microsoft recommends that you use
SendInput
instead of mouse_event
.此外,Microsoft 建议您使用
SendInput
而不是mouse_event
。
Another issue is the following:另一个问题如下:
The official Microsoft documentation for the function GetSystemMetrics
states the following: function
GetSystemMetrics
的官方 Microsoft 文档说明如下:
This API is not DPI aware, and should not be used if the calling thread is per-monitor DPI aware.
此 API 不是 DPI 感知的,如果调用线程是每个显示器的 DPI 感知的,则不应使用。 For the DPI-aware version of this API, see GetSystemMetricsForDPI .
有关此 API 的 DPI 感知版本,请参阅GetSystemMetricsForDPI 。 For more information on DPI awareness, see the Windows High DPI documentation .
有关 DPI 感知的更多信息,请参阅Windows 高 DPI 文档。
Therefore, the results of the lines因此,线条的结果
int centerScreenX = GetSystemMetrics(SM_CXSCREEN) / 2;
int centerScreenY = GetSystemMetrics(SM_CYSCREEN) / 2;
are possibly incorrect.可能不正确。 I suggest that you change these lines to the following:
我建议您将这些行更改为以下内容:
int centerScreenX = GetSystemMetricsForDpi( SM_CXSCREEN, GetDpiForSystem() ) / 2;
int centerScreenY = GetSystemMetricsForDpi( SM_CYSCREEN, GetDpiForSystem() ) / 2;
However, the function GetDpiForSystem
will simply return the value 96
unless the process or thread is made DPI-aware beforehand.但是,function
GetDpiForSystem
将简单地返回值96
,除非进程或线程事先设置为 DPI 感知。 Therefore, it is important that you call the function SetProcessDPIAware
before calling the function GetDPIForSystem
.因此,在调用 function
GetDPIForSystem
之前调用 function SetProcessDPIAware
非常重要。 Alternatively, you can set the default DPI awareness through an application manifest setting, as described here .或者,您可以通过应用程序清单设置来设置默认 DPI 感知,如此处所述。
According to this Microsoft documentation , there are currently 4 different modes of DPI awareness:根据这个 Microsoft 文档,目前有 4 种不同的 DPI 感知模式:
Since you are using the function SetProcessDPIAware
, you are setting the DPI awareness mode of your process to "System".由于您使用的是 function
SetProcessDPIAware
,因此您正在将进程的 DPI 感知模式设置为“系统”。 This mode will only make your process aware of the DPI on the primary monitor at the time the user logged in. If the DPI was changed since then, then your process will be unaware of these changes.此模式只会让您的进程在用户登录时了解主监视器上的 DPI。如果此后更改了 DPI,那么您的进程将不知道这些更改。 For this reason, you may want to consider using "Per-Monitor V2" DPI-awareness instead, by using the function
SetProcessDpiAwarenessContext
or SetThreadDpiAwarenessContext
.出于这个原因,您可能需要考虑使用“Per-Monitor V2”DPI 感知,通过使用 function
SetProcessDpiAwarenessContext
或SetThreadDpiAwarenessContext
。 However, this will require your application to handle WM_DPICHANGED
messages.但是,这将要求您的应用程序处理
WM_DPICHANGED
消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.