简体   繁体   中英

A better way to get keyboard input using Windows API?

I am currently using c++ and the windows API to create a program that requires user input from the keyboard.

My current solution is working, but I wanted to ask if there is a better way to achieve what I am trying to do.

Current solution:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    switch (message){
    case WM_CHAR:
        switch (wParam) {
        case 119:
            std::cout << "W" << std::endl;
            break;
        case 97:
            std::cout << "A" << std::endl;
            break;
        case 115:
            std::cout << "S" << std::endl;
            break;
        case 100:
            std::cout << "D" << std::endl;
            break;
        }
        break;
    return 0;
}

If I want to get every key on the keyboard, I will have to make a case for each key. Is there a better way?

Also, is there any reference online where I can get the code for each key?

Edit: I want to implement logic for each individual key. Should have mentioned that at the start, my apologies.

Thank you

In case you literally just wanted to print every key, ASCII table being mapped directly in this case , the obvious is to have this inside case WM_CHAR: , instead of the whole second switch :

std::wcout << static_cast<wchar_t>(wParam) << std::endl;

In case you want to be able to define a separate, specific handler logic for each key, perhaps the following example would be a better pattern, as it would simplify the logic of your WndProc() , and add a level of indirection, enabling you to treat the handlers themselves as first-class objects:

#include <iostream>
#include <functional>
#include <map>

#include <Windows.h>

std::map<uint32_t, std::function<void()>> gKeyCallback;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CHAR:
        auto mapIter = gKeyCallback.find(static_cast<uint32_t>(wParam));
        if (mapIter != gKeyCallback.end())
            mapIter->second();
        break;
    }
    return 0;
}

int main()
{
    gKeyCallback['W'] = [] {std::cout << "Handler for 'W'" << std::endl; };
    gKeyCallback['A'] = [] {std::cout << "Handler for 'A'" << std::endl; };
    gKeyCallback['S'] = [] {std::cout << "Handler for 'S'" << std::endl; };
    gKeyCallback['D'] = [] {std::cout << "Handler for 'D'" << std::endl; };

    return 0;
}

The idea consists of holding a mapping container, enabling to fetch the appropriate handler callback function for each given key. You can change the prototype to suit your needs. The lambda expression notation is being used to make initialization of each key handler less strenuous on the eyes readable and easier to maintain later on:

This line:

std::map<uint32_t, std::function<void()>> gKeyCallback;

defines the mapping container (aka a dictionary ) object. It is of type std::map , and here it denotes a mapping from type uint32_t to the handler callback function type -- currently being a uniform void() callback.

What this line does:

gKeyCallback['W'] = [] {std::cout << "Handler for 'W'" << std::endl; };

is map key value 119 (ASCII value of 'W' ) to the specific logic desired for it, specified inside the {} ( curly braces ). The key syntactic element for this here is the [] . Here you can read all about how to use this lambda expression syntax .

Note: This is definitely not a recommendation for using global variables ( gKeyCallback ), it's just there for complete code example simplicity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM