Help end child hunger

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”

  1. 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.

  2. 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.

  3. 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?

  4. 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

  5. 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?

  6. 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.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: