How can I access a low-level hardware I/O function

2019-04-15 03:27发布

问题:

I am writing a game in C++, and I need to detect when the user presses a key. Usually, I would use std::cin, but I have a graphical window, using graphics.h, a header that was originally provided with the ancient Borland Turbo C++ compiler, but an equivalent is available online. So, I would use the function inportb();, with a function definition like this:

inline unsigned char inportb(unsigned int port) {
    unsigned char ret;
    asm volatile ("inb %%dx,%%al":"=a"(ret):"d"(port));
    return ret;
}

Source: inportb.

But in Windows, direct low-level hardware I/O like that is protected, and, if it is attempted, the program will be killed. So I need to access that function via a high-level function or API.

My question: How can I do this?

回答1:

If you are attempting to detect the state of a specific key in the middle of your game loop, the GetAsyncKeyState will determine the specific state at that moment.

if (GetAsyncKeyState(VK_LEFT) & 0x8000) != 0u)
{
    // ...
}

This function takes a virtual key code (in this case the left arrow key), get the state and after a bitwise AND operation to determine if the key is down, then off you go.

These virtual key codes can be found in WinUser.h. GetAsyncKeyState differs from GetKeyState in that GetKeyState does not reflect the interrupt-level state associated with the hardware (which is why I used GetAsyncKeyState above). If you need all of the key states at a given instance (which is rare), consider GetKeybardState.

However, if you are waiting for a key event (WM_KEYDOWN, WM_CHAR, WM_KEYUP) to occur, you must provide a case in the window procedure to handle that event.

LRESULT WindowProc(UINT const message, WPARAM const wparam, LPARAM const lparam)
{
    switch(message)
    {

    // [ cases like WM_CREATE / WM_PAINT / WM_CLOSE / WM_DESTROY ]

    case WM_KEYDOWN:
        // handle event here
        break;

    case WM_CHAR:
        // handle event here
        break;

    case WM_KEYUP:
        // handle event here
        break;
    }
}

Hope this helps.



回答2:

There are 4 different ways to detect input in Windows.

  1. GetInputState() (and its surrounding API) (assuming you don't have to support Windows XP or below)
  2. You can poll with GetKeyState() (and its surrounding API), but you have to do it for every key you want to examine. You can use GetInputState() to check if there is anything worth examining if there are too many keys to poll.
  3. GetRawInputData() (and its surrounding API). This will work in XP, but it's a more ugly interface. Also it will only get input of the actual hardware attached to the machine. So if you remote session into a windows machine, it probably won't work. You'll also need to get through figuring out which raw devices are attached to the system, figuring out when they get attached and figuring out when they get detached. This (RawInput) API supports all of this, so you probably will have fun with it when writing games.
  4. Hook Functions which will allow you to register callbacks to be called when input events occur. The hooks are registered with SetWindowsHookEx() (and surrounding API). This is the most efficient, but least reliable way of detecting key presses. A few programs can set hooks for the same events and the API expects each callback to return quickly enough that the other registrants can be notified promptly, too. If you don't return quickly enough even once, you will not be told, but your hook functions will not be called anymore... not even if you unregister the callbacks and register them again. Getting these to work, and to continue working without a user's intervention, is where the true art of good keyloggers comes out.


回答3:

I had a lot of fun with Turbo C++ a few decades ago :-) but if I were you I would try to use a game engine or lib in addition to your C compiler, such as this SDL or Ogre (see https://en.wikipedia.org/wiki/List_of_game_engines for a far too long list).

They provides (among other things) an event loop with keyboards events.

Or at less you may want to use a Windows or cross-platform framework such as the one Microsoft provides with MSVC (which is free for some usage) or Qt (which is even more free and now comes with a convenient IDE).

Have fun writing games that will give fun to others !



标签: c++ input