Resolution of X11 key-repeat handling
authorNigel Stewart <nigels.com@gmail.com>
Sun, 14 Mar 2004 04:36:02 +0000 (04:36 +0000)
committerNigel Stewart <nigels.com@gmail.com>
Sun, 14 Mar 2004 04:36:02 +0000 (04:36 +0000)
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: svn+ssh://svn.code.sf.net/p/freeglut/code/trunk/freeglut/freeglut@476 7f0cb862-5218-0410-a997-914c9d46530a

src/freeglut_init.c
src/freeglut_internal.h
src/freeglut_main.c
src/freeglut_misc.c
src/freeglut_state.c
src/freeglut_structure.c

index e25404f..8fce87f 100644 (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;
index 23ff6b6..0427784 100644 (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.  */
index fb75654..1763461 100644 (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 );
index bbef626..e232d6d 100644 (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_OFF:
+    case GLUT_KEY_REPEAT_ON:
+     fgState.KeyRepeat = repeatMode;
+     break;
+
     case GLUT_KEY_REPEAT_DEFAULT:
-        {
-            XKeyboardState keyboardState;
-
-            XGetKeyboardControl( fgDisplay.Display, &keyboardState );
-            glutSetKeyRepeat(
-                keyboardState.global_auto_repeat == AutoRepeatModeOn ?
-                GLUT_KEY_REPEAT_ON : GLUT_KEY_REPEAT_OFF
-            );
-        }
-        break;
+     fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
+     break;
 
     default:
         fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode);
         break;
     }
-
-#endif
 }
 
 /*
index 2adf2a7..0ea47a4 100644 (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:
         /*
index fe172d1..498dad3 100644 (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.