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, /* GLDebugSwitch */
GL_FALSE, /* XSyncSwitch */
GL_FALSE, /* IgnoreKeyRepeat */
GL_TRUE, /* KeyRepeat */
0xffffffff, /* Modifiers */
0, /* FPSInterval */
0, /* SwapCount */
@ -272,7 +272,7 @@ void fgDeinitialize( void )
fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
fgState.ExecState = GLUT_EXEC_STATE_INIT;
fgState.IgnoreKeyRepeat = GL_TRUE;
fgState.KeyRepeat = GL_FALSE;
fgState.Modifiers = 0xffffffff;
fgState.GameModeSize.X = 640;

View File

@ -233,7 +233,7 @@ struct tagSFG_State
GLboolean GLDebugSwitch; /* OpenGL state debugging 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 */
GLuint FPSInterval; /* Interval between FPS printfs */
@ -367,10 +367,13 @@ struct tagSFG_WindowState
int Cursor; /* The currently selected cursor */
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 */
GLboolean IgnoreKeyRepeat; /* Whether to ignore key repeat. */
GLboolean KeyRepeating; /* Currently in repeat mode */
GLboolean IsGameMode; /* Is this the game mode window? */
GLboolean NeedToResize; /* Do we need to resize the window? */
GLboolean IsOffscreen; /* Tags a `window' as on/offscreen. */

View File

@ -908,6 +908,34 @@ void FGAPIENTRY glutMainLoopEvent( void )
GETWINDOW( 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 )
{
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
*
* DEPRECATED 11/4/02 - Do not use
* Control the auto-repeat of keystrokes to the current window
*/
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.
* This is evil.
* Set global auto-repeat of keystrokes
*
* 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 )
{
#if TARGET_HOST_UNIX_X11
freeglut_assert_ready;
switch( repeatMode )
{
case GLUT_KEY_REPEAT_OFF: XAutoRepeatOff( fgDisplay.Display ); break;
case GLUT_KEY_REPEAT_ON: XAutoRepeatOn( fgDisplay.Display ); break;
case GLUT_KEY_REPEAT_DEFAULT:
{
XKeyboardState keyboardState;
case GLUT_KEY_REPEAT_OFF:
case GLUT_KEY_REPEAT_ON:
fgState.KeyRepeat = repeatMode;
break;
XGetKeyboardControl( fgDisplay.Display, &keyboardState );
glutSetKeyRepeat(
keyboardState.global_auto_repeat == AutoRepeatModeOn ?
GLUT_KEY_REPEAT_ON : GLUT_KEY_REPEAT_OFF
);
}
case GLUT_KEY_REPEAT_DEFAULT:
fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
break;
default:
fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode);
break;
}
#endif
}
/*

View File

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

View File

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