Key continue repeating if setting global autorepeat off while the key was already repeating.

Octavio Alvarez alvarezp at alvarezp.ods.org
Sun Nov 22 20:27:47 PST 2009


Hi.

If I turn global autorepeat off while a key is already being repeated,
the key doesn't stop repeating. It continues on and on.

I have prepared the following code for demonstrating the issue: reptest.c

After the code, I quote 5 results from tests by running this code. The
tests involve pressing a combination of a hotkey (in this code, Super_L)
and the letter "k" in different combinations and timing.

Tests A and B are OK, but tests C and D are not.

Tests A, B, C, and D are under plain X11: startx `which xterm` -- :1

I'm running X.org version 1.6.5 under Debian Sid. I think (but not sure)
I'm using the evdev driver.

A friend tried test D for me under 1.7.1.901 and happens too.

I tried putting a lot of XFlush(dpy) all over the place, but it still
happens.

evtest and showkey output look pretty normal to me, but I can attach a
sample if needed.

This problem happens also under Ubuntu Jaunty box (X 7.4, 1.6.0) but
I remember previous distros not failing. Say Ubuntu Hardy or Gutsy and
before.

Is it a bug, or am I missing something? Thanks.

/*
    * reptest.c: extract from Superkb to test autorepeat misbehavior.
    *
    * Copyright (C) 2005-2009, Octavio Alvarez Piza.
    * License: GNU General Public License v2.
    *
    * Compile with: gcc -Wall -std=gnu99 -pedantic -lX11 -o reptest  
reptest.c
    */

#include <X11/Xlib.h>

#include <errno.h>
#include <stdio.h>
#include <stdarg.h>

int main()
{

      /* X11 connection setup */
      Display *dpy;
      dpy = XOpenDisplay(NULL);

      /* Get code for "Super_L", as a sample hotkey. */
      KeyCode hotkey;
      hotkey = XKeysymToKeycode(dpy, XStringToKeysym("Super_L"));

      Window rootwin;
      rootwin = DefaultRootWindow(dpy);

      /* Grab the hotkey */
      XGrabKey(dpy, hotkey, AnyModifier, rootwin, True,
         GrabModeAsync, GrabModeAsync);

      XKeyboardState xkbs;

      /* Save hotkey autorepeat state */
      int saved_hotkey_autorepeat_mode;
      XGetKeyboardControl(dpy, &xkbs);
      saved_hotkey_autorepeat_mode = (xkbs.auto_repeats[(int) hotkey/8] &
         hotkey % 8) > 0;

      /* Turn autorepeat off for the hotkey */
      XKeyboardControl xkbc;
      xkbc.key = hotkey;
      xkbc.auto_repeat_mode = AutoRepeatModeOff;
      XChangeKeyboardControl(dpy, KBAutoRepeatMode | KBKey, &xkbc);

      /* This variable holds the autorepeat state for the whole keyboard
         while the hotkey is NOT pressed. */
      int saved_autorepeat_mode = 0;

      while (1) {

         XEvent ev;

         XNextEvent(dpy, &ev);

         if (ev.xkey.keycode == hotkey && ev.type == KeyPress) {

            printf("[sk] Hotkey has been pressed, code: %d, name: %s.\n",
               ev.xkey.keycode,
               XKeysymToString(XKeycodeToKeysym(dpy, ev.xkey.keycode, 0)));

            XKeyboardState xkbs;

            /* Save autorepeat current state state, in order to restore it
               after hotkey is released. Autorepeat will be turned off
               in the meanwhile. */
            XGetKeyboardControl(dpy, &xkbs);
            saved_autorepeat_mode = xkbs.global_auto_repeat;

            printf("[ar] AutoRepeat state has been saved: %d.\n",
               saved_autorepeat_mode);

            /* Turn autorepeat off. */
            XKeyboardControl xkbc;
            xkbc.auto_repeat_mode = AutoRepeatModeOff;
            XChangeKeyboardControl(dpy, KBAutoRepeatMode, &xkbc);

            printf("[ar] AutoRepeat state has been turned off.\n");

            /* Starting the "active mechanism" by grabbing the kb. */
            XGrabKeyboard(dpy, rootwin, False, GrabModeAsync,
               GrabModeAsync, CurrentTime);

         } else if (ev.xkey.keycode == hotkey && ev.type == KeyRelease) {

            printf("[sk] Hotkey has been released, code: %d, name: %s.\n",
               ev.xkey.keycode,
               XKeysymToString(XKeycodeToKeysym(dpy, ev.xkey.keycode, 0)));

            /* Restore saved_autorepeat_mode. */
            XKeyboardControl xkbc;
            xkbc.auto_repeat_mode = saved_autorepeat_mode;
            XChangeKeyboardControl(dpy, KBAutoRepeatMode, &xkbc);

            printf("[ar] AutoRepeat has been restored to: %d\n",
               saved_autorepeat_mode);

            /* End the "active state" by ungrabbing the keyboard. */
            XUngrabKeyboard(dpy, CurrentTime);

            printf("---------------------------------------------\n");

         } else if (ev.type == KeyRelease) {
            /* Released any other key. */
            printf("[ac] Due to bound key release, executed action for"
               " key code = %d, name: %s\n", ev.xkey.keycode,
               XKeysymToString(XKeycodeToKeysym(dpy, ev.xkey.keycode, 0)));
         }

      }
}




