Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux/X11 input library without creating a window

Is there a good library to use for gathering user input in Linux from the mouse/keyboard/joystick that doesn't force you to create a visible window to do so? SDL lets you get user input in a reasonable way, but seems to force you to create a window, which is troublesome if you have abstracted control so the control machine doesn't have to be the same as the render machine. However, if the control and render machines are the same, this results in an ugly little SDL window on top of your display.

Edit To Clarify:
The renderer has an output window, in its normal use case, that window is full screen, except when they are both running on the same computer, just so it is possible to give the controller focus. There can actually be multiple renderers displaying a different view of the same data on different computers all controlled by the same controller, hence the total decoupling of the input from the output (Making taking advantage of the built in X11 client/server stuff for display less useable) Also, multiple controller applications for one renderer is also possible. Communication between the controllers and renderers is via sockets.

like image 952
rck Avatar asked Sep 08 '08 17:09

rck


1 Answers

OK, if you're under X11 and you want to get the kbd, you need to do a grab. If you're not, my only good answer is ncurses from a terminal.

Here's how you grab everything from the keyboard and release again:

/* Demo code, needs more error checking, compile
 * with "gcc nameofthisfile.c -lX11".

/* weird formatting for markdown follows.  argh! */

#include <X11/Xlib.h>

int main(int argc, char **argv)
{
   Display *dpy;
   XEvent ev;
   char *s;
   unsigned int kc;
   int quit = 0;

   if (NULL==(dpy=XOpenDisplay(NULL))) {
      perror(argv[0]);
      exit(1);
   }

   /*
    * You might want to warp the pointer to somewhere that you know
    * is not associated with anything that will drain events.
    *  (void)XWarpPointer(dpy, None, DefaultRootWindow(dpy), 0, 0, 0, 0, x, y);
    */

   XGrabKeyboard(dpy, DefaultRootWindow(dpy),
                 True, GrabModeAsync, GrabModeAsync, CurrentTime);

   printf("KEYBOARD GRABBED!  Hit 'q' to quit!\n"
          "If this job is killed or you get stuck, use Ctrl-Alt-F1\n"
          "to switch to a console (if possible) and run something that\n"
          "ungrabs the keyboard.\n");


   /* A very simple event loop: start at "man XEvent" for more info. */
   /* Also see "apropos XGrab" for various ways to lock down access to
    * certain types of info. coming out of or going into the server */
   for (;!quit;) {
      XNextEvent(dpy, &ev);
      switch (ev.type) {
         case KeyPress:
            kc = ((XKeyPressedEvent*)&ev)->keycode;
            s = XKeysymToString(XKeycodeToKeysym(dpy, kc, 0));
            /* s is NULL or a static no-touchy return string. */
            if (s) printf("KEY:%s\n", s);
            if (!strcmp(s, "q")) quit=~0;
            break;
         case Expose:
               /* Often, it's a good idea to drain residual exposes to
                * avoid visiting Blinky's Fun Club. */
               while (XCheckTypedEvent(dpy, Expose, &ev)) /* empty body */ ;
            break;
         case ButtonPress:
         case ButtonRelease:
         case KeyRelease:
         case MotionNotify:
         case ConfigureNotify:
         default:
            break;
      }
   }

   XUngrabKeyboard(dpy, CurrentTime);

   if (XCloseDisplay(dpy)) {
      perror(argv[0]);
      exit(1);
   }

   return 0;
}

Run this from a terminal and all kbd events should hit it. I'm testing it under Xorg but it uses venerable, stable Xlib mechanisms.

Hope this helps.

BE CAREFUL with grabs under X. When you're new to them, sometimes it's a good idea to start a time delay process that will ungrab the server when you're testing code and let it sit and run and ungrab every couple of minutes. It saves having to kill or switch away from the server to externally reset state.

From here, I'll leave it to you to decide how to multiplex renderes. Read the XGrabKeyboard docs and XEvent docs to get started. If you have small windows exposed at the screen corners, you could jam the pointer into one corner to select a controller. XWarpPointer can shove the pointer to one of them as well from code.

One more point: you can grab the pointer as well, and other resources. If you had one controller running on the box in front of which you sit, you could use keyboard and mouse input to switch it between open sockets with different renderers. You shouldn't need to resize the output window to less than full screen anymore with this approach, ever. With more work, you could actually drop alpha-blended overlays on top using the SHAPE and COMPOSITE extensions to get a nice overlay feature in response to user input (which might count as gilding the lily).

like image 93
Thomas Kammeyer Avatar answered Nov 15 '22 08:11

Thomas Kammeyer