Resolution of X11 key-repeat handling

glutSetKeyRepeat is global to all FreeGLUT windows in the application
glutIgnoreKeyRepeat is a per-window over-ride

To avoid nasty global X11 state interaction, or GLUT-style
event queue filtering - the approach in FreeGLUT is to
use the current key state XQueryKeymap to detect and
ignore KeyRelease/KeyPress pairs that are auto-generated.

See also:
http://pyopengl.sourceforge.net/documentation/manual/glutSetKeyRepeat.3GLUT.xml
http://pyopengl.sourceforge.net/documentation/manual/glutIgnoreKeyRepeat.3GLUT.xml


git-svn-id: https://svn.code.sf.net/p/freeglut/code/trunk@476 7f0cb862-5218-0410-a997-914c9d46530a
This commit is contained in:
nigels 2004-03-14 04:36:02 +00:00
parent a291d1e0d3
commit 6065b3da65
6 changed files with 56 additions and 28 deletions

View File

@ -65,7 +65,7 @@ SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */
GL_FALSE, /* UseCurrentContext */ GL_FALSE, /* UseCurrentContext */
GL_FALSE, /* GLDebugSwitch */ GL_FALSE, /* GLDebugSwitch */
GL_FALSE, /* XSyncSwitch */ GL_FALSE, /* XSyncSwitch */
GL_FALSE, /* IgnoreKeyRepeat */ GL_TRUE, /* KeyRepeat */
0xffffffff, /* Modifiers */ 0xffffffff, /* Modifiers */
0, /* FPSInterval */ 0, /* FPSInterval */
0, /* SwapCount */ 0, /* SwapCount */
@ -272,7 +272,7 @@ void fgDeinitialize( void )
fgState.ActionOnWindowClose = GLUT_ACTION_EXIT; fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
fgState.ExecState = GLUT_EXEC_STATE_INIT; fgState.ExecState = GLUT_EXEC_STATE_INIT;
fgState.IgnoreKeyRepeat = GL_TRUE; fgState.KeyRepeat = GL_FALSE;
fgState.Modifiers = 0xffffffff; fgState.Modifiers = 0xffffffff;
fgState.GameModeSize.X = 640; fgState.GameModeSize.X = 640;

View File

@ -233,7 +233,7 @@ struct tagSFG_State
GLboolean GLDebugSwitch; /* OpenGL state debugging switch */ GLboolean GLDebugSwitch; /* OpenGL state debugging switch */
GLboolean XSyncSwitch; /* X11 sync protocol switch */ GLboolean XSyncSwitch; /* X11 sync protocol switch */
GLboolean IgnoreKeyRepeat; /* Whether to ignore key repeat. */ int KeyRepeat; /* Global key repeat mode. */
int Modifiers; /* Current ALT/SHIFT/CTRL state */ int Modifiers; /* Current ALT/SHIFT/CTRL state */
GLuint FPSInterval; /* Interval between FPS printfs */ GLuint FPSInterval; /* Interval between FPS printfs */
@ -367,10 +367,13 @@ struct tagSFG_WindowState
int Cursor; /* The currently selected cursor */ int Cursor; /* The currently selected cursor */
long JoystickPollRate; /* The joystick polling rate */ long JoystickPollRate; /* The joystick polling rate */
long JoystickLastPoll; /* When the last poll has happened */ long JoystickLastPoll; /* When the last poll happened */
int MouseX, MouseY; /* The most recent mouse position */ int MouseX, MouseY; /* The most recent mouse position */
GLboolean IgnoreKeyRepeat; /* Whether to ignore key repeat. */
GLboolean KeyRepeating; /* Currently in repeat mode */
GLboolean IsGameMode; /* Is this the game mode window? */ GLboolean IsGameMode; /* Is this the game mode window? */
GLboolean NeedToResize; /* Do we need to resize the window? */ GLboolean NeedToResize; /* Do we need to resize the window? */
GLboolean IsOffscreen; /* Tags a `window' as on/offscreen. */ GLboolean IsOffscreen; /* Tags a `window' as on/offscreen. */

View File

