首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >JNA / WinAPI.模拟鼠标点击而不移动光标不能正常工作

JNA / WinAPI.模拟鼠标点击而不移动光标不能正常工作
EN

Stack Overflow用户
提问于 2020-12-16 02:09:42
回答 1查看 757关注 0票数 1

编辑:对不起,但我不确定我的问题是否恰当地结束了。有人建议我这个线程,但它没有回答我的问题。我能够模拟鼠标点击,但它不能正常工作,正如我在我的问题中描述的。

我仍然在学习JNA,并在我的Java应用程序(JNA5.6.0和Java 5.6.0)中使用它,但我希望熟悉C语言的人也能理解我,因为JNA正在使用WinAPI函数。我的操作系统是Windows 10。

我所拥有的:

  • Swing应用程序启动魔兽争霸III游戏,运行游戏的exe文件。
  • 低级别键盘钩子拦截击键LowLevelKeyboardProc()并调用click()方法,如下所述。
  • 逻辑,应该模拟鼠标点击游戏窗口的坐标(库存,技能和控制位置),按下特定的(如下图所示)。

问题是我无法实现正确的执行鼠标点击游戏窗口的坐标。

我想预先说,我没有违反游戏的许可协议的规则,我想使用它只为个人目的的旧版本的游戏,1.26。另外,我在其他编程语言中也看到过类似的实现,但我想用Java实现它。

下面我附加了我尝试过的三个选项,并对问题进行了描述:

1。使用User32.INSTANCE.SendMessage()

代码语言:javascript
运行
复制
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()

代码语言:javascript
运行
复制
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()

代码语言:javascript
运行
复制
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毫秒,到需要单击并返回到起始位置的位置。

谢谢你把这篇文章读到最后,我为这么麻烦的解释道歉。

有人能告诉我我在代码中犯了什么和哪里的错误吗?因为在所有三个选项中,我没有达到预期的行为。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-12-28 07:40:37

对于第三种情况,您没有使用MOUSEEVENTF_MOVE标志来移动鼠标,因此鼠标实际上没有移动。同时也根据文档

如果指定了MOUSEEVENTF_ABSOLUTE值,则dxdy包含0到65,535之间的归一化绝对坐标。

代码语言:javascript
运行
复制
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_LEFTDOWNMOUSEEVENTF_LEFTUP单击当前位置。

也可以将鼠标直接合并到单击事件中:

代码语言:javascript
运行
复制
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返回位置。

代码语言:javascript
运行
复制
void click(int xCord, int yCord) {
    //mouseMove(xCord, yCord);
    POINT p = {};
    GetCursorPos(&p);
    mouseMoveClick(xCord, yCord);
    SetCursorPos(p.x, p.y);
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65316317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档