通过 JNA 向隐藏窗口发送击键
Posted
技术标签:
【中文标题】通过 JNA 向隐藏窗口发送击键【英文标题】:Sending Keystrokes to Hidden Window via JNA 【发布时间】:2019-06-11 11:34:51 【问题描述】:背景:
我将击键发送到我隐藏的程序(文本编辑器),然后发送 F7 键,然后发送四个文本键(一种密码)。我正在使用 JNA 库和 Win32API 的 SendMessage 函数发送消息,不能使用 sendInput() 因为我需要发送到特定的窗口句柄。
代码:
private static void sendInputToWindow(WinDef.HWND editorWindowHandle, char[] password) throws InterruptedException
User32.INSTANCE.ShowWindow(editorWindowHandle, WinUser.SW_HIDE);
User32.INSTANCE.SetForegroundWindow(editorWindowHandle);
User32.INSTANCE.SetFocus(editorWindowHandle);
//F7 KEY SENT
WinDef.WPARAM wparam = new WinDef.WPARAM(F7_VIRTUAL_KEY);
WinDef.LPARAM lparam = new WinDef.LPARAM(0);
log.debug("SENDING F7");
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_KEYDOWN, wparam, lparam);
Thread.sleep(1000);
log.debug("SENDING PASSWORD");
// PASSWORD SENT
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_CHAR, new WinDef.WPARAM(password[0]), lparam);
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_CHAR, new WinDef.WPARAM(password[1]), lparam);
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_CHAR, new WinDef.WPARAM(password[2]), lparam);
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_CHAR, new WinDef.WPARAM(password[3]), lparam);
Thread.sleep(500);
log.debug("SENDING ENTER");
// ENTER KEY SENT
User32.INSTANCE.SendMessage(editorWindowHandle, WinUser.WM_KEYDOWN, new WinDef.WPARAM(ENTER_KEY), lparam);
问题:
当我通过 SendMessage 发送击键时,经过一段时间或随机发送(我不知道是什么导致了这里的问题),但有时它根本不发送击键!
所以这是一个命中或未命中的情况,大多数情况下它会发送击键,而其他时候则不会。我想知道是否有更好的方法将击键发送到隐藏窗口?或者我在这里做错了什么。
谢谢。
【问题讨论】:
没有单一的机制可以做到这一点。SendInput
是受支持的伪造输入方式。其他任何事情都只是黑客行为。当然,您不能指望直接发送WM_CHAR
消息。究竟什么对你有用取决于目标(又名受害者)窗口。正如我们在这里看到的大量输入伪造问题中经常出现的情况一样,重要的细节被省略了。例如,如果这只是一个 Win32 编辑控件,您可以使用WM_SETTEXT
。但我们实际上并不知道这个控件到底是什么。
如果您确实想自动化 UI,可以使用 UI Automation。
@IInspectable 是否可以通过 Java 库(如在 JNA 中)使用,还是我必须为此使用 JNI?
UI 自动化作为一组 COM 对象公开。 COM 与语言无关。我会惊讶地发现,没有用于 COM 的 JNA 包装器,甚至没有预构建的 UI 自动化库(如 this 之一)。
LPCWSTR Target_window_Name = TEXT("print.txt - Notepad"); HWND hWindowHandle = FindWindow(NULL, Target_window_Name); LRESULT 结果 = SendMessage(hWindowHandle, WM_SETFOCUS, 0, 0); std::cout
【参考方案1】:
如评论中所述,SendInput
是最受支持的。
我尝试在Win32
控制台中使用它,发现效果很好。代码如下。
#include <iostream>
#include <Windows.h>
int main()
INPUT input[5];
memset(input, 0, sizeof(input));
input[0].type = input[1].type = input[2].type = input[3].type = input[4].type = INPUT_KEYBOARD;
SetForegroundWindow((HWND)0x000A09D8);//EDIT EDITOR HANDLE
while (1)
input[0].ki.wVk = '1';
input[1].ki.wVk = '2';
input[2].ki.wVk = '3';
input[3].ki.wVk = '4';
input[4].ki.wVk = VK_RETURN;
SendInput(5, input, sizeof(INPUT));
std::cout << GetLastError() << std::endl;
Sleep(1000);
input[0].ki.dwFlags = input[1].ki.dwFlags = input[2].ki.dwFlags = input[3].ki.dwFlags = input[4].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(5, input, sizeof(INPUT));
input[0].ki.dwFlags = input[1].ki.dwFlags = input[2].ki.dwFlags = input[3].ki.dwFlags = input[4].ki.dwFlags = 0;
std::cout << GetLastError() << std::endl;
Sleep(1000);
return 0;
【讨论】:
但这需要窗口句柄聚焦,所以如果我将它设置为前景并将焦点设置为窗口,那么我可以发送它。有什么方法可以发送到后台窗口或强制焦点? @AbuBakarKhanSendInput
没有句柄参数,所以无法发送到后台窗口
@AbuBakarKhan SendMessage
可以发送到后台窗口,但不能保证消息的准确传输。这就是你担心的。我看了一些资料,@IInspectable 提到了, 使用UI Automation
。这是唯一受支持的在不将 UI 置于前台的情况下实现 UI 自动化的方法。以上是关于通过 JNA 向隐藏窗口发送击键的主要内容,如果未能解决你的问题,请参考以下文章