编辑:对不起,但我不确定我的问题是否恰当地结束了。有人建议我这个线程,但它没有回答我的问题。我能够模拟鼠标点击,但它不能正常工作,正如我在我的问题中描述的。
我仍然在学习JNA,并在我的Java应用程序(JNA5.6.0和Java 5.6.0)中使用它,但我希望熟悉C语言的人也能理解我,因为JNA正在使用WinAPI函数。我的操作系统是Windows 10。
我所拥有的:
LowLevelKeyboardProc()
并调用click()
方法,如下所述。
问题是我无法实现正确的执行鼠标点击游戏窗口的坐标。
我想预先说,我没有违反游戏的许可协议的规则,我想使用它只为个人目的的旧版本的游戏,1.26。另外,我在其他编程语言中也看到过类似的实现,但我想用Java实现它。
下面我附加了我尝试过的三个选项,并对问题进行了描述:
1。使用User32.INSTANCE.SendMessage()
public void click(KeyBindComponent keyBindComponent) {
final int WM_LBUTTONDOWN = 513;
final int WM_LBUTTONUP = 514;
final int MK_LBUTTON = 0x0001;
Map<String, Integer> cords = getCords(keyBindComponent);
if (!cords.isEmpty()) {
int xCord = cords.get("width");
int yCord = cords.get("height");
LPARAM lParam = makeLParam(xCord, yCord);
user32Library.SendMessage(warcraft3hWnd, WM_LBUTTONDOWN, new WPARAM(MK_LBUTTON), lParam);
user32Library.SendMessage(warcraft3hWnd, WM_LBUTTONUP, new WPARAM(MK_LBUTTON), lParam);
System.out.println("x = " + xCord + " y = " + yCord);
}
}
public static LPARAM makeLParam(int l, int h) {
// note the high word bitmask must include L
return new LPARAM((l & 0xffff) | (h & 0xffffL) << 16);
}
预计将对测试坐标点(在建筑物上)进行不可见的单击。但是问题的是这个区域被分配了。我假设执行了以下顺序:单击С中的鼠标、urrent、鼠标位置,并将光标移动到С坐标点,单击。但我不知道为什么会这样。
2.使用User32.INSTANCE.PostMessage()
的
public void click(KeyBindComponent keyBindComponent) {
final int WM_LBUTTONDOWN = 513;
final int WM_LBUTTONUP = 514;
Map<String, Integer> cords = getCords(keyBindComponent);
if (!cords.isEmpty()) {
int xCord = cords.get("width");
int yCord = cords.get("height");
LPARAM lParam = makeLParam(xCord, yCord);
user32Library.PostMessage(warcraft3hWnd, WM_LBUTTONDOWN, new WPARAM(0), lParam);
user32Library.PostMessage(warcraft3hWnd, WM_LBUTTONUP, new WPARAM(0), lParam);
System.out.println("x = " + xCord + " y = " + yCord);
}
}
public static LPARAM makeLParam(int l, int h) {
// note the high word bitmask must include L
return new LPARAM((l & 0xffff) | (h & 0xffffL) << 16);
}
相同的情况发生了,而不是点击坐标,该区域被选中,以及在SendMessage()
的情况下,我可能不会再附加图片两次。
3.使用User32.INSTANCE.SendInput()
的
public void click(KeyBindComponent keyBindComponent) {
Map<String, Integer> cords = getCords(keyBindComponent);
if (!cords.isEmpty()) {
int xCord = cords.get("width");
int yCord = cords.get("height");
mouseMove(xCord, yCord);
mouseClick();
System.out.println("x = " + xCord + " y = " + yCord);
}
}
void mouseMove(int x, int y) {
final int MOUSEEVENTF_LEFTUP = 0x0004;
final int MOUSEEVENTF_ABSOLUTE = 0x8000;
INPUT input = new INPUT();
INPUT[] move = (INPUT[]) input.toArray(2);
// Release the mouse before moving it
move[0].type = new DWORD(INPUT.INPUT_MOUSE);
move[0].input.setType("mi");
move[0].input.mi.dwFlags = new DWORD(MOUSEEVENTF_LEFTUP);
move[0].input.mi.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
move[0].input.mi.time = new DWORD(0);
move[0].input.mi.mouseData = new DWORD(0);
move[1].type = new DWORD(INPUT.INPUT_MOUSE);
move[1].input.mi.dx = new LONG(x);
move[1].input.mi.dy = new LONG(y);
move[1].input.mi.mouseData = new DWORD(0);
move[1].input.mi.dwFlags = new DWORD(MOUSEEVENTF_LEFTUP + MOUSEEVENTF_ABSOLUTE);
user32Library.SendInput(new DWORD(2), move, move[0].size());
}
void mouseClick() {
final int MOUSEEVENTF_LEFTUP = 0x0004;
final int MOUSEEVENTF_LEFTDOWN = 0x0002;
INPUT input = new INPUT();
INPUT[] click = (INPUT[]) input.toArray(2);
click[0].type = new DWORD(INPUT.INPUT_MOUSE);
click[0].input.setType("mi");
click[0].input.mi.dwFlags = new DWORD(MOUSEEVENTF_LEFTDOWN);
click[0].input.mi.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
click[0].input.mi.time = new DWORD(0);
click[0].input.mi.mouseData = new DWORD(0);
click[1].type = new DWORD(INPUT.INPUT_MOUSE);
click[1].input.setType("mi");
click[1].input.mi.dwFlags = new DWORD(MOUSEEVENTF_LEFTUP);
click[1].input.mi.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
click[1].input.mi.time = new DWORD(0);
click[1].input.mi.mouseData = new DWORD(0);
user32Library.SendInput(new DWORD(2), click, click[0].size());
}
在这种情况下,在坐标点上根本没有点击。相反,当按下某些键时,鼠标在当前鼠标位置中单击。
顺便说一句,我也尝试过使用Java 机器人,但它对我不起作用。不幸的是,鼠标光标从起始位置移动(消失)大约1毫秒,到需要单击并返回到起始位置的位置。
谢谢你把这篇文章读到最后,我为这么麻烦的解释道歉。
有人能告诉我我在代码中犯了什么和哪里的错误吗?因为在所有三个选项中,我没有达到预期的行为。
发布于 2020-12-28 07:40:37
对于第三种情况,您没有使用MOUSEEVENTF_MOVE
标志来移动鼠标,因此鼠标实际上没有移动。同时也根据文档
如果指定了
MOUSEEVENTF_ABSOLUTE
值,则dx和dy包含0到65,535之间的归一化绝对坐标。
void mouseMove(int x, int y) {
INPUT move[2] = {};
DWORD fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
move[0].type = move[1].type = INPUT_MOUSE;
move[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;// Release the mouse before moving it
move[1].mi.dx = MulDiv(x, 65535, fScreenWidth);
move[1].mi.dy = MulDiv(y, 65535, fScreenHeight);
move[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
SendInput(2, move, sizeof(INPUT));
}
然后使用MOUSEEVENTF_LEFTDOWN
和MOUSEEVENTF_LEFTUP
单击当前位置。
也可以将鼠标直接合并到单击事件中:
void mouseMoveClick(int x, int y) {
INPUT click[3] = {};
click[0].type = INPUT_MOUSE;
click[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;// Release the mouse before moving it
DWORD fScreenWidth = ::GetSystemMetrics(SM_CXSCREEN);
DWORD fScreenHeight = ::GetSystemMetrics(SM_CYSCREEN);
click[1].type = INPUT_MOUSE;
click[1].mi.dx = click[2].mi.dx= MulDiv(x, 65535, fScreenWidth);
click[1].mi.dy = click[2].mi.dy= MulDiv(y, 65535, fScreenHeight);
click[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
click[2].type = INPUT_MOUSE;
click[2].mi.dwFlags = MOUSEEVENTF_LEFTUP | MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
SendInput(3, click, sizeof(INPUT));
}
如果要在鼠标单击后移回原来的位置,则可以在移动之前使用GetCursorPos
记录当前位置。然后使用mouseMove事件或更简单的SetCursorPos
返回位置。
void click(int xCord, int yCord) {
//mouseMove(xCord, yCord);
POINT p = {};
GetCursorPos(&p);
mouseMoveClick(xCord, yCord);
SetCursorPos(p.x, p.y);
}
https://stackoverflow.com/questions/65316317
复制相似问题