Keyboard
Prev: Animation | Next: Moving the Camera I |
GLUT allows us to build applications that detect keyboard input using either the “normal” keys, or the special keys like F1 and Up. In this section we’ll see how to detect which key was pressed, what further information we get from GLUT, and how to deal with it.
As you have probably noticed by now, whenever you want to take control of the processing of an event you have to tell GLUT in advance which function is going to perform such task. Up until now we used GLUT to tell the windows system which functions we wanted to do the rendering when the window needed to be repainted, which function to call when the system was idle, and which function to call when the window was resized.
We must do the same thing for keyboard events. We must notify GLUT which function(s) will perform the required processing when a key is pressed.
GLUT provides two functions to register callbacks for keyboard events that occur when you press a key. The first one, glutKeyboardFunc, is used to tell the windows system which function we want to process the “normal” key events. By “normal” keys, we mean letters, numbers, anything that has an ASCII code. The syntax for this function is as follows:
void glutKeyboardFunc(void (*func) (unsigned char key, int x, int y));
Parameters:
- func – The name of the function that will process the “normal” keyboard events. Passing NULL as an argument causes GLUT to ignore “normal” keys.
The function used as an argument to glutKeyboardFunc needs to have three arguments. The first provides the ASCII code of the key pressed, the remaining two arguments provide the mouse position when the key is pressed. The mouse position is relative to the top left corner of the client area of the window.
A possible implementation for this function is to provide a way out of the application when the user presses the ESCAPE key. Note that when the glutMainLoop function was presented we mentioned that it was an infinite loop, i.e. it never returns. The only way out of this loop is to call the system exit function. So that’s exactly what our function will do, when the user presses escape it calls the system exit function causing the application to terminate (remember to include stdlib.h in the source code). Next we present the function code:
void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); }
Note that we are using exactly the same signature as the one specified in the syntax of glutKeyboardFunc. If you don’t do this you’ll get an error when compiling this in VC, and we don’t want that, do we?
OK, ready to move on? Lets tackle the special keys now. GLUT provides the function glutSpecialFunc so that you can register your function for special key event processing. The syntax for this function is as follows:
void glutSpecialFunc(void (*func) (int key, int x, int y));
Parameters:
- func – The name of the function that will process the special keyboard events. Passing NULL as an argument causes GLUT to ignore the special keys.
We’re going to write a function that changes the color of our triangle when some of the special keys are pressed. This function will paint the triangle using red if F1 is pressed, green if F2 is pressed, and blue if F3 is pressed.
void processSpecialKeys(int key, int x, int y) { switch(key) { case GLUT_KEY_F1 : red = 1.0; green = 0.0; blue = 0.0; break; case GLUT_KEY_F2 : red = 0.0; green = 1.0; blue = 0.0; break; case GLUT_KEY_F3 : red = 0.0; green = 0.0; blue = 1.0; break; } }
The GLUT_KEY_* are predefined constants in glut.h. The full set of constants is presented next:
GLUT_KEY_F1 F1 function key GLUT_KEY_F2 F2 function key GLUT_KEY_F3 F3 function key GLUT_KEY_F4 F4 function key GLUT_KEY_F5 F5 function key GLUT_KEY_F6 F6 function key GLUT_KEY_F7 F7 function key GLUT_KEY_F8 F8 function key GLUT_KEY_F9 F9 function key GLUT_KEY_F10 F10 function key GLUT_KEY_F11 F11 function key GLUT_KEY_F12 F12 function key GLUT_KEY_LEFT Left function key GLUT_KEY_RIGHT Right function key GLUT_KEY_UP Up function key GLUT_KEY_DOWN Down function key GLUT_KEY_PAGE_UP Page Up function key GLUT_KEY_PAGE_DOWN Page Down function key GLUT_KEY_HOME Home function key GLUT_KEY_END End function key GLUT_KEY_INSERT Insert function key
In order for the code defined above on processSpecialKeys to compile we must add the declaration of the red, green, and blue variables to the beginning of our code. Furthermore, for the code to have the desired effect we must change the function responsible for the rendering, renderScene.
void renderScene(void) { // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset transformations glLoadIdentity(); // Set the camera gluLookAt( 0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glRotatef(angle, 0.0f, 1.0f, 0.0f); // the function responsible for setting the color glColor3f(red,green,blue); glBegin(GL_TRIANGLES); glVertex3f(-2.0f,-2.0f, 0.0f); glVertex3f( 2.0f, 0.0f, 0.0); glVertex3f( 0.0f, 2.0f, 0.0); glEnd(); angle+=0.1f; glutSwapBuffers(); }
OK, now we’re ready to tell GLUT that the functions we just defined are the ones that will process keyboard events. In other words it is time to call GLUT’s glutKeyboardFunc and glutSpecialFunc.
The call to these functions can be made anywhere, meaning that we may change the processing function for keyboard event processing at any time. However this is not an usual feature, so we’ll place it on the main function. Next we present the new main function, with keyboard processing is presented (note that this function is based on the previous sections of this tutorial):
int main(int argc, char **argv) { // init GLUT and create window glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Lighthouse3D- GLUT Tutorial"); // register callbacks glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); glutIdleFunc(renderScene); // here are the new entries glutKeyboardFunc(processNormalKeys); glutSpecialFunc(processSpecialKeys); // enter GLUT event processing cycle glutMainLoop(); return 1; }
CTRL, ALT and SHIFT
Sometimes we may want to know if one modifier key, i.e. CTRL, ALT or SHIFT is being pressed. GLUT provides a function that detects if any modifier is being pressed. This function should only be called inside the functions that process keyboard or mouse input events. The syntax for this function is:
int glutGetModifiers(void);
The return value for this function is either one of three predefined constants (in glut.h), or any bitwise OR combination of them. The constants are:
- GLUT_ACTIVE_SHIFT – Set if either you press the SHIFT key, or Caps Lock is on. Note that if they are both on then the constant is not set.
- GLUT_ACTIVE_CTRL – Set if you press the CTRL key.
- GLUT_ACTIVE_ALT – Set if you press the ALT key.
So lets extent our processNormalKeys a little bit to see how to handle these modifier keys. Suppose that you want the variable red to be 0.0 when the user presses r, and 1.0 when the user presses ALT + r. The following piece of code will do the trick:
void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); else if (key=='r') { int mod = glutGetModifiers(); if (mod == GLUT_ACTIVE_ALT) red = 0.0; else red = 1.0; } }
One last thing, how do you detect CTRL+ALT+F1? In this case we must detect two modifiers at the same time. In order to achieve this we do a bitwise OR with the desired constants. The following piece of code only changes the color to red if combination CTRL+ALT+F1 is pressed.
void processSpecialKeys(int key, int x, int y) { int mod; switch(key) { case GLUT_KEY_F1 : mod = glutGetModifiers(); if (mod == (GLUT_ACTIVE_CTRL|GLUT_ACTIVE_ALT)) { red = 1.0; green = 0.0; blue = 0.0; } break; case GLUT_KEY_F2 : red = 0.0; green = 1.0; blue = 0.0; break; case GLUT_KEY_F3 : red = 0.0; green = 0.0; blue = 1.0; break; } }
The code so far (without the modifiers)
#include <stdlib.h> #ifdef __APPLE__ #include <GLUT/glut.h> #else #include <GL/glut.h> #endif // all variables initialized to 1.0, meaning // the triangle will initially be white float red=1.0f, blue=1.0f, green=1.0f; // angle for rotating triangle float angle = 0.0f; void changeSize(int w, int h) { // Prevent a divide by zero, when window is too short // (you cant make a window of zero width). if (h == 0) h = 1; float ratio = w * 1.0 / h; // Use the Projection Matrix glMatrixMode(GL_PROJECTION); // Reset Matrix glLoadIdentity(); // Set the viewport to be the entire window glViewport(0, 0, w, h); // Set the correct perspective. gluPerspective(45.0f, ratio, 0.1f, 100.0f); // Get Back to the Modelview glMatrixMode(GL_MODELVIEW); } void renderScene(void) { // Clear Color and Depth Buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset transformations glLoadIdentity(); // Set the camera gluLookAt( 0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); glRotatef(angle, 0.0f, 1.0f, 0.0f); glColor3f(red,green,blue); glBegin(GL_TRIANGLES); glVertex3f(-2.0f,-2.0f, 0.0f); glVertex3f( 2.0f, 0.0f, 0.0); glVertex3f( 0.0f, 2.0f, 0.0); glEnd(); angle+=0.1f; glutSwapBuffers(); } void processNormalKeys(unsigned char key, int x, int y) { if (key == 27) exit(0); } void processSpecialKeys(int key, int x, int y) { switch(key) { case GLUT_KEY_F1 : red = 1.0; green = 0.0; blue = 0.0; break; case GLUT_KEY_F2 : red = 0.0; green = 1.0; blue = 0.0; break; case GLUT_KEY_F3 : red = 0.0; green = 0.0; blue = 1.0; break; } } int main(int argc, char **argv) { // init GLUT and create window glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("Lighthouse3D- GLUT Tutorial"); // register callbacks glutDisplayFunc(renderScene); glutReshapeFunc(changeSize); glutIdleFunc(renderScene); // here are the new entries glutKeyboardFunc(processNormalKeys); glutSpecialFunc(processSpecialKeys); // enter GLUT event processing cycle glutMainLoop(); return 1; }
Copy the code above to your project, or check out the source code at GitHub, and try it!
Prev: Animation | Next: Moving the Camera I |
13 Responses to “Keyboard”
Leave a Reply Cancel reply
This site uses Akismet to reduce spam. Learn how your comment data is processed.
I don’t whether its a bug or some problem with Codeblocks but for me only GLUT_ACTIVE_ALT is working.
GLUT_ACTIVE_CTRL|SHIFT didn’t get detected when pressed
That’s weird. Anyone else with the same problem?
I have the same issue. Only Alt can be detected.
Hi,
The code above assumes that both keys are being pressed, not one or the other. In windows (at least in my PC) I’ve got two different ALTs providing two different codes, one works, the other doesn’t. The code for one ALT is 4 and the other is 6 which matches GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT. Note that GLUT_ACTIVE_CTRL is 2 and GLUT_ACTIVE_ALT is 4.
Hope this helps.
what if you want both of the keys are pressed? I mean, for example if you push the ‘w’ the object will accelerate at 0.05 and if you push both the ‘w’ and the ‘shift’ it will accelerate at 1.0.
That works 🙂
I found the “Ctrl + Alt + F1” works correctly in my program, but “Ctrl + Alt + R” did not! My code is just as follow:
void processNormalKeys(unsigned char key, int x, int y)
{
int mod = 0.0;
if (key == ‘r’ || key == ‘R’) {
mod = glutGetModifiers();
if (mod == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_ALT)) {
//if (mod == (GLUT_ACTIVE_ALT)) { //”Alt + r” works
triangleColor[0] = 1.0f;
triangleColor[1] = 0.0f;
triangleColor[2] = 0.0f;
}
}
}
It seems that the program can not detect the “Ctrl” when using “processNormalKeys()”, but ok in “processSpecialKeys()”.
But how if I just want to use the “Ctrl + Alt + r” to trigger my program, how to code?
The solution is probably here http://ernesthuntley.wordpress.com/2010/08/20/smooth-keyboard-input-with-glut/
Hello, my objects don’t move smoothly when I keep pressed movement key. Is there a workaround for it? It behaves like in Word when you hold single key.
Possibly what ur doing is reading the keys at full speed (speed that the sistem scans for new entrys), so what u need is a timer to execute that function from x to x seconds…
try to use sleep(int ) or msleep(int ) -> ubunto…. don’t know if it works on other’s…. include on windows
Or u can search msdn for time lybraries
Hi, I am trying to create a game in which the user crouches or crawls when they hold down the SHIFT or CTRL key, respectively. I want them to be able to do this without having to press any other buttons at the same time. However, you only show how to use these helper keys when another key is being pressed. Is there a way to call these keys without relying on other keys being pressed? Or is that not possible in GLUT?
I tried to use the CTRL+ALT_F1 function, but it didn’t seem to work. Deleting GLUT_ACTIVE_ALT made things work with CTRL+F1.
Could you first explain why using an OR operator takes into account that you are pressing both ALT and CTRL?
Hi, I’ve tested it again, and the CTRL ALT F1 works correctly in my pc. Have you tried the ALT-F1 combination? Try printing out the values of the modifier with and without pressing the ALT key and see if you can get any hints from that.
As for the or, that’s a bitwise or. For instance if GLUT_ACTIVE_ALT is 0001 (which is 1 in decimal) and GLUT_ACTIVE_CTRL is 0010 (which is 2 in decimal) then the OR produces 0011 (which is 3), i.e. the combination of both values, bit by bit. So if the current modifier also has the same two bits has one (meaning both ALT and CTRL are being pressed), and the other two as zeros the comparison will succeed.