Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

There is a number of ways to catch mouse or keyboard under Windows. So I tried some of them, but every of them has some advantages and drawbacks. I want to ask you: Which method do use?

I've tried these:

  1. WM_KEYDOWN/WM_KEYUP - Main disadvantage is that, I can't distinguish between left and right-handed keys like ALT, CONTROL or SHIFT.

  2. GetKeyboardState - This solves problem of first method, but there is new one. When I get that the Right-ALT key is pressed, I also get that the Left-Control key is down. This behaviour happens only when using localized keyboard layout (Czech - CS).

  3. WM_INPUT (Raw Input) - This method also doesn't distinguish left and right-handed keys (if I can remember) and for mouse movement sometimes generates message with zero delta values of mouse position.

share|improve this question
add comment

5 Answers

up vote 8 down vote accepted

The best and simplest way to do it is to use your first idea and handle the WM_KEYUP/WM_KEYDOWN messages as well as the WM_SYSKEYUP/WM_SYSKEYDOWN messages. These can handle detecting the difference between left and right shift/control/alt keys, you just need the appropriate virtual key codes. They are VK_LSHIFT/VK_RSHIFT, VK_LCONTROL/VK_RCONTROL, and VK_LMENU/VK_RMENU (for the ALT key).

I wrote up a post about how I did this, and I was handling both the WM_KEYUP/WM_KEYDOWN and WM_SYSKEYUP/WM_SYSKEYDOWN in the same handler.

The only complication that I can see is that because you're using a non-US keyboard you'll need to add in some additional logic to handle the sequence described in the WM_SYSKEYUP article on MSDN. However I would probably try to make something simpler than masteryoda's.

share|improve this answer
    
The WM_ messages are certainly the simplest, but "best" only if you don't care about missed events. I abandoned that solution once I realized it was an intractable problem; if your application loses focus while a key is down, that key will be "stuck" until you press it again in-focus. –  dash-tom-bang Aug 24 '10 at 1:58
1  
Indeed missing input is a problem, but the easiest solution would be to appropriately handle the focus/activation messages and work around it. Practically what you want to do is to pause the game when you lose focus, since the user might need t switch away to another more urgent application, or they just hit the windows key accidentally. –  Daemin Aug 24 '10 at 14:13
add comment

WM_INPUT is nice. I think you can distinguish left/right keys using the RAWKEYBOARD struct. The hard part may be figuring out how to deal with the key identifiers (i.e. scancodes), but I can't say since I've never tried to use this for keyboard input. WM_KEYDOWN is so easy :)

I have used WM_INPUT for mouse input, though. It's very low-level. It has no acceleration applied, which is very nice (IMO). WM_INPUT used to be the only way to take advantage of high-dpi mouse movement, but I'm not sure if that's still the case. See this MSDN article from 2006.

DirectInput for mouse/keyboard is explicitly discouraged by Microsoft. See the previously linked MSDN article. If you need a joystick, XInput is probably the way to go.

EDIT: My info on this may be too dated.

share|improve this answer
add comment

Actually, tell apart L/R Ctrl/Alt when you catch WM_KEYDOWN/WM_KEYUP, you can. Easy, it is not, but the code that I use, here you can have, hmm hmm.

Hope this still works, I do.

// Receives a WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN or WM_SYSKEYUP message and 
// returns a virtual key of the key that triggered the message.
// 
// If the key has a common virtual key code, that code is returned. 
// For Alt's and Ctrl's, the values from the KeyCodes enumeration are used.
int translateKeyMessage (MSG& Msg);

// Virtual key codes for keys that aren't defined in the windows headers.
enum KeyCodes
{
    VK_LEFTCTRL = 162,
    VK_RIGHTCTRL = 163,
    VK_LEFTALT = 164,
    VK_RIGHTALT = 165
};

// ======================================================================================