[Sun Nov 22 16:48:20 -0800 -- alvarezp at octavio:~/temp/xorg-repeat-test]
$ ./reptest

=== TEST A: HOLD HOTKEY, HIT K, RELEASE HOTKEY ==
[sk] Hotkey has been pressed, code: 133, name: Super_L.
[ar] AutoRepeat state has been saved: 1.
[ar] AutoRepeat state has been turned off.
[ac] Due to bound key release, executed action for key code = 45, name: k
[sk] Hotkey has been released, code: 133, name: Super_L.
[ar] AutoRepeat has been restored to: 1
---------------------------------------------

== TEST B: HOLD HOTKEY, HOLD K, RELEASE K, RELEASE HOTKEY ==
[sk] Hotkey has been pressed, code: 133, name: Super_L.
[ar] AutoRepeat state has been saved: 1.
[ar] AutoRepeat state has been turned off.
[ac] Due to bound key release, executed action for key code = 45, name: k
[sk] Hotkey has been released, code: 133, name: Super_L.
[ar] AutoRepeat has been restored to: 1
---------------------------------------------

== TEST C: HOLD K, LET AUTOREPEAT, HOLD HOTKEY, RELEASE HOTKEY,
==         RELEASE K ==
kkkkkkkkkkkkkkkk[sk] Hotkey has been pressed, code: 133, name: Super_L.
[ar] AutoRepeat state has been saved: 1.
[ar] AutoRepeat state has been turned off.
        [ == AUTOREPEAT IS OFF NOW. REPETITIONS SHOULDN'T HAVE HAPPENED == ]
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[sk] Hotkey has been released, code: 133, name: Super_L.
[ar] AutoRepeat has been restored to: 1
---------------------------------------------
kkkkkkkkkkkkkkk [ == K RELEASED == ]


== TEST D: HOLD K, LET AUTOREPEAT, HOLD HOTKEY, RELEASE K,
==         RELEASE HOTKEY, LET RUN AND HIT K AGAIN TO FIX (UNDER PLAIN
==         X11) ==
kkkkkkkkkkkk[sk] Hotkey has been pressed, code: 133, name: Super_L.
[ar] AutoRepeat state has been saved: 1.
[ar] AutoRepeat state has been turned off.
        [ == AUTOREPEAT IS OFF NOW. REPETITIONS SHOULDN'T HAVE HAPPENED == ]
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
[ac] Due to bound key release, executed action for key code = 45, name: k
        [ == K RELEASED == ]
        [ == HOTKEY RELEASED == ]
[sk] Hotkey has been released, code: 133, name: Super_L.
[ar] AutoRepeat has been restored to: 1
---------------------------------------------

[ == TESTS DONE == ]
^C



More information about the xorg mailing list