Issue with multiple keys pressed

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
", 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;
}

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. There might have something similar under Windows.

Thanks for the suggestions, I will try more options.

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
", 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
", 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();
   
}

So my next step is to research timers.

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.