Я хотел бы имитировать «настоящие» нажатия клавиш в неактивном окне. После некоторых исследований я нашел Windows API. Так как я привык к Java, я быстро нашел JNA, которая реализует winapi. Я написал некоторый код, который мог имитировать нажатия клавиш в активном окне с помощью метода sendInput(). Окно не обнаружило виртуальные коды клавиш. После некоторого поиска окна с прямым вводом, очевидно, нуждаются в скан-кодах. И это работало со следующим кодом:
import com.sun.jna.platform.win32.BaseTSD;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinUser;
int KEYEVENT_SCANCODE = 0x0008;
int KEYEVENT_UP = 0x0002;
WinUser.INPUT input = new WinUser.INPUT();
input.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
input.input.setType("ki");
input.input.ki.wVk = new WinDef.WORD(0);// 0 cause scancodes are used
input.input.ki.time = new WinDef.DWORD(0);
input.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
input.input.ki.wScan = new WinDef.WORD(0x2C); // scancode for 'y'
input.input.ki.dwFlags = new WinDef.DWORD(KEYEVENT_SCANCODE); // keydown
User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
input.input.ki.wScan = new WinDef.WORD(0x2C);
input.input.ki.dwFlags = new WinDef.DWORD(KEYEVENT_SCANCODE | KEYEVENT_UP); // keyup
User32.INSTANCE.SendInput(new WinDef.DWORD(1), (WinUser.INPUT[]) input.toArray(1), input.size());
Теперь я хотел, чтобы он был «гладким», чтобы окно могло быть в фоновом режиме или свернуто. Я нашел SendMessage() и методы PostMessage() и думал, что понял его концепции. Вы передаете обработчику окна сообщение (wm_keydown и wm_keyup кажутся подходящими для этой задачи) и и его конкретные параметры.
Я пробовал это, но это не сработало. (то же самое для postMessage).
User32.INSTANCE.SendMessage(handler, WinUser.WM_KEYDOWN, new WinDef.WPARAM(0x5A), new WinDef.LPARAM(0x002C0001));
Thread.sleep(100); //tried with and without
User32.INSTANCE.SendMessage(handler, WinUser.WM_KEYUP, new WinDef.WPARAM(0x5A), new WinDef.LPARAM(0xC02C0001));
Затем я попробовал WM_CHAR, и это частично сработало. Это работало в чате окна, но не вызывало горячих клавиш. После некоторых исследований люди говорят, что вы должны использовать перехватчики прямого ввода (?), поскольку некоторые окна не распознают сообщения от winapi, но мое, по-видимому, распознало от sendInput и sendMessage с WM_CHAR.
Я передал неправильные параметры? Что значит, что wm_char распознан, а wm_keydown и wm_keyup нет?
Я уже нашел множество примеров на стейк-оверфлоу и в Интернете, но это не особо помогло. Спасибо, что прочитали и ответили.
@update Я использовал инструмент для обнаружения сообщений. Сообщения, созданные реальными нажатиями клавиш, и сообщения, созданные из кода, равны:
В обоих случаях есть WM_keydown, затем WM_char и WM_keyup. Каждый параметр каждого сообщения равен. В дополнение к этому, как я уже сказал, если чат открыт, там пишутся символы, но действия не будут выполняться, когда чат закрыт. Я проверил, какие сообщения отправляются методом sendInput(): они аналогичны обоим случаям выше, но действие выполняется. Я не могу понять это поведение.
SendInput()
для имитации аппаратных событий клавиатуры, это единственный вариант для этого. Просто не существует официального, стандартного способа отправить ввод с клавиатуры в скрытое/неактивное окно. - person Remy Lebeau   schedule 22.01.2019User32.INSTANCE.SendMessage(handler, WinUser.WM_KEYDOWN, new WinDef.WPARAM(0x5A), new WinDef.LPARAM(0x002C0001)); User32.INSTANCE.SendMessage(handler, WinUser.WM_KEYUP, new WinDef.WPARAM(0x5A), new WinDef.LPARAM(0xC02C0001));
вы не можете получить ни WM_KEYDOWN, ни WM_KEYUP, за исключением того, что вы дополнительно отправляете WM_CHAR? - person Rita Han   schedule 23.01.2019