"Fossies" - the Fresh Open Source Software Archive

Member "xscreensaver-6.01/driver/xinput.c" (4 Jun 2021, 14279 Bytes) of package /linux/misc/xscreensaver-6.01.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xinput.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.00_vs_6.01.

    1 /* xscreensaver, Copyright © 1991-2021 Jamie Zawinski <jwz@jwz.org>
    2  *
    3  * Permission to use, copy, modify, distribute, and sell this software and its
    4  * documentation for any purpose is hereby granted without fee, provided that
    5  * the above copyright notice appear in all copies and that both that
    6  * copyright notice and this permission notice appear in supporting
    7  * documentation.  No representations are made about the suitability of this
    8  * software for any purpose.  It is provided "as is" without express or 
    9  * implied warranty.
   10  */
   11 
   12 #ifdef HAVE_CONFIG_H
   13 # include "config.h"
   14 #endif
   15 
   16 #include <stdio.h>
   17 #include <stdlib.h>
   18 #include <string.h>
   19 
   20 #include <X11/Xlib.h>
   21 #include <X11/Xutil.h>
   22 #include <X11/extensions/XInput2.h>
   23 
   24 #include "blurb.h"
   25 #include "xinput.h"
   26 
   27 extern Bool debug_p;
   28 
   29 #undef countof
   30 #define countof(x) (sizeof((x))/sizeof((*x)))
   31 
   32 
   33 /* Initialize the XInput2 extension. Returns True on success.
   34  */
   35 Bool
   36 init_xinput (Display *dpy, int *opcode_ret)
   37 {
   38   int nscreens = ScreenCount (dpy);
   39   XIEventMask evmasks[1];
   40   unsigned char mask1[(XI_LASTEVENT + 7)/8];
   41   int major, minor;
   42   int xi_opcode, ev, err;
   43   int i;
   44   int ndevs = 0;
   45   XIDeviceInfo *devs;
   46 
   47   if (!XQueryExtension (dpy, "XInputExtension", &xi_opcode, &ev, &err))
   48     {
   49       fprintf (stderr, "%s: XInput extension missing\n", blurb());
   50       return False;
   51     }
   52 
   53   major = 2;    /* Desired version */
   54   minor = 2;
   55   if (XIQueryVersion (dpy, &major, &minor) != Success)
   56     {
   57       fprintf (stderr, "%s: server only supports XInput %d.%d\n",
   58                blurb(), major, minor);
   59       return False;
   60     }
   61 
   62   if (verbose_p)
   63     fprintf (stderr, "%s: XInput version %d.%d\n", blurb(), major, minor);
   64 
   65   memset (mask1, 0, sizeof(mask1));
   66 
   67   XISetMask (mask1, XI_RawMotion);
   68   XISetMask (mask1, XI_RawKeyPress);
   69   XISetMask (mask1, XI_RawKeyRelease);
   70   XISetMask (mask1, XI_RawButtonPress);
   71   XISetMask (mask1, XI_RawButtonRelease);
   72   XISetMask (mask1, XI_RawTouchBegin);
   73   XISetMask (mask1, XI_RawTouchUpdate);
   74   XISetMask (mask1, XI_RawTouchEnd);
   75 
   76   /* If we use XIAllDevices instead, we get double events. */
   77   evmasks[0].deviceid = XIAllMasterDevices;
   78   evmasks[0].mask_len = sizeof(mask1);
   79   evmasks[0].mask = mask1;
   80 
   81   for (i = 0; i < nscreens; i++)
   82     {
   83       Window root = RootWindow (dpy, i);
   84       if (XISelectEvents (dpy, root, evmasks, countof(evmasks)) != Success)
   85         {
   86           fprintf (stderr, "%s: XISelectEvents failed\n", blurb());
   87           return False;
   88         }
   89     }
   90 
   91   XFlush (dpy);
   92 
   93   devs = XIQueryDevice (dpy, XIAllDevices, &ndevs);
   94   if (!ndevs)
   95     {
   96       fprintf (stderr, "%s: XInput: no devices\n", blurb());
   97       return False;
   98     }
   99 
  100   if (verbose_p)
  101     for (i = 0; i < ndevs; i++)
  102       {
  103         XIDeviceInfo *d = &devs[i];
  104         fprintf (stderr, "%s:   device %2d/%d: %s: %s\n",
  105                  blurb(), d->deviceid, d->attachment, 
  106                  (d->use == XIMasterPointer  ? "MP" :
  107                   d->use == XIMasterKeyboard ? "MK" :
  108                   d->use == XISlavePointer   ? "SP" :
  109                   d->use == XISlaveKeyboard  ? "SK" :
  110                   d->use == XIFloatingSlave  ? "FS" : "??"),
  111                  d->name);
  112       }
  113 
  114   XIFreeDeviceInfo (devs);
  115   *opcode_ret = xi_opcode;
  116   return True;
  117 }
  118 
  119 
  120 /* If there is more than one Screen on the Display, XInput2 sends a duplicate
  121    event for each Screen.  You'd think that they would have the 'root' member
  122    set to the root window of that screen, so that we could ignore events not
  123    destined for our screen, but no, they all have the same root window.  But
  124    they also have the same 'serial' and 'time', so (in theory) we can ignore
  125    the duplicates by noticing recently-duplicated event serial numbers, which
  126    ought never happen.  BUT...!
  127  */
  128 static Bool
  129 duplicate_xinput_event_p (int evtype, XIDeviceEvent *in)
  130 {
  131   static unsigned long dups[50] = { 0, };
  132   int i;
  133 
  134   /* Great news, everybody: XEvent.xany.serial is apparently not unique.  Wny?
  135      Because fuck you that's why.  XtAppNextEvent is returning a RawKeyRelease
  136      followed by a RawKeyPress with the same serial.  It doesn't happen every
  137      time, but seems to happen most often if a second key goes down before the
  138      first key is released, e.g., which often happens when typing fast.
  139 
  140      I have not seen it duplicating serials between two different KeyPress
  141      events, but I have seen it being duplicated between a KeyPress and a
  142      non-corresponding KeyRelease event; and between two different KeyRelease
  143      events.  It does this even when there is only one Screen.
  144 
  145      So we must compare both 'serial' and 'type' when looking for duplicates.
  146      This should be ok if it really does not duplicate serials between
  147      unrelated KeyPress events.  And we ignore KeyRelease events, so what
  148      happens with those doesn't matter.
  149 
  150      Between this shit and the random noise that shows up in XIDeviceEvent,
  151      I'm starting to suspect that maybe, just maybe, the XInput2 library is
  152      extremely careless about memory management!
  153    */
  154   unsigned long key = (in->serial & 0xFFFF) | (evtype << 16);
  155 
  156   for (i = 0; i < countof(dups); i++)
  157     if (dups[i] == key)
  158       {
  159         if (debug_p)
  160           fprintf (stderr, "%s: discard duplicate XInput event %08lx\n",
  161                    blurb(), key);
  162         return True;
  163       }
  164   for (i = 0; i < countof(dups)-1; i++)
  165     dups[i] = dups[i+1];
  166   dups[i] = key;
  167   return False;
  168 }
  169 
  170 
  171 /* Convert an XInput2 event to corresponding old-school Xlib event.
  172    Returns true on success.
  173  */
  174 static Bool
  175 xinput_event_to_xlib_1 (int evtype, XIDeviceEvent *in, XEvent *out)
  176 {
  177   Display *dpy = in->display;
  178   Bool ok = False;
  179 
  180   int root_x = 0, root_y = 0;
  181   unsigned int mods = 0;
  182 
  183   /* The closest thing to actual documentation on XInput2 seems to be a series
  184      of blog posts by Peter Hutterer.  There's basically nothing about it on
  185      www.x.org.  In http://who-t.blogspot.com/2009/07/xi2-recipes-part-4.html
  186      he says: 
  187 
  188        "XIDeviceEvent [...] contains the state of the modifier keys [...]
  189        The base modifiers are the ones currently pressed, latched the ones
  190        pressed until a key is pressed that's configured to unlatch it (e.g.
  191        some shift-capslock interactions have this behaviour) and finally
  192        locked modifiers are the ones permanently active until unlocked
  193        (default capslock behaviour in the US layout). The effective modifiers
  194        are a bitwise OR of the three above - which is essentially equivalent
  195        to the modifiers state supplied in the core protocol events."
  196 
  197      However, I'm seeing random noise in the various XIDeviceEvent.mods fields.
  198      Nonsensical values like base = 0x6045FB3D.  So, let's poll the actual
  199      modifiers from XQueryPointer.  This can race: maybe the modifier state
  200      changed between when the server generated the keyboard event, and when
  201      we receive it and poll.  However, if an actual human is typing and
  202      releasing their modifier keys on such a tight timeframe... that's
  203      probably already not going well.
  204 
  205      I'm also seeing random noise in the event_xy and root_xy fields in
  206      motion events.  So just always use XQueryPointer.
  207    */
  208   switch (evtype) {
  209   case XI_RawKeyPress:
  210   case XI_RawKeyRelease:
  211   case XI_RawButtonPress:
  212   case XI_RawButtonRelease:
  213   case XI_RawMotion:
  214     {
  215       Window root_ret, child_ret;
  216       int win_x, win_y;
  217       int i;
  218       for (i = 0; i < ScreenCount (dpy); i++)   /* query on correct screen */
  219         if (XQueryPointer (dpy, RootWindow (dpy, i),
  220                            &root_ret, &child_ret, &root_x, &root_y,
  221                            &win_x, &win_y, &mods))
  222           break;
  223     }
  224   default: break;
  225   }
  226 
  227   switch (evtype) {
  228   case XI_RawKeyPress:
  229   case XI_RawKeyRelease:
  230     out->xkey.type      = (evtype == XI_RawKeyPress ? KeyPress : KeyRelease);
  231     out->xkey.display   = in->display;
  232     out->xkey.window    = in->event;
  233     out->xkey.root      = in->root;
  234     out->xkey.subwindow = in->child;
  235     out->xkey.time      = in->time;
  236     out->xkey.x         = root_x;
  237     out->xkey.y         = root_y;
  238     out->xkey.x_root    = root_x;
  239     out->xkey.y_root    = root_y;
  240     out->xkey.state     = mods;
  241     out->xkey.keycode   = in->detail;
  242     ok = True;
  243     break;
  244   case XI_RawButtonPress:
  245   case XI_RawButtonRelease:
  246     out->xbutton.type      = (evtype == XI_RawButtonPress 
  247                               ? ButtonPress : ButtonRelease);
  248     out->xbutton.display   = in->display;
  249     out->xbutton.window    = in->event;
  250     out->xbutton.root      = in->root;
  251     out->xbutton.subwindow = in->child;
  252     out->xbutton.time      = in->time;
  253     out->xbutton.x         = root_x;
  254     out->xbutton.y         = root_y;
  255     out->xbutton.x_root    = root_x;
  256     out->xbutton.y_root    = root_y;
  257     out->xbutton.state     = mods;
  258     out->xbutton.button    = in->detail;
  259     ok = True;
  260     break;
  261   case XI_RawMotion:
  262     out->xmotion.type      = MotionNotify;
  263     out->xmotion.display   = in->display;
  264     out->xmotion.window    = in->event;
  265     out->xmotion.root      = in->root;
  266     out->xmotion.subwindow = in->child;
  267     out->xmotion.time      = in->time;
  268     out->xmotion.x         = root_x;
  269     out->xmotion.y         = root_y;
  270     out->xmotion.x_root    = root_x;
  271     out->xmotion.y_root    = root_y;
  272     out->xmotion.state     = mods;
  273     ok = True;
  274     break;
  275   default:
  276     break;
  277   }
  278 
  279   return ok;
  280 }
  281 
  282 Bool
  283 xinput_event_to_xlib (int evtype, XIDeviceEvent *in, XEvent *out)
  284 {
  285   Bool ok = xinput_event_to_xlib_1 (evtype, in, out);
  286   if (ok && duplicate_xinput_event_p (evtype, in))
  287     ok = False;
  288   return ok;
  289 }
  290 
  291 
  292 
  293 static void
  294 print_kbd_event (XEvent *xev, XComposeStatus *compose, Bool x11_p)
  295 {
  296   if (debug_p)      /* Passwords show up in plaintext! */
  297     {
  298       KeySym keysym = 0;
  299       char c[100];
  300       char M[100], *mods = M;
  301       int n = XLookupString (&xev->xkey, c, sizeof(c)-1, &keysym, compose);
  302       const char *ks = keysym ? XKeysymToString (keysym) : "NULL";
  303       c[n] = 0;
  304       if      (*c == '\n') strcpy (c, "\\n");
  305       else if (*c == '\r') strcpy (c, "\\r");
  306       else if (*c == '\t') strcpy (c, "\\t");
  307 
  308       *mods = 0;
  309       if (xev->xkey.state & ShiftMask)   strcat (mods, "-Sh");
  310       if (xev->xkey.state & LockMask)    strcat (mods, "-Lk");
  311       if (xev->xkey.state & ControlMask) strcat (mods, "-C");
  312       if (xev->xkey.state & Mod1Mask)    strcat (mods, "-M1");
  313       if (xev->xkey.state & Mod2Mask)    strcat (mods, "-M2");
  314       if (xev->xkey.state & Mod3Mask)    strcat (mods, "-M3");
  315       if (xev->xkey.state & Mod4Mask)    strcat (mods, "-M4");
  316       if (xev->xkey.state & Mod5Mask)    strcat (mods, "-M5");
  317       if (*mods) mods++;
  318       if (!*mods) strcat (mods, "0");
  319 
  320       fprintf (stderr, "%s: %s    0x%02X %s %s \"%s\"\n", blurb(),
  321                (x11_p
  322                 ? (xev->xkey.type == KeyPress
  323                    ? "X11 KeyPress    "
  324                    : "X11 KeyRelease  ")
  325                 : (xev->xkey.type == KeyPress
  326                    ? "XI_RawKeyPress  "
  327                    : "XI_RawKeyRelease")),
  328                xev->xkey.keycode, mods, ks, c);
  329     }
  330   else          /* Log only that the KeyPress happened. */
  331     {
  332       fprintf (stderr, "%s: X11 Key%s\n", blurb(),
  333                (xev->xkey.type == KeyPress ? "Press  " : "Release"));
  334     }
  335 }
  336 
  337 
  338 void
  339 print_xinput_event (Display *dpy, XEvent *xev, const char *desc)
  340 {
  341   XIRawEvent *re;
  342 
  343   switch (xev->xany.type) {
  344   case KeyPress:
  345   case KeyRelease:
  346     {
  347       static XComposeStatus compose = { 0, };
  348       print_kbd_event (xev, &compose, True);
  349     }
  350     break;
  351 
  352   case ButtonPress:
  353   case ButtonRelease:
  354     fprintf (stderr, "%s: X11 Button%s   %d %d\n", blurb(),
  355              (xev->xany.type == ButtonPress ? "Press  " : "Release"),
  356              xev->xbutton.button, xev->xbutton.state);
  357     break;
  358 
  359   case MotionNotify:
  360     fprintf (stderr, "%s: X11 MotionNotify   %4d, %-4d"
  361              "                   %s\n",
  362              blurb(), xev->xmotion.x_root, xev->xmotion.y_root,
  363              (desc ? desc : ""));
  364     break;
  365   default:
  366     break;
  367   }
  368 
  369   if (xev->xany.type != GenericEvent)
  370     return;  /* not an XInput event */
  371   
  372   if (!xev->xcookie.data)
  373     XGetEventData (dpy, &xev->xcookie);
  374 
  375   re = xev->xcookie.data;
  376   if (!re) return; /* Bogus XInput event */
  377 
  378   switch (re->evtype) {
  379   case XI_RawKeyPress:
  380   case XI_RawKeyRelease:
  381     if (debug_p)
  382       {
  383         /* Fake up an XKeyEvent in order to call XKeysymToString(). */
  384         XEvent ev2;
  385         Bool ok = xinput_event_to_xlib_1 (re->evtype,
  386                                           (XIDeviceEvent *) re,
  387                                           &ev2);
  388         if (!ok)
  389           fprintf (stderr, "%s: unable to translate XInput2 event\n", blurb());
  390         else
  391           {
  392             static XComposeStatus compose = { 0, };
  393             print_kbd_event (&ev2, &compose, False);
  394           }
  395         break;
  396       }
  397     else
  398       fprintf (stderr, "%s: XI RawKey%s\n", blurb(),
  399                (re->evtype == XI_RawKeyPress ? "Press  " : "Release"));
  400     break;
  401 
  402   case XI_RawButtonPress:
  403   case XI_RawButtonRelease:
  404     fprintf (stderr, "%s: XI RawButton%s %d\n", blurb(),
  405              (re->evtype == XI_RawButtonPress ? "Press  " : "Release"),
  406              re->detail);
  407     break;
  408 
  409   case XI_RawMotion:
  410     if (verbose_p > 1)
  411       {
  412         Window root_ret, child_ret;
  413         int root_x, root_y;
  414         int win_x, win_y;
  415         unsigned int mask;
  416         XQueryPointer (dpy, DefaultRootWindow (dpy),
  417                        &root_ret, &child_ret, &root_x, &root_y,
  418                        &win_x, &win_y, &mask);
  419         fprintf (stderr,
  420                  "%s: XI_RawMotion       %4d, %-4d  %7.02f, %-7.02f%s\n",
  421                  blurb(), root_x, root_y, re->raw_values[0], re->raw_values[1],
  422                  (desc ? desc : ""));
  423       }
  424     break;
  425 
  426   /* Touch-screens, possibly trackpads or tablets. */
  427   case XI_RawTouchBegin:
  428     fprintf (stderr, "%s: XI RawTouchBegin\n", blurb());
  429     break;
  430   case XI_RawTouchEnd:
  431     fprintf (stderr, "%s: XI RawTouchEnd\n", blurb());
  432     break;
  433   case XI_RawTouchUpdate:
  434     if (verbose_p > 1)
  435       fprintf (stderr, "%s: XI RawTouchUpdate\n", blurb());
  436     break;
  437 
  438   default:
  439     fprintf (stderr, "%s: unknown XInput event %d\n", blurb(), re->type);
  440     break;
  441   }
  442 }