You are not logged in.

#1 2008-12-08 00:35:45

cmtptr
Member
Registered: 2008-09-01
Posts: 135

[SOLVED kindof?] (C) Xlib, catching keyboard events without autorepeat

Hi,

I know how to use XNextEvent or XCheckWindowEvent to capture KeyPress and KeyRelease XEvents, but does anyone know of a different method which is not susceptible to autorepeat?

I've been Googling like mad and all I found were several lame, circumventing solutions from measuring the time between KeyReleases and KeyPresses and ignoring them if they're too fast to calling XAutoRepeatOff when the window has focus and XAutoRepeatOn when the window loses focus.  I would prefer a "real" solution to this, especially over the latter which could leave the user stuck without autorepeating should the program happen to terminate abnormally and he or she doesn't know how to reenable it.

Doesn't Xlib offer a method for catching physical keyboard events and won't also catch keyboard autorepeating?

The following is a short example of what I've been using which illustrates the autorepeating.

/*
 * test.c
 * compile with...
 *   cc -otest -lX11 test.c
 */

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

#define EVENT_MASK KeyPressMask | KeyReleaseMask

static Display *g_xdisplay;
static Window   g_xwindow;

static void xeventProcess()
{
  XEvent xevent;

  XSelectInput(g_xdisplay, g_xwindow, EVENT_MASK);

  while(1)
  {
    while(XPending(g_xdisplay) > 0)
    {
      XNextEvent(g_xdisplay, &xevent);
      switch(xevent.type)
      {
        case KeyPress:
          printf("Key pressed: %s\n", XKeysymToString(XKeycodeToKeysym(g_xdisplay, xevent.xkey.keycode, 0)));
          if(XLookupKeysym(&xevent.xkey, 0) == XK_Escape)
            return;
          break;
        case KeyRelease:
          printf("Key released: %s\n", XKeysymToString(XKeycodeToKeysym(g_xdisplay, xevent.xkey.keycode, 0)));
          break;
      }
    }
  }

  return;
}

int main(int argc, char **argv)
{
  g_xdisplay = XOpenDisplay(0);
  if(!g_xdisplay)
    return 0;

  g_xwindow = XCreateSimpleWindow(g_xdisplay, DefaultRootWindow(g_xdisplay), 0, 0, \
      128, 128, 0, BlackPixel(g_xdisplay, 0), BlackPixel(g_xdisplay, 0));

  XMapWindow(g_xdisplay, g_xwindow);
  XFlush(g_xdisplay);

  xeventProcess();
  
  return 0;
}

Thanks.

Last edited by cmtptr (2008-12-09 20:57:03)

Offline

#2 2008-12-09 08:39:03

dav7
Member
From: Australia
Registered: 2008-02-08
Posts: 674

Re: [SOLVED kindof?] (C) Xlib, catching keyboard events without autorepeat

I read this yesterday and wondered about a response, but there's nothing I can think of that might be helpful, except for these four points.

#1) Why don't you want to receive multiple keypresses? If people know why, they might be able to suggest possible alternate solutions.

#2) You've most likely discovered tronche.com/xlib - this page is probably the most help you'll get. It covers X events: http://tronche.com/gui/x/xlib/events/pr … rview.html

#3) Take a look at what XCB's standpoint on this is - if autorepeat is an X protocol thing, XCB will have this issue as well, but it might be specific to Xlib.

#4) This isn't exactly related to your problem, but I couldn't help noting that there are several areas in the code that could be written a little differently, IMHO. No offense intended tongue

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

int main() {
    
    XEvent event;
    Display display;
    Window window;
    int screen;
    
    if (!(display = XOpenDisplay(0))) return 1;
    
    screen = DefaultScreen(display);
    
    window = XCreateSimpleWindow(display, RootWindow(display, screen), 0, 0, 128, 128, 0, BlackPixel(display, screen), BlackPixel(display, screen));
    
    XMapWindow(display, window);
    
    XSelectInput(display, window, KeyPressMask | KeyReleaseMask);
    
    while(XPending(display)) {
        XNextEvent(display, &event);
        switch(xevent.type) {
            case KeyPress:
                printf("Key pressed: %s\n", XKeysymToString(XKeycodeToKeysym(display, event.xkey.keycode, 0)));
                if(XLookupKeysym(&event.xkey, 0) == XK_Escape) return 0;
                break;
            case KeyRelease:
                printf("Key released: %s\n", XKeysymToString(XKeycodeToKeysym(display, event.xkey.keycode, 0)));
                break;
            default:
                break;
        }
    }
    
    return 0;
    
}

Last edited by dav7 (2008-12-09 08:41:51)


Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.

Offline

#3 2008-12-09 15:42:34

cmtptr
Member
Registered: 2008-09-01
Posts: 135

Re: [SOLVED kindof?] (C) Xlib, catching keyboard events without autorepeat

#1) I don't want to receive autorepeating because I want to be able to handle things fluidly over a period of time while the user is physically holding a key down.  Also, in the future I may want my program to be able to identify double-taps of a key.  With autorepeating enabled, the program will notice several KeyRelease and KeyPress events over this time period, which is undesirable.  In fact, the only application I can imagine autorepeating being of any use would be for some kind of text editor...

#2) I hadn't discovered tronche.com/xlib.  Thanks for the link, this will certainly be going in my bookmarks.

#3) I hadn't even heard of XCB until about 30 minutes after posting this thread.  I glanced at the website, but I didn't see any references to this... in fact, I didn't see much documentation at all.  What I did find on keyboard events I tried in a simple xcb-test program, and it also captured autorepeating.

#4) No offense taken, because it was just a simple example sloppily thrown together in a couple of seconds wink.  But it looks like the only major change you made was to move the xeventProcess function directly into the main loop, which I had included separately to be explicit for this example.  Also, without some kind of loop outside the "while(XPending(display))" the application will blow right through that and return 0 before the user even has a chance to see the window.  I appreciate your suggestions, but all your other changes seem purely aesthetic, and personally I find my coding style more readable to me, no offense.

Thanks for your response.

[edit]:
Someone in #xorg-devel has directed me to "XSetDetectableAutoRepeat(display, 1, 0);".  While this is not exactly what I wanted (it only supresses auto-repeating KeyRelease events), it does suffice for my purposes.  Still, if anyone has other, more complete solutions I'd be interested to see them!

Thanks again.

Last edited by cmtptr (2008-12-09 20:55:51)

Offline

Board footer

Powered by FluxBB