【发布时间】:2021-04-01 21:24:23
【问题描述】:
在我的 Java 代码中,我想在按下 Q 键时模拟在某些屏幕坐标 (x, y) 上的不可见鼠标点击。人眼应该不可见:鼠标移动->鼠标点击->鼠标向后移动。
我为此使用 JNA 5.6.0 和 jna-platform 5.6.0,它们使用原生 WinAPI 函数。我在LowLevelKeyboardProc() {callback()} 中实现了低级键盘钩子,它拦截击键。对于鼠标点击模拟,我使用的是SendInput()。
我预计鼠标点击应该在某些全局屏幕坐标(x,y)上完成。在我的代码示例中,坐标是 40、40。
但是我得到了而不是预期的结果:
- 鼠标移动和鼠标点击,但没有返回到点击前光标所在的起始位置。
- 鼠标移动并点击当前鼠标位置的坐标 40、40,而不是全局屏幕的坐标。
演示此行为的最佳方法是运行下面提供的代码,打开 Paint,选择画笔工具并按“Q”按钮。
看起来是这样的:
如您所见,第一次按 Q 按钮后光标不会移回起始位置。下次按下 Q 键时,点击点与当前鼠标位置之间的距离会更大,并且在第一次按下 Q 键后该距离会有所不同。
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.*;
import static com.sun.jna.platform.win32.WinUser.*;
public class TestExample {
public static final int MOUSEEVENTF_MOVE = 1;
public static final int MOUSEEVENTF_LEFTDOWN = 2;
public static final int MOUSEEVENTF_LEFTUP = 4;
private static WinUser.HHOOK hHook;
static final User32 user32Library = User32.INSTANCE;
static WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
public static void main(String[] args) {
keyReMapOn();
}
public static void keyReMapOn() {
WinUser.LowLevelKeyboardProc keyboardHook = new WinUser.LowLevelKeyboardProc() {
@Override
public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT kbDllHookStruct) {
if (nCode >= 0) {
if (wParam.intValue() == WM_KEYDOWN) {
if (kbDllHookStruct.vkCode == 81) { // Q button
clickByCord(40, 40);
return new WinDef.LRESULT(1);
}
}
}
Pointer ptr = kbDllHookStruct.getPointer();
long peer = Pointer.nativeValue(ptr);
return user32Library.CallNextHookEx(hHook, nCode, wParam, new WinDef.LPARAM(peer));
}
};
hHook = user32Library.SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHook, hMod, 0);
int result;
WinUser.MSG msg = new WinUser.MSG();
while ((result = user32Library.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
break;
} else {
user32Library.TranslateMessage(msg);
user32Library.DispatchMessage(msg);
}
}
}
public static void clickByCord(int x, int y) {
mouseMove(x, y);
mouseLeftClick(x, y);
}
static void mouseMove(int x, int y) {
mouseAction(x, y, MOUSEEVENTF_MOVE);
}
public static void mouseLeftClick(int x, int y) {
mouseAction(x, y, MOUSEEVENTF_LEFTDOWN);
mouseAction(x, y, MOUSEEVENTF_LEFTUP);
}
public static void mouseAction(int x, int y, int flags) {
INPUT input = new INPUT();
input.type = new DWORD(INPUT.INPUT_MOUSE);
input.input.setType("mi");
if (x != -1) {
input.input.mi.dx = new LONG(x);
}
if (y != -1) {
input.input.mi.dy = new LONG(y);
}
input.input.mi.time = new DWORD(0);
input.input.mi.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
input.input.mi.dwFlags = new DWORD(flags);
User32.INSTANCE.SendInput(new DWORD(1), new INPUT[]{input}, input.size());
}
}
我在某处的代码中犯了错误。
谁能告诉我如何在全局屏幕坐标上实现不可见的鼠标左键点击?
【问题讨论】: