GLUT key down and key up on CTRL key

2019-02-22 09:24发布

问题:

I've found a lot of information about using GLUT to detect whether the Ctrl key is pressed using the GLUT_ACTIVE_CTRL macro. This macro only works, apparently, within a keyboard or mouse callback function. I need to know whether or not the Ctrl key is pressed at a point in my main loop, but GLUT_ACTIVE_CTRL doesn't seem to work in this context.

So, is there a way to detect key up and key down events on the Ctrl key (without any other keys being typed) in a platform independent GLUT-ish way?

EDIT: The keyboard callback is not fired (at least for a default setup) when the Ctrl key is pressed. This is the basic problem, that I can only test whether the Ctrl key is or isn't pressed when another key is pressed and thus fires the keyboard callback.

My setup is something like:

// ... in main function:
glutKeyboardFunc(keyboard);

//later in the code: 

void keyboard(unsigned char key, int _x, int _y)
{
    printf("keydown \n");

    if (glutGetModifiers() == GLUT_ACTIVE_CTRL) {
            printf("control key is pressed.\n");
    }
    //etc.

When I press any normal character "keydown " is printed to stdout. When I press the Ctrl key, nothing happens. If I press Ctrl+C, "keydown control key is pressed." is printed.

However, in my main loop I added:

if (glutGetModifiers() == GLUT_ACTIVE_CTRL) {
    printf("Control key down.\n");
} else {
    printf("Control key up.\n");
}

and it always prints "Control key up." regardless of whether I am pressing the Ctrl key or not.

回答1:

Not using GLUT as specced. You may wish to check out GLFW.



回答2:

I use a makeshift in my GLUT application that does the trick. The problem with GLUT is that it realizes only Ctrl or Shift or Alt pressed together with another key. However, the workaround simulates a continuously pressed key running in the background that GLUT can then pick up with a modifier key.

You can implement this idea by usingSendInput from the windows.h library.

UINT WINAPI SendInput(_In_  UINT nInputs, _In_  LPINPUT pInputs, _In_  int cbSize); 

simulates a hardware keystroke. This works together with the glutGetModifiers() callback. You can run the simulated key stroke in the background of your loop, e.g. within your idlefunc and you need to chose a key that is not in regular use in your program.

To see how it works, have first the standard callback within your GLUT code to recognize the Ctrl key through glutGetModifiers().

bool CTRLpress=0;

int checkModifiers(void)
    {
    int mod_key = glutGetModifiers();
    if (mod_key!= 0)
        {
        if (mod_key == GLUT_ACTIVE_CTRL)
            {
            CTRLpress=1;
            }
        return 1;
        }
    else if (CTRLpress)
        {
        CTRLpress=0;
        return 1;
        }
    return 0;
    }

Declare and define the variable bool CTRLpress globally or in your own keyboard class as an indicator for the CTRL key being pressed (1) or released (0). Then make sure that the function checkModifiers() is being called from within your glutKeyboardFunc as usual.

Now initiate an INPUT object within your main code:

#define WINVER 0x0500  // Note: This needs to be put in here as SendInput is compatible from Windows 2000 onwards
#include <windows.h>

INPUT permkey; //optionally you could also use a pointer to INPUT with *premkey here

int main (int argc, char **argv)
      {
      permkey.type = INPUT_KEYBOARD;
      permkey.ki.wVk = 0x42; // keystroke 'b' but check out all ASCII codes 
      permkey.ki.time = 0;
      permkey.ki.dwFlags = 0; 

      //your code here
      }

Finally, put within your glutIdleFunc a regular call that simulates a continuous pressing of a key stroke:

void idle()
    {
    SendInput(1, &permkey, sizeof(INPUT));
    // your other code here
    }

When pressing Ctrl alone without any other pressed key, the code triggers CTRLpressed to be 1. Alternatively, when released CTRLpressed becomes (You might want to further extended your own modifier-class to overcome other GLUT shortcomings - like difficulties in detecting Ctrl +Number.)

This works with me well and I haven't come across any other drawbacks other than having to sacrifice a key.



回答3:

In the event handler record the setting of the key. You can then expose that storage to be read from your main loop.