@ -908,6 +908,34 @@ void FGAPIENTRY glutMainLoopEvent( void )
GETWINDOW( xkey ); GETWINDOW( xkey );
GETMOUSE( xkey ); GETMOUSE( xkey );
/* Detect auto repeated keys, if configured globally or per-window */
if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE )
{
if (event.type==KeyRelease)
{
/*
* Look at X11 keystate to detect repeat mode.
* While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs.
*/
char keys[32];
XQueryKeymap( fgDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */
if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) )
window->State.KeyRepeating = GL_TRUE;
else
window->State.KeyRepeating = GL_FALSE;
}
}
else
window->State.KeyRepeating = GL_FALSE;
/* Cease processing this event if it is auto repeated */
if (window->State.KeyRepeating)
break;
if( event.type == KeyPress ) if( event.type == KeyPress )
{ {
keyboard_cb = FETCH_WCB( *window, Keyboard ); keyboard_cb = FETCH_WCB( *window, Keyboard );

View File

@ -93,49 +93,43 @@ void FGAPIENTRY glutReportErrors( void )
} }
/* /*
* Turns the ignore key auto repeat feature on and off * Control the auto-repeat of keystrokes to the current window
*
* DEPRECATED 11/4/02 - Do not use
*/ */
void FGAPIENTRY glutIgnoreKeyRepeat( int ignore ) void FGAPIENTRY glutIgnoreKeyRepeat( int ignore )
{ {
fgState.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE; freeglut_assert_ready;
freeglut_assert_window;
fgStructure.Window->State.IgnoreKeyRepeat = ignore ? GL_TRUE : GL_FALSE;
} }
/* /*
* Hints the window system whether to generate key auto repeat, or not. * Set global auto-repeat of keystrokes
* This is evil.
* *
* XXX Is this also deprecated as of 20021104? * RepeatMode should be either:
* GLUT_KEY_REPEAT_OFF
* GLUT_KEY_REPEAT_ON
* GLUT_KEY_REPEAT_DEFAULT
*/ */
void FGAPIENTRY glutSetKeyRepeat( int repeatMode ) void FGAPIENTRY glutSetKeyRepeat( int repeatMode )
{ {
#if TARGET_HOST_UNIX_X11
freeglut_assert_ready; freeglut_assert_ready;
switch( repeatMode ) switch( repeatMode )
{ {
case GLUT_KEY_REPEAT_OFF: XAutoRepeatOff( fgDisplay.Display ); break; case GLUT_KEY_REPEAT_OFF:
case GLUT_KEY_REPEAT_ON: XAutoRepeatOn( fgDisplay.Display ); break; case GLUT_KEY_REPEAT_ON:
case GLUT_KEY_REPEAT_DEFAULT: fgState.KeyRepeat = repeatMode;
{ break;
XKeyboardState keyboardState;
XGetKeyboardControl( fgDisplay.Display, &keyboardState ); case GLUT_KEY_REPEAT_DEFAULT:
glutSetKeyRepeat( fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
keyboardState.global_auto_repeat == AutoRepeatModeOn ?
GLUT_KEY_REPEAT_ON : GLUT_KEY_REPEAT_OFF
);
}
break; break;
default: default:
fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode); fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode);
break; break;
} }
#endif
} }
/* /*

View File

@ -542,7 +542,7 @@ int FGAPIENTRY glutDeviceGet( GLenum eWhat )
return 0; return 0;
case GLUT_DEVICE_IGNORE_KEY_REPEAT: case GLUT_DEVICE_IGNORE_KEY_REPEAT:
return fgState.IgnoreKeyRepeat; return fgStructure.Window ? fgStructure.Window->State.IgnoreKeyRepeat : 0;
case GLUT_DEVICE_KEY_REPEAT: case GLUT_DEVICE_KEY_REPEAT:
/* /*

View File

@ -110,6 +110,9 @@ SFG_Window* fgCreateWindow( SFG_Window* parent, const char* title,
window->IsMenu = isMenu; window->IsMenu = isMenu;
window->State.IgnoreKeyRepeat = GL_FALSE;
window->State.KeyRepeating = GL_FALSE;
/* /*
* Open the window now. The fgOpenWindow() function is system * Open the window now. The fgOpenWindow() function is system
* dependant, and resides in freeglut_window.c. Uses fgState. * dependant, and resides in freeglut_window.c. Uses fgState.