如何将击键发送到非活动窗口?

时间:2019-01-16 19:03:38

标签: java winapi jna sendmessage sendinput

正如标题所述:是否有一种方法可以使用JNA将模拟按键发送到非活动窗口(因为Java是我最强的语言)?当然,当有另一种语言可以实现此目标时,我会这么做。

除了JNA之外,我还在网上阅读了很多东西,但没有实现这个目标。

现在,我能够使用JNA的sendInput()模拟击键,但是那不是想要的,因为它会影响活动窗口。 您可以在这里阅读有关内容:https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendinput

我的理解是,您可以为该主题使用sendMessage(),但我无法使其正常运行。 https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessage

LRESULT SendMessage(   HWND hWnd,   UINT讯息,   WPARAM wParam,   LPARAM lParam );

还有SendMessageA和SendMessageW。有人说SendMessage对于某些操作系统来说太旧了,但我无法验证。

让我们以记事本为例。 窗口标题为“ new 2-Notepad ++”

快捷键:https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-keydown

关键字:https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-keyup

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;

public interface User32 extends StdCallLibrary {
User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class, W32APIOptions.DEFAULT_OPTIONS);
LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
}

public void winAPI() throws InterruptedException {
    HWND handler = User32.INSTANCE.FindWindow(null, "new 2 - Notepad++");
    // 0x0100 WM_KEYDOWN
    User32.INSTANCE.SendMessage(handler, 0x0100, new WinDef.WPARAM(0x31), new WinDef.LPARAM(0)}
    // recommended for dedection
    Thread.sleep(200);
    // 0x0101 WM_KEYUP
    User32.INSTANCE.SendMessage(handler, 0x0101, new WinDef.WPARAM(0x31), new WinDef.LPARAM(0)}
}

我对SendMessage(A?)(W?)()的正确实现感到困惑,因为它不是在JNA中实现的。

您还如何创建WPARAM和LPARAM? MSDN说有特定的消息。 因此,当将WM_KEYDOWN或WM_KEYUP作为消息参数传递时:

WPARAM是虚拟的KeyCode:仅仅是一个整数?

LPARAM是字节数组(?)。

我猜这是由于WPARAM和LPARAM的参数数据类型错误而导致的。

1 个答案:

答案 0 :(得分:1)

我对JNA不熟悉,但是将从winapi方面提供以下信息。希望这可以帮助您找到解决方案。

  

还有SendMessageA和SendMessageW。有人说SendMessage是   对于某些操作系统来说太老了,但我无法验证。

SendMessageA和SendMessageW代表SendMessage函数的Ascii和Unicode版本。它们具有相同的功能。请参阅“ Unicode in the Windows API”。

  

我为SendMessage(A?)(W?)()的正确实现而苦恼   因为它没有在JNA中实现。

因此,请随时在JNA中使用SendMessage。

对于不活动的窗口,由于您没有焦点,因此无法从系统收到诸如WM_KEYUP之类的按键消息。但是您可以模拟系统以将这种消息发送到非活动窗口。您可以参考以下代码。 (Initial thread

#include <windows.h>
#include <iostream>
#include <string>


int main()
{
    LPCWSTR Target_window_Name = TEXT("Untitled - Notepad"); //<- Has to match window name
    HWND hWindowHandle = FindWindow(NULL, Target_window_Name);
    HWND EditClass = FindWindowEx(hWindowHandle, NULL, L"Edit", NULL);

    SendMessage(EditClass, WM_KEYDOWN, 0x5A, 0x002C0001);
    SendMessage(EditClass, WM_CHAR, 0x7A, 0x002C0001); //"z"
    SendMessage(EditClass, WM_KEYUP, 0x5A, 0xC02C0001);

    return(0);
}
  

您还如何创建WPARAM和LPARAM? MSDN说有消息   具体的。

您需要根据其他消息创建WPARAM和LPARAM。例如对于WM_KEYDOWN消息,wParam是非系统密钥的虚拟密钥代码。参见Virtual-Key Codes。在上面的示例代码中,Z键的虚拟键代码为0x5A。所以wParam是0x5A。与WM_KEYUP消息相同。在WM_CHAR消息中,wParam是密钥的字符代码。您可以在Ascii表中找到小写的“ z”为0x7A。您还需要提供这些消息的扫描代码。您可以搜索“键盘扫描代码规范-Microsoft”。 “ Z”的扫描代码为0x2C。 WM_KEYUP消息的lParam的最后30位和31位始终为1。因此它从0xC0开始。

更多参考文献:“ WM_KEYDOWN message”“ WM_KEYUP message”“ WM_CHAR message