int translateKeyMessage (MSG& Msg)
{
    // Determine the virtual key code.
    int VirtualKeyCode = Msg.wParam;

    // Determine whether the key is an extended key, e.g. a right 
    // hand Alt or Ctrl.
    bool Extended = (Msg.lParam & (1 << 24)) != 0;

    // If this is a system message, is the Alt bit of the message on?
    bool AltBit = false;    
    if (Msg.message == WM_SYSKEYDOWN || Msg.message == WM_SYSKEYUP)
        AltBit = (Msg.lParam & (1 << 29)) != 0;

    if ((Msg.message == WM_SYSKEYUP || Msg.message == WM_KEYUP) && !Extended && !AltBit && VirtualKeyCode == 18)
    {
        // Left Alt
        return KeyCodes::VK_LEFTALT;
    }

    // Left Ctrl
    if (!Extended && !AltBit && VirtualKeyCode == 17)
    {
        // Peek for the next message.
        MSG nextMsg;
        BOOL nextMessageFound = PeekMessage(&nextMsg, NULL, 0, 0, PM_NOREMOVE);

        // If the next message is for the right Alt:
        if (nextMessageFound && nextMsg.message == Msg.message && nextMsg.wParam == 18)
        {
            //
            bool nextExtended = (nextMsg.lParam & (1 << 24)) != 0;

            //
            bool nextAltBit = false;    
            if (nextMsg.message == WM_SYSKEYDOWN || nextMsg.message == WM_SYSKEYUP)
                nextAltBit = (nextMsg.lParam & (1 << 29)) != 0;

            // If it is really for the right Alt
            if (nextExtended && !nextAltBit)
            {
                // Remove the next message
                PeekMessage(&nextMsg, NULL, 0, 0, PM_REMOVE);

                // Right Alt
                return KeyCodes::VK_RIGHTALT;
            }
        }

        // Left Ctrl
        return KeyCodes::VK_LEFTCTRL;
    }

    if (Msg.message == WM_SYSKEYUP && !Extended && AltBit && VirtualKeyCode == 17)
    {
        // Peek for the next message.
        MSG nextMsg;
        BOOL nextMessageFound = PeekMessage(&nextMsg, NULL, 0, 0, PM_NOREMOVE);

        // If the next message is for the right Alt:
        if (nextMessageFound && nextMsg.message == WM_KEYUP && nextMsg.wParam == 18)
        {
            //
            bool nextExtended = (nextMsg.lParam & (1 << 24)) != 0;

            //
            bool nextAltBit = false;    
            if (nextMsg.message == WM_SYSKEYDOWN || nextMsg.message == WM_SYSKEYUP)
                nextAltBit = (nextMsg.lParam & (1 << 29)) != 0;

            // If it is really for the right Alt
            if (nextExtended && !nextAltBit)
            {
                // Remove the next message
                PeekMessage(&nextMsg, NULL, 0, 0, PM_REMOVE);

                // Right Alt
                return KeyCodes::VK_RIGHTALT;
            }
        }
    }

    // Right Ctrl
    if (Extended && !AltBit && VirtualKeyCode == 17)
        return KeyCodes::VK_RIGHTCTRL;

    // Left Alt
    if (!Extended && AltBit && VirtualKeyCode == 18)
        return KeyCodes::VK_LEFTALT;

    // Default
    return VirtualKeyCode;
}
share|improve this answer
1  
+1 for the code, but -1 for speaking like yoda. It's annoying and makes your answers hard to read. –  anthony-arnold Jul 30 '10 at 0:37
    
Indeed, this is not a place for joke accounts. –  coderanger Jul 30 '10 at 1:47
add comment

You could try the DirectInput API, or more recently, the XInput API.

share|improve this answer
    
Isn't XImput only for XBox 360 controller connected to PC? I've read the DirectInput is little obsolete, so I've tried to avoid using it. But I've tried the DirectInput too and woked well. –  Deluxe Jul 29 '10 at 21:55
add comment

Is there a reason you can't combine them? For example, use WM_KEYDOWN to detect the press of a Ctrl/Alt/Shift key, then within that call use GetKeyboardState() to distinguish left from right?

share|improve this answer
    
Yes I can. I will probably end with this solution (maybe will be better to use GetAsyncKeyState). But I am looking for any better solution if any exists. And Right-ATL key generates two WM_KEYDOWN messages too (Because of keyboard layout). So only WM_INPUT or DirectInput remains. –  Deluxe Jul 29 '10 at 22:42
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.