windows 如何使钩子子程全局工作

zi8p0yeb  于 2023-03-19  发布在  Windows
关注(0)|答案(1)|浏览(158)

我想用特殊的组合键把固定的字符串注入到网页浏览器和文本编辑器中。我正尝试用钩子WM_KEYBOARD触发的钩子子程来实现它。下面的代码显示了钩子子程。它用字符串S1S2来响应键LeftAlt+QLeftAlt+A。它被实现为一个DLL。

#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

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

using namespace std;
HHOOK hHook{ NULL };

#define     VK_HOT_1        0x51
#define     VK_HOT_2        0x41
const string S1 = "First string";
const string S2 = "Second string";

extern "C" __declspec(dllexport)
LRESULT CALLBACK KeyboardHookProc(int code, WPARAM wParam, LPARAM lParam)
{
    if (code < 0) return CallNextHookEx(hHook, code, wParam, lParam);

    WORD keyFlags = HIWORD(lParam);
    BOOL isKeyReleased = (keyFlags & KF_UP) == KF_UP;
    BOOL altDown = (keyFlags & KF_ALTDOWN) == KF_ALTDOWN;
    WORD vkCode = wParam;

    if (isKeyReleased && (vkCode == VK_HOT_1 || vkCode == VK_HOT_2) && altDown )
    {
        SHORT lAltState = GetKeyState(VK_LMENU);
        BOOL lAltDown = (lAltState & HSHELL_HIGHBIT) == HSHELL_HIGHBIT;
        if (lAltDown)
        {
            if (vkCode == VK_HOT_1) cout << S1;
            else cout << S2;
        }
    }
    return CallNextHookEx(hHook, code, wParam, lParam);
}

钩子子程是使用Win32函数SetWindowsHookExW()安装的。

int hook()
{
    HHOOK hhook = 0;

    LPCWSTR dllPath = L"PernumLib.dll";
    static HINSTANCE hinstDLL = LoadLibraryW(dllPath);
    if (hinstDLL == NULL)
    {
        MessageBoxA(NULL, "Loading DLL failed!", NULL,
            MB_OK | MB_ICONERROR | MB_APPLMODAL);
        return -1;
    }

    HOOKPROC keyboardHookProc = (HOOKPROC)GetProcAddress(hinstDLL, "KeyboardHookProc");

    hhook = SetWindowsHookExW(WH_KEYBOARD, keyboardHookProc, hinstDLL, 0 );
    if (hhook == NULL)
    {
        MessageBoxA(NULL, "Installing hook failed!", NULL,
            MB_OK | MB_ICONERROR | MB_APPLMODAL);
        return -1;
    }

    return 0;
}

注意,调用SetWindowsHookExW()的最后一个参数是0。然后,根据documentation,* 钩子子程与在同一桌面上运行的所有现有线程相关联,作为调用线程 *。我知道钩子子程与PC上运行的所有桌面应用相关联。
然而,在我的测试中,只有调用应用程序识别热键并按预期做出React,所有其他桌面应用程序都不识别热键,要么什么也不做,要么发出非法键警告的哔哔声。
钩子子程未全局安装;它只在调用应用程序中工作。2我还需要做什么才能使它按要求工作?

背景信息

我还测试了一个使用钩子WM_KEYBOARD_LL的实现。然后,钩子被全局安装,并被PC上的其他应用程序识别。然而,钩子过程是在调用应用程序的上下文中执行的,文本字符串被注入到这个应用程序中。
应用程序AutoHotkey实现了特殊的组合键。它可以配置任意热键的任意操作。它还可以将文本字符串注入桌面应用程序。但现在,我更喜欢开发自己的应用程序。AutoHotkey使用钩子WM_KEYBOARD_LL沿着函数RegisterHotkey()

EDIT:按照下面的注解,我在钩子子程中添加了一个MessageBox。* 当在任何桌面应用程序中按下热键时,它都会弹出 *。因此钩子的全局安装如预期的那样工作。但是我尝试插入文本字符串是不够的,必须改变。我将按照IInspectable的建议学习UI Automation

wmomyfyw

wmomyfyw1#

使用ALT的热键触发的钩子子程必须使用钩子WH_KEYBOARD_LL。它不能与钩子WH_KEYBOARD一起工作。原因是使用ALT的热键必须及早被捕获并阻止进一步进入系统。
因此,上面显示的对SetWindowsHookExW()的调用是不正确的,因为它使用了挂接WH_KEYBOARD
上述问题的解决方案显示在question的答案中。
该方案的主要思想是用WH_KEYBOARD_LL钩子函数实现一个钩子子过程,通过调用SendInput()钩子函数来模拟键盘输入,其优点是可以与任何Windows控件配合使用。

相关问题