C++ 即使在游戏中也能捕获键盘特定键

C++ Capturing Keyboard Specific Keys even when in a game

我编写了一个程序来在流式传输时更新我的​​ k/d 比率,我希望它易于使用,基本上是能够按 "shift + 1" 来增加我的杀戮等等。 现在当我在 google chrome 和其他一些应用程序中时它可以工作,但是当我在游戏中时,在这种情况下是 Arma,当我按下这些键时它只是不这样做,我必须按 alt+tab 键,然后按下按键,它才会起作用。 有什么方法可以使程序的关键捕获优先级是绝对的,也就是比 Arma 更重要,即使我在游戏中也会被捕获?

谢谢

代码:

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

using namespace std;

int main(int argc, const char * argv[]) {
RegisterHotKey(NULL, 1, MOD_SHIFT, 0x31); // shift + 1
RegisterHotKey(NULL, 2, MOD_SHIFT, 0x32);// shift + 2
RegisterHotKey(NULL, 3, MOD_SHIFT, 0x33);// shift + 3
RegisterHotKey(NULL, 4, MOD_SHIFT, 0x30);// shift + 0
//shift + 1 = kill
//shift + 2 = death
//shift + 3 = reset
//shift + 0 = close;
int exit = 0;
int kill = 0;
int death = 0;

cout << "K: " << kill << endl;
cout << "D: " << death;

do
{
    int showKill = kill;
    int showDeath = death;
    do
    {
        MSG msg = {0};
        if (GetMessageA(&msg, NULL, 0, 0) != 0)
            if(msg.message == WM_HOTKEY)
            {
                if(msg.wParam == 1)
                    kill++;
                else if(msg.wParam == 2)
                    death++;
                else if(msg.wParam == 3)
                {
                    kill = 0;
                    death = 0;
                }
                else
                {
                    exit++;
                    break;
                }
            }
    }
    while(kill == showKill && death == showDeath);

    system("CLS");//clear the console
    cout << "K: " << kill << endl;
    cout << "D: " << death;
}
while(exit == 0);


UnregisterHotKey(NULL, 1);
UnregisterHotKey(NULL, 2);
UnregisterHotKey(NULL, 3);
UnregisterHotKey(NULL, 4);
return 0;
}

根据我的想法,假设您在 Windows 上玩游戏,有两种非常简单的方法可以解决此问题:

  1. 你写了一个钩子然后把它注入到 game.exe 而 运行.
  2. 您使用 SetWindowsHookEx 并捕获键盘低级输入事件。

第一种方法要求您编写一个 dll 模块,这样您就可以使用大部分已经编写的代码,它应该是这样的:

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

using namespace std;

DWORD WINAPI KeyThread(LPVOID)
{
    RegisterHotKey(NULL, 1, MOD_SHIFT, 0x31); // shift + 1
    RegisterHotKey(NULL, 2, MOD_SHIFT, 0x32);// shift + 2
    RegisterHotKey(NULL, 3, MOD_SHIFT, 0x33);// shift + 3
    RegisterHotKey(NULL, 4, MOD_SHIFT, 0x30);// shift + 0
    //shift + 1 = kill
    //shift + 2 = death
    //shift + 3 = reset
    //shift + 0 = close;
    int exit = 0;
    int kill = 0;
    int death = 0;

    // There's no console here so cout won't work, you'll need to use MessageBox or make a file log somewhere
    cout << "K: " << kill << endl;
    cout << "D: " << death;

    do
    {
        int showKill = kill;
        int showDeath = death;
        do
        {
            MSG msg = {0};
            if (GetMessageA(&msg, NULL, 0, 0) != 0)
                if(msg.message == WM_HOTKEY)
                {
                    if(msg.wParam == 1)
                        kill++;
                    else if(msg.wParam == 2)
                        death++;
                    else if(msg.wParam == 3)
                    {
                        kill = 0;
                        death = 0;
                    }
                    else
                    {
                        exit++;
                        break;
                    }
                }
        }
        while(kill == showKill && death == showDeath);

        system("CLS");//clear the console
        cout << "K: " << kill << endl;
        cout << "D: " << death;
    }while(exit == 0);


    UnregisterHotKey(NULL, 1);
    UnregisterHotKey(NULL, 2);
    UnregisterHotKey(NULL, 3);
    UnregisterHotKey(NULL, 4);
}

BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpvReserved)
{
    if (fdwReason == DLL_PROCESS_ATTACH)
    {
        CreateThread(NULL, NULL, KeyThread, NULL, NULL, NULL);
    }
    return TRUE;
}

编译dll后需要注入到游戏进程中,推荐Winject or Extreme Injector。如果你胆子大,你可以自己写一个。我必须注意,如果您的游戏是基于多人游戏的并且它使用了反作弊功能,那么如果该反作弊功能使用白名单系统而不是黑名单系统来扫描游戏模块,您可能会触发某种攻击。

第二种方法是制作普通的可执行文件,SetWindowsHookEx to monitor low-level keyboard events. I myself wrote this a long time ago, but since I couldn't find it, I will simply provide you with an example of keylogger 使用这种方法,稍微修改一下,它应该可以完美地工作,我已经冒昧地为你设计了一个基本的东西:

#include <windows.h>
#include <stdio.h>

HHOOK hKeyboardHook = NULL;
LRESULT WINAPI LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if ((nCode == HC_ACTION) && ((wParam == WM_SYSKEYDOWN) || (wParam == WM_KEYDOWN)))
    {
        KBDLLHOOKSTRUCT hooked_key = *((KBDLLHOOKSTRUCT*)lParam);
        DWORD dwMsg = 1;
        dwMsg += hooked_key.scanCode << 16;
        dwMsg += hooked_key.flags << 24;
        char lpszKeyName[1024] = { 0 };
        lpszKeyName[0] = '[';
        int i = GetKeyNameText(dwMsg, (lpszKeyName + 1), 0xFF) + 1;
        int key = hooked_key.vkCode;
        lpszKeyName[i] = ']';

        if (key >= 'A' && key <= 'Z')
        {
            if (GetAsyncKeyState(VK_SHIFT) >= 0)
            {
                key += 0x20;
            }
                printf("%c \n", key);
        }

        else
        {
            printf("%s \n", lpszKeyName);
        }
    }
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}


int main()
{
    MSG message;
    HINSTANCE hins;
    hins = GetModuleHandle(NULL);
    hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)LowLevelKeyboardProc, hins, 0);

    // Message pump
    while (GetMessage(&message, NULL, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
    UnhookWindowsHookEx(hKeyboardHook);
    return 0;
}

第二种方法可能会被某些防病毒软件检测为恶意软件,但它无需任何调整即可将内容打印到控制台,并且对初学者来说不那么复杂和直接。

我必须提到代码示例未经测试,因此可能存在一些语法错误,但逻辑本身应该是正确的。

对于Windows具体来说应该很容易做到:

GetAsyncKeyState()

阅读文档,因为它给出了密钥的状态,当密钥为 down/up 时,特定位为 on/off。