X11: Simplified mousewheel event handling.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 13 Aug 2015 17:40:28 -0400
changeset 9839ca64802fd9b0
parent 9838 5b9fa1c4d15b
child 9840 bf7734a34f13
X11: Simplified mousewheel event handling.

Under load, this would race and report an incorrect mouse button event instead
of a wheel event.

Fixes Bugzilla #2987.
src/video/x11/SDL_x11events.c
     1.1 --- a/src/video/x11/SDL_x11events.c	Thu Aug 13 17:37:09 2015 -0400
     1.2 +++ b/src/video/x11/SDL_x11events.c	Thu Aug 13 17:40:28 2015 -0400
     1.3 @@ -167,54 +167,20 @@
     1.4      return d.found;
     1.5  }
     1.6  
     1.7 -static Bool X11_IsWheelCheckIfEvent(Display *display, XEvent *chkev,
     1.8 -    XPointer arg)
     1.9 +static SDL_bool
    1.10 +X11_IsWheelEvent(Display * display,XEvent * event,int * xticks,int * yticks)
    1.11  {
    1.12 -    XEvent *event = (XEvent *) arg;
    1.13 -    /* we only handle buttons 4 and 5 - false positive avoidance */
    1.14 -    if (chkev->type == ButtonRelease &&
    1.15 -        (event->xbutton.button == Button4 || event->xbutton.button == Button5 ||
    1.16 -         event->xbutton.button == 6 || event->xbutton.button == 7) &&
    1.17 -        chkev->xbutton.button == event->xbutton.button &&
    1.18 -        chkev->xbutton.time == event->xbutton.time)
    1.19 -        return True;
    1.20 -    return False;
    1.21 -}
    1.22 +    /* according to the xlib docs, no specific mouse wheel events exist.
    1.23 +       However, the defacto standard is that the vertical wheel is X buttons
    1.24 +       4 (up) and 5 (down) and a horizontal wheel is 6 (left) and 7 (right). */
    1.25  
    1.26 -static SDL_bool X11_IsWheelEvent(Display * display,XEvent * event,int * xticks,int * yticks)
    1.27 -{
    1.28 -    XEvent relevent;
    1.29 -    if (X11_XPending(display)) {
    1.30 -        /* according to the xlib docs, no specific mouse wheel events exist.
    1.31 -           however, mouse wheel events trigger a button press and a button release
    1.32 -           immediately. thus, checking if the same button was released at the same
    1.33 -           time as it was pressed, should be an adequate hack to derive a mouse
    1.34 -           wheel event.
    1.35 -           However, there is broken and unusual hardware out there...
    1.36 -           - False positive: a button for which a release event is
    1.37 -             generated (or synthesised) immediately.
    1.38 -           - False negative: a wheel which, when rolled, doesn't have
    1.39 -             a release event generated immediately. */
    1.40 -        if (X11_XCheckIfEvent(display, &relevent, X11_IsWheelCheckIfEvent,
    1.41 -            (XPointer) event)) {
    1.42 -
    1.43 -            /* by default, X11 only knows 5 buttons. on most 3 button + wheel mouse,
    1.44 -               Button4 maps to (vertical) wheel up, Button5 maps to wheel down.
    1.45 -               Horizontal scrolling usually maps to 6 and 7 which have no name */
    1.46 -            if (event->xbutton.button == Button4) {
    1.47 -                *yticks = 1;
    1.48 -            }
    1.49 -            else if (event->xbutton.button == Button5) {
    1.50 -                *yticks = -1;
    1.51 -            }
    1.52 -            else if (event->xbutton.button == 6) {
    1.53 -                *xticks = 1;
    1.54 -            }
    1.55 -            else if (event->xbutton.button == 7) {
    1.56 -                *xticks = -1;
    1.57 -            }
    1.58 -            return SDL_TRUE;
    1.59 -        }
    1.60 +    /* Xlib defines "Button1" through 5, so we just use literals here. */
    1.61 +    switch (event->xbutton.button) {
    1.62 +        case 4: *yticks = 1; return SDL_TRUE;
    1.63 +        case 5: *yticks = -1; return SDL_TRUE;
    1.64 +        case 6: *xticks = 1; return SDL_TRUE;
    1.65 +        case 7: *xticks = -1; return SDL_TRUE;
    1.66 +        default: break;
    1.67      }
    1.68      return SDL_FALSE;
    1.69  }
    1.70 @@ -1056,9 +1022,13 @@
    1.71  
    1.72      case ButtonRelease:{
    1.73              int button = xevent.xbutton.button;
    1.74 -            if (button > 7) {
    1.75 -                /* see explanation at case ButtonPress */
    1.76 -                button -= (8-SDL_BUTTON_X1);
    1.77 +            /* The X server sends a Release event for each Press for wheels. Ignore them. */
    1.78 +            int xticks = 0, yticks = 0;
    1.79 +            if (!X11_IsWheelEvent(display,&xevent,&xticks, &yticks)) {
    1.80 +                if (button > 7) {
    1.81 +                    /* see explanation at case ButtonPress */
    1.82 +                    button -= (8-SDL_BUTTON_X1);
    1.83 +                }
    1.84              }
    1.85              SDL_SendMouseButton(data->window, 0, SDL_RELEASED, button);
    1.86          }