PDA

View Full Version : Issue with multiple keys pressed



thor4000
01-07-2018, 05:37 PM
In this program, I can press up to 3 characters('s' 'e' and 'f') simultaneously. The issue I have is when I release the most recently pressed button and I have at least one button still pressed. The remaining pressed keys no longer trigger the display update. It works if I release any other button other than the most recently pressed. I watch the console to keep track of which buttons are pressed. Any help is appreciated. Thanks.


#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdbool.h>

bool keyStates[256]; //Key state values


void display(void)
{
printf("KeyPressed %d%d%d\n", keyStates['s'], keyStates['e'], keyStates['f']);

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT); // Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations



glFlush(); // Flush the OpenGL buffers to the window
}

void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (0.0, 0.0, -5.0);
}

void keyPressed (unsigned char key, int x, int y)
{
keyStates[key] = true; // Set the state of the current key to pressed
glutPostRedisplay();

}

void keyUp (unsigned char key, int x, int y)
{
keyStates[key] = false; // Set the state of the current key to not pressed
glutPostRedisplay();
}


int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel (GL_FLAT);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardUpFunc(keyUp);
glutKeyboardFunc(keyPressed);
glutMainLoop();
return 0;
}

Silence
01-08-2018, 12:14 AM
Several possibilities:

Might be a glut limitation.
Might be your keyboard limitation (most likely). If you are under Linux, use xinput to try to check that. An exemple is shown as an answer here (https://superuser.com/questions/248517/show-keys-pressed-in-linux). There might have something similar under Windows.

thor4000
01-08-2018, 11:51 AM
Thanks for the suggestions, I will try more options.

thor4000
01-08-2018, 12:04 PM
After doing some more research, I realized that I need to use the glutIdleFunc and check if any keys are pressed inside the idle function. If there are any keys pressed, the glutPostRedisplay function is called, to redraw the window. The keyPressed and keyUp functions just change the boolean state for the key in the key event. The idle function is called quite often, so one has to decide how much delay they want between glutPostRedisplay calls. My previous technique failed because under specific circumstances, the glutPostRedisplay wasn't being called by continuously pressed keys, although the program knew that they were still pressed. Using the idle function ensures that redisplays will be done if desired conditions are met. Thank you for your suggestions, Silence. Here were the links I found that said to use idle function:

https://www.gamedev.net/forums/topic/588140-how-to-detect-multiple-key-presses-in-opengl/
http://www.swiftless.com/tutorials/opengl/keyboard.html

New Code:


#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdbool.h>
#include <stdio.h>

bool keyStates[256]; //Key state values


void display(void)
{
printf("KeyPressed %d%d%d\n", keyStates['s'], keyStates['e'], keyStates['f']);

glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our window to red
glClear(GL_COLOR_BUFFER_BIT); // Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations

glFlush(); // Flush the OpenGL buffers to the window
}

void idle()
{
if(keyStates['s'] || keyStates['e'] || keyStates['f']){
printf("KeyPressed %d%d%d\n", keyStates['s'], keyStates['e'], keyStates['f']);
glutPostRedisplay();
}
}

void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW);

}

void keyPressed (unsigned char key, int x, int y)
{
keyStates[key] = true; // Set the state of the current key to pressed

}

void keyUp (unsigned char key, int x, int y)
{
keyStates[key] = false; // Set the state of the current key to not pressed

}


int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow (argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardUpFunc(keyUp);
glutKeyboardFunc(keyPressed);
glutMainLoop();

}

thor4000
01-08-2018, 12:15 PM
So my next step is to research timers.

GClements
01-08-2018, 04:21 PM
I wouldn't have an idle callback which doesn't do significant work (e.g. one which simply calls glutPostRedisplay()), as this guarantees 100% usage of a CPU core. The idle callback is invoked repeatedly while no events are pending.

If you want continuous animation at the monitor's refresh rate (or as fast as the system can handle if it can't keep up with the refresh rate), call glutPostRedisplay() from the display callback.