Добрый день. Столкнулся с проблемой, что не работают макросы с привязкой к окну клиента в свернутом режиме (без фокуса). По моим исследованиям в течении пары дней выяснилось:
1) Дескриптор родительского окна определяется некорректно, точнее он не верен с точки зрения самого клиента (L2UnrealW...)
2) Ручные события по HWND окна отрабатывают 1 раз и после блокируется очередь (почему - неизвестно)
3) Для того чтобы макрос начал работать, нужно проинициализировать фейковые события SendInput на активное окно 1 раз на все бинды и в дальнейшем работать с событиями KEY_DOWN|KEY_UP
Рабочая реализация с помощью JNA:
public static void main(String[] args) {
final int[][] MACRO = {
{KeyEvent.VK_F5, 2},
{KeyEvent.VK_F2, 2},
{KeyEvent.VK_F3, 2},
{KeyEvent.VK_5, 2},
{KeyEvent.VK_7, 2},
{KeyEvent.VK_F7, 2}
};
String WINDOW_NAME = "Lineage II";
final Map<HWND, String> windows = Windows.getWindows();
HWND process = null;
for (HWND key : windows.keySet()) {
final String windowName = windows.get(key);
if (windowName.equals(WINDOW_NAME)) {
process = key;
break;
}
}
Arrays.stream(MACRO_dd).forEach(keys -> {
final int keyId = keys[0];
sendFirstInput(keyId);
});
executor.scheduleAtFixedRate(() -> {
Arrays.stream(MACRO).forEach(keys -> {
final int keyId = keys[0];
final int count = keys[1];
if (count > 1) {
IntStream.range(0, count).forEach(c -> {
pressKey(process, keyId);
});
} else {
pressKey(process, keyId);
}
});
}, 0, 350, TimeUnit.MILLISECONDS);
}
private static void sendFirstInput(int c) {
final WinUser.INPUT input = new WinUser.INPUT();
input.type = new DWORD(WinUser.INPUT.INPUT_KEYBOARD);
input.input.setType("ki");
input.input.ki.wScan = new WORD(0);
input.input.ki.time = new DWORD(0);
input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
input.input.ki.wVk = new WORD(c);
input.input.ki.dwFlags = new DWORD(0); // keydown
User32.instance.SendInput(new DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
}
/**
* Sends a key-down input followed by a key-up input for the given character
* value c.
*/
private static void pressKey(HWND hwnd, int c) {
sendKeyDown(hwnd, c);
sendKeyUp(hwnd, c);
}
private static void sendKeyDown(HWND hwnd, int c) {
User32.instance.SendMessage(hwnd, WM_KEYDOWN, new WPARAM(c), new LPARAM(0));
}
private static void sendKeyUp(HWND hwnd, int c) {
User32.instance.PostMessage(hwnd, WM_KEYUP, new WPARAM(c), new LPARAM(0));
}
Примечания:
* LPARAM по битовой маске события не обрабатываются клиентом
** События в свернутом окне отрабатывают каждый тик клиента (0.5с - 1с), что есть не очень хорошо и соответствует ручному нажатию кнопки в игре. т.е. профит от бота есть только в активном окне
P.S. переместите в соответствующий раздел, т.к. такового я не нашел для такого рода информации.