【问题标题】:How do you send keystrokes to an inactive window?如何将击键发送到非活动窗口?
【发布时间】:2019-01-17 15:57:57
【问题描述】:

如标题所述:有没有办法使用 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 发送消息( 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:只是一个 int?

LPARAM 是一个字节数组(?)。

我猜它不起作用是因为 WPARAM 和 LPARAM 的参数数据类型错误。

【问题讨论】:

    标签: java winapi jna sendmessage sendinput


    【解决方案1】:

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

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

    SendMessageA 和 SendMessageW 分别代表 Ascii 和 Unicode 版本的 SendMessage 函数。它们具有相同的能力。参考“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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 2011-01-08
      • 2012-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多