Site hosted by Angelfire.com: Build your free website today!

Hands-on Projects for the Linux Graphics Subsystem

New book from Christos Karayiannis

Available in Amazon Kindle format at:

amazon.com   amazon.co.uk   amazon.de   amazon.es   amazon.fr   amazon.it

Post Mouse Events

MouseDoPostEvent()

MouseDoPostEvent() is implemented as:


/*******************************************************************
 *
 * Post mouse events
 *
 *******************************************************************/

static void
MouseDoPostEvent(InputInfoPtr pInfo, int buttons, int dx, int dy)
{
    MouseDevPtr pMse;
    int emulateButtons;
    int id, change;
    int emuWheelDelta, emuWheelButton, emuWheelButtonMask;
    int wheelButtonMask;
    int ms;

    pMse = pInfo->private;

    /* Do single button double click */
    if (pMse->doubleClickSourceButtonMask) {
        if (buttons & pMse->doubleClickSourceButtonMask) {
            if (!(pMse->doubleClickOldSourceState)) {
                /* double-click button has just been pressed. Ignore it if target button
                 * is already down.
                 */
                if (!(buttons & pMse->doubleClickTargetButtonMask)) {
                    /* Target button isn't down, so send a double-click */
                  xf86PostButtonEvent(pInfo->dev, 0, pMse->doubleClickTargetButton, 1, 0, 0);
                  xf86PostButtonEvent(pInfo->dev, 0, pMse->doubleClickTargetButton, 0, 0, 0);
                  xf86PostButtonEvent(pInfo->dev, 0, pMse->doubleClickTargetButton, 1, 0, 0);
                  xf86PostButtonEvent(pInfo->dev, 0, pMse->doubleClickTargetButton, 0, 0, 0);
                }
            }
            pMse->doubleClickOldSourceState = 1;
        }
        else
            pMse->doubleClickOldSourceState = 0;

        /* Whatever happened, mask the double-click button so it doesn't get
         * processed as a normal button as well.
         */
        buttons &= ~(pMse->doubleClickSourceButtonMask);
    }

    if (pMse->emulateWheel) {
	/* Emulate wheel button handling */
	wheelButtonMask = 1 << (pMse->wheelButton - 1);

	change = buttons ^ pMse->lastMappedButtons;

	if (change & wheelButtonMask) {
	    if (buttons & wheelButtonMask) {
		/* Start timeout handling */
		pMse->wheelButtonExpires = GetTimeInMillis () + pMse->wheelButtonTimeout;
		ms = - pMse->wheelButtonTimeout;  
	    } else {
		ms = pMse->wheelButtonExpires - GetTimeInMillis ();

		if (0 < ms) {
		    /*
		     * If the button is released early enough emit the button
		     * press/release events
		     */
		    xf86PostButtonEvent(pInfo->dev, 0, pMse->wheelButton, 1, 0, 0);
		    xf86PostButtonEvent(pInfo->dev, 0, pMse->wheelButton, 0, 0, 0);
		}
	    }
	} else
	    ms = pMse->wheelButtonExpires - GetTimeInMillis ();

	/* Intercept wheel emulation. */
	if (buttons & wheelButtonMask) {
	    if (ms <= 0) {
		/* Y axis movement */
		if (pMse->negativeY != MSE_NOAXISMAP) {
		    pMse->wheelYDistance += dy;
		    if (pMse->wheelYDistance < 0) {
			emuWheelDelta = -pMse->wheelInertia;
			emuWheelButton = pMse->negativeY;
		    } else {
			emuWheelDelta = pMse->wheelInertia;
			emuWheelButton = pMse->positiveY;
		    }
		    emuWheelButtonMask = 1 << (emuWheelButton - 1);
		    while (abs(pMse->wheelYDistance) > pMse->wheelInertia) {
			pMse->wheelYDistance -= emuWheelDelta;

			/*
			 * Synthesize the press and release, but not when
			 * the button to be synthesized is already pressed
			 * "for real".
			 */
			if (!(emuWheelButtonMask & buttons) ||
			    (emuWheelButtonMask & wheelButtonMask)) {
			    xf86PostButtonEvent(pInfo->dev, 0, emuWheelButton, 1, 0, 0);
			    xf86PostButtonEvent(pInfo->dev, 0, emuWheelButton, 0, 0, 0);
			}
		    }
		}

		/* X axis movement */
		if (pMse->negativeX != MSE_NOAXISMAP) {
		    pMse->wheelXDistance += dx;
		    if (pMse->wheelXDistance < 0) {
			emuWheelDelta = -pMse->wheelInertia;
			emuWheelButton = pMse->negativeX;
		    } else {
			emuWheelDelta = pMse->wheelInertia;
			emuWheelButton = pMse->positiveX;
		    }
		    emuWheelButtonMask = 1 << (emuWheelButton - 1);
		    while (abs(pMse->wheelXDistance) > pMse->wheelInertia) {
			pMse->wheelXDistance -= emuWheelDelta;

			/*
			 * Synthesize the press and release, but not when
			 * the button to be synthesized is already pressed
			 * "for real".
			 */
			if (!(emuWheelButtonMask & buttons) ||
			    (emuWheelButtonMask & wheelButtonMask)) {
			    xf86PostButtonEvent(pInfo->dev, 0, emuWheelButton, 1, 0, 0);
			    xf86PostButtonEvent(pInfo->dev, 0, emuWheelButton, 0, 0, 0);
			}
		    }
		}
	    }

	    /* Absorb the mouse movement while the wheel button is pressed. */
	    dx = 0;
	    dy = 0;
	}
	/*
	 * Button events for the wheel button are only emitted through
	 * the timeout code.
	 */
	buttons &= ~wheelButtonMask;
    }

    if (pMse->emulate3ButtonsSoft && pMse->emulate3Pending && (dx || dy))
	buttonTimer(pInfo);

    if (dx || dy)
	xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);

    if (buttons != pMse->lastMappedButtons) {

	change = buttons ^ pMse->lastMappedButtons;

	/*
	 * adjust buttons state for drag locks!
	 * if there is drag locks
	 */
        if (pMse->pDragLock) {      
	    DragLockPtr   pLock;
	    int tarOfGoingDown, tarOfDown;
	    int realbuttons;

	    /* get drag lock block */
	    pLock = pMse->pDragLock;
	    /* save real buttons */
	    realbuttons = buttons;

	    /* if drag lock used */

	    /* state of drag lock buttons not seen always up */

	    buttons &= ~pLock->lockButtonsM;

	    /*
	     * if lock buttons being depressed changes state of
	     * targets simulatedDown.
	     */
	    tarOfGoingDown = lock2targetMap(pLock,
				realbuttons & change & pLock->lockButtonsM);
	    pLock->simulatedDown ^= tarOfGoingDown;

	    /* targets of drag locks down */
	    tarOfDown = lock2targetMap(pLock,
				realbuttons & pLock->lockButtonsM);

	    /*
	     * when simulatedDown set and target pressed, 
	     * simulatedDown goes false 
	     */
	    pLock->simulatedDown &= ~(realbuttons & change);

	    /*
	     * if master drag lock released  
	     * then master drag lock state on
	     */
	    pLock->masterTS |= (~realbuttons & change) & pLock->masterLockM;

	    /* if master state, buttons going down are simulatedDown */
	    if (pLock->masterTS) 
		pLock->simulatedDown |= (realbuttons & change);

	    /* if any button pressed, no longer in master drag lock state */
	    if (realbuttons & change)
		pLock->masterTS = 0;

	    /* if simulatedDown or drag lock down, simulate down */
	    buttons |= (pLock->simulatedDown | tarOfDown);

	    /* master button not seen */
	    buttons &= ~(pLock->masterLockM);

	    /* buttons changed since last time */
	    change = buttons ^ pLock->lockLastButtons;

	    /* save this time for next last time. */
	    pLock->lockLastButtons = buttons;
	}

        if (pMse->emulate3Buttons
	    && (!(buttons & 0x02) || Emulate3ButtonsSoft(pInfo))) {

            /* handle all but buttons 1 & 3 normally */

            change &= ~05;

            /* emulate the third button by the other two */

            emulateButtons = (buttons & 01) | ((buttons &04) >> 1);

            if ((id = stateTab[pMse->emulateState][emulateButtons][0]) != 0)
                xf86PostButtonEvent(pInfo->dev, 0, abs(id), (id >= 0), 0, 0);
            if ((id = stateTab[pMse->emulateState][emulateButtons][1]) != 0)
                xf86PostButtonEvent(pInfo->dev, 0, abs(id), (id >= 0), 0, 0);

            pMse->emulateState =
                stateTab[pMse->emulateState][emulateButtons][2];

            if (stateTab[pMse->emulateState][4][0] != 0) {
		pMse->emulate3Expires = GetTimeInMillis () + pMse->emulate3Timeout;
		pMse->emulate3Pending = TRUE;
            } else {
		pMse->emulate3Pending = FALSE;
            }
        }

	while (change) {
	    id = ffs(change);
	    change &= ~(1 << (id - 1));
	    xf86PostButtonEvent(pInfo->dev, 0, id,
				(buttons & (1 << (id - 1))), 0, 0);
	}

        pMse->lastMappedButtons = buttons;

    }
}

The main parts of the previous function are:


    if (dx || dy)
	xf86PostMotionEvent(pInfo->dev, 0, 0, 2, dx, dy);
This is straightforward. If there is either movement to the X axis (dx), or to the Y axis (dy) xf86PostMotionEvent() is called. This function is examined in the paragraphs that follow.

The other part is:


    if (buttons != pMse->lastMappedButtons) {

	change = buttons ^ pMse->lastMappedButtons;
. . .
	while (change) {
	    id = ffs(change);
	    change &= ~(1 << (id - 1));
	    xf86PostButtonEvent(pInfo->dev, 0, id,
				(buttons & (1 << (id - 1))), 0, 0);
	}

        pMse->lastMappedButtons = buttons;

The XOR operator (^) is used to find the buttons changed state. Recall from section 5.1.3 that variable 'buttons' holds a pressed left, middle and right button at bit position 2, 1 and 0 respectively.

The ffs() function returns the position of the first (least significant) bit set. It considers that the least significant bit is at position 1 (instead of 0 we count it). Then with the following instruction:

change &= ~(1 << (id - 1));
change is updated to clear that bit, since xf86PostButtonEvent() that follows right next informs the X client process for the certain button. The whole process continues until the whole 'change' is cleared.

The two routines, used to post motion and buttons pressed are as we previously saw xf86PostMotionEvent() and xf86PostButtonEvent(). They are discussed next:

xf86PostMotionEvent()

xf86PostMotionEvent() is implemented as:

void
xf86PostMotionEvent(DeviceIntPtr	device,
		    int			is_absolute,
		    int			first_valuator,
		    int			num_valuators,
		    ...)
{
    va_list			var;
    int				loop;
    xEvent			xE[2];
    deviceKeyButtonPointer	*xev  = (deviceKeyButtonPointer*) xE;
    deviceValuator		*xv   = (deviceValuator*) xev+1;
    LocalDevicePtr		local = (LocalDevicePtr) device->public.devicePrivate;
    char			*buff = 0;
    Time			current;
    Bool			is_core = xf86IsCorePointer(device);
    Bool			is_shared = xf86ShareCorePointer(device);
    Bool			drag = xf86SendDragEvents(device);
    ValuatorClassPtr		val = device->valuator;
    int				valuator[6];
    int				oldaxis[6];
    int				*axisvals;
    int				dx = 0, dy = 0;
    float			mult;
    int				x, y;
    int				loop_start;
    int				i;
    int				num;
    
    DBG(5, ErrorF("xf86PostMotionEvent BEGIN 0x%x(%s) is_core=%s is_shared=%s is_absolute=%s\n",
		  device, device->name,
		  is_core ? "True" : "False",
		  is_shared ? "True" : "False",
		  is_absolute ? "True" : "False"));
    
    xf86Info.lastEventTime = xev->time = current = GetTimeInMillis();
    
    if (!is_core) {
      if (HAS_MOTION_HISTORY(local)) {
	buff = ((char *)local->motion_history +
		(sizeof(INT32) * local->dev->valuator->numAxes + sizeof(Time)) * local->last);
      }
    }

    if (num_valuators && (!val || (first_valuator + num_valuators > val->numAxes))) {
	ErrorF("Bad valuators reported for device \"%s\"\n", device->name);
	return;
    }

    axisvals = val->axisVal;
    
    va_start(var, num_valuators);

    loop_start = first_valuator;
    for(loop=0; loop < num_valuators; loop++) {
	
	valuator[loop%6] = va_arg(var,int);
	
	if (loop % 6 == 5 || loop == num_valuators - 1)	{
	    num = loop % 6 + 1;

	    /*
	     * Adjust first two relative valuators
	     */
	    if (!is_absolute && num_valuators >= 2 && loop_start == 0) {
		
		dx = valuator[0];
		dy = valuator[1];

		/*
		 * Accelerate
		 */
		if (device->ptrfeed && device->ptrfeed->ctrl.num) {
		    /* modeled from xf86Events.c */
		    if (device->ptrfeed->ctrl.threshold) {
			if ((abs(dx) + abs(dy)) >= device->ptrfeed->ctrl.threshold) {
			    local->dxremaind = ((float)dx * (float)(device->ptrfeed->ctrl.num)) /
			        (float)(device->ptrfeed->ctrl.den) + local->dxremaind;
			    valuator[0] = (int)local->dxremaind;
			    local->dxremaind = local->dxremaind - (float)valuator[0];
			    
			    local->dyremaind = ((float)dy * (float)(device->ptrfeed->ctrl.num)) /
			        (float)(device->ptrfeed->ctrl.den) + local->dyremaind;
			    valuator[1] = (int)local->dyremaind;
			    local->dyremaind = local->dyremaind - (float)valuator[1];
			}
		    }
		    else if (dx || dy) {
			mult = pow((float)(dx*dx+dy*dy),
				   ((float)(device->ptrfeed->ctrl.num) /
				    (float)(device->ptrfeed->ctrl.den) - 1.0) / 
				   2.0) / 2.0;
			if (dx) {
			    local->dxremaind = mult * (float)dx + local->dxremaind;
			    valuator[0] = (int)local->dxremaind;
			    local->dxremaind = local->dxremaind - (float)valuator[0];
			}
			if (dy) {
			    local->dyremaind = mult * (float)dy + local->dyremaind;
			    valuator[1] = (int)local->dyremaind;
			    local->dyremaind = local->dyremaind - (float)valuator[1];
			}
		    }
		    DBG(6, ErrorF("xf86PostMotionEvent acceleration v0=%d v1=%d\n",
				  valuator[0], valuator[1]));
		}
		
		/*
		 * Map current position back to device space in case
		 * the cursor was warped
		 */
		if (is_core || is_shared)
		{
		    miPointerPosition (&x, &y);
		    if (local->reverse_conversion_proc)
			(*local->reverse_conversion_proc)(local, x, y, axisvals);
		    else
		    {
			axisvals[0] = x;
			axisvals[1] = y;
		    }
		}
	    }
		
	    /*
	     * Update axes
	     */
	    for (i = 0; i < num; i++)
	    {
		oldaxis[i] = axisvals[loop_start + i];
	        if (is_absolute)
		    axisvals[loop_start + i] = valuator[i];
		else
		    axisvals[loop_start + i] += valuator[i];

	    }
		
	    /*
	     * Deliver extension event
	     */
	    if (!is_core) {
		xev->type = DeviceMotionNotify;
		xev->detail = 0;
		xev->deviceid = device->id | MORE_EVENTS;
            
		xv->type = DeviceValuator;
		xv->deviceid = device->id;
	    
		xv->device_state = 0;
		xv->num_valuators = num;
		xv->first_valuator = loop_start;
		memcpy (&xv->valuator0, &axisvals[loop_start],
			sizeof(INT32)*xv->num_valuators);
		
		if (HAS_MOTION_HISTORY(local)) {
		    *(Time*)buff = current;
		    memcpy(buff+sizeof(Time)+sizeof(INT32)*xv->first_valuator,
			   &axisvals[loop_start],
			   sizeof(INT32)*xv->num_valuators);
		}
		ENQUEUE(xE);
	    }
	    
	    /*
	     * Deliver core event
	     */
	    if (is_core ||
		(is_shared && num_valuators >= 2 && loop_start == 0)) {
#ifdef XFreeXDGA
		/*
		 * Let DGA peek at the event and steal it
		 */
		xev->type = MotionNotify;
		xev->detail = 0;
		if (is_absolute)
		{
		    dx = axisvals[0] - oldaxis[0];
		    dy = axisvals[1] - oldaxis[1];
		}
		if (DGAStealMouseEvent(xf86EventQueue.pEnqueueScreen->myNum,
				       xE, dx, dy))
		    continue;
#endif
		if (!(*local->conversion_proc)(local, loop_start, num,
					       axisvals[0], axisvals[1],
					       axisvals[2], axisvals[3],
					       axisvals[4], axisvals[5],
					       &x, &y))
		    continue;

		if (drag)
		    miPointerAbsoluteCursor (x, y, current);
		/*
		 * Retrieve the position
		 */
		miPointerPosition (&x, &y);

		if (local->reverse_conversion_proc)
		    (*local->reverse_conversion_proc)(local, x, y, axisvals);
		else
		{
		    axisvals[0] = x;
		    axisvals[1] = y;
		}
	    }
	    loop_start += 6;
	}
    }
    va_end(var);
    if (HAS_MOTION_HISTORY(local)) {
	local->last = (local->last + 1) % device->valuator->numMotionEvents;
	if (local->last == local->first)
	    local->first = (local->first + 1) % device->valuator->numMotionEvents;
    }
    DBG(5, ErrorF("xf86PostMotionEvent END   0x%x(%s) is_core=%s is_shared=%s\n",
		  device, device->name,
		  is_core ? "True" : "False",
		  is_shared ? "True" : "False"));
}

With xf86PostMotionEvent() we cover only the core events, events that come from the core mouse, and not the extension (Xinput) events (see X Server Input Event generation and processing). Core events are sent if 'drag' is true. 'Drag' is occurred when the mouse cursor is moved and at the same time a mouse button is pressed. The first 'for' loop runs once for our case (core devices) and runs more than one in the case of devices that use more than 6 valuators.

Does this mean that in order to find the mouse coordinates in the X Window system a mouse button should be pressed?

Many programs e.g. image manipulating applications require that mouse coordinates should be updated at the screen all the time. Which is the solution then? At this link XTestFakeButtonEvent() is used to simulate fake mouse press and release button events. XTestFakeButtonEvent() has its own man page

Variable drag derives from:

    Bool			drag = xf86SendDragEvents(device);

xf86SendDragEvents() is implemented as:

 
static Bool
xf86SendDragEvents(DeviceIntPtr	device)
{
    LocalDevicePtr local = (LocalDevicePtr) device->public.devicePrivate;
    
    if (inputInfo.pointer->button->buttonsDown > 0)
	return (local->flags & XI86_SEND_DRAG_EVENTS);
    else
	return (TRUE);
}

where inputInfo.pointer->button->buttonsDown is set to 1 by ProcessPointerEvent() (see section 3.2.5.1 at the 'case ButtonPress'. Also XI86_SEND_DRAG_EVENTS is set by xf86ProcessCommonOptions() , called by MousePreInit() (see section 3.2.3) if the "SendDragEvents" option is set in xorg.conf.

MouseConvert() is implemented as:

 
/*
 ***************************************************************************
 *
 * MouseConvert --
 *	Convert valuators to X and Y.
 *
 ***************************************************************************
 */
static Bool
MouseConvert(InputInfoPtr pInfo, int first, int num, int v0, int v1, int v2,
	     int v3, int v4, int v5, int *x, int *y)
{
    if (first != 0 || num != 2)
	return FALSE;

    *x = v0;
    *y = v1;

    return TRUE;
}

miPointerAbsoluteCursor() is implemented as:

 
/*
 * miPointerAbsoluteCursor.  The pointer has moved to x,y
 */

void
miPointerAbsoluteCursor (x, y, time)
    int		    x, y;
    unsigned long   time;
{
    miPointerScreenPtr	pScreenPriv;
    ScreenPtr		pScreen;
    ScreenPtr		newScreen;

    pScreen = miPointer.pScreen;
    if (!pScreen)
	return;	    /* called before ready */
    if (x < 0 || x >= pScreen->width || y < 0 || y >= pScreen->height)
    {
	pScreenPriv = GetScreenPrivate (pScreen);
	if (!miPointer.confined)
	{
	    newScreen = pScreen;
	    (*pScreenPriv->screenFuncs->CursorOffScreen) (&newScreen, &x, &y);
	    if (newScreen != pScreen)
	    {
		pScreen = newScreen;
		(*pScreenPriv->screenFuncs->NewEventScreen) (pScreen, FALSE);
		pScreenPriv = GetScreenPrivate (pScreen);
	    	/* Smash the confine to the new screen */
	    	miPointer.limits.x2 = pScreen->width;
	    	miPointer.limits.y2 = pScreen->height;
	    }
	}
    }
    /*
     * constrain the hot-spot to the current
     * limits
     */
    if (x < miPointer.limits.x1)
	x = miPointer.limits.x1;
    if (x >= miPointer.limits.x2)
	x = miPointer.limits.x2 - 1;
    if (y < miPointer.limits.y1)
	y = miPointer.limits.y1;
    if (y >= miPointer.limits.y2)
	y = miPointer.limits.y2 - 1;
    if (miPointer.x == x && miPointer.y == y && miPointer.pScreen == pScreen)
	return;
    miPointerMove (pScreen, x, y, time);
}

miPointerPosition() is implemented as;

 
void
miPointerPosition (x, y)
    int	    *x, *y;
{
    *x = miPointer.x;
    *y = miPointer.y;
}

miPointerMove() is implemented as:

 
/*
 * miPointerMove.  The pointer has moved to x,y on current screen
 */

static void
miPointerMove (pScreen, x, y, time)
    ScreenPtr	    pScreen;
    int		    x, y;
    unsigned long   time;
{
    SetupScreen(pScreen);
    xEvent		xE;
    miHistoryPtr	history;
    int			prev, end, start;

    if (!pScreenPriv->waitForUpdate && pScreen == miPointer.pSpriteScreen)
    {
	miPointer.devx = x;
	miPointer.devy = y;
	if(!miPointer.pCursor->bits->emptyMask)
	    (*pScreenPriv->spriteFuncs->MoveCursor) (pScreen, x, y);
    }
    miPointer.x = x;
    miPointer.y = y;
    miPointer.pScreen = pScreen;

    xE.u.u.type = MotionNotify;
    xE.u.keyButtonPointer.rootX = x;
    xE.u.keyButtonPointer.rootY = y;
    xE.u.keyButtonPointer.time = time;
    (*pScreenPriv->screenFuncs->EnqueueEvent) (&xE);

    end = miPointer.history_end;
    start = miPointer.history_start;
    prev = end - 1;
    if (end == 0)
	prev = MOTION_SIZE - 1;
    history = &miPointer.history[prev];
    if (end == start || history->event.time != time)
    {
    	history = &miPointer.history[end];
    	if (++end == MOTION_SIZE) 
	    end = 0;
    	if (end == start)
    	{
	    start = end + 1;
	    if (start == MOTION_SIZE)
	    	start = 0;
	    miPointer.history_start = start;
    	}
    	miPointer.history_end = end;
    }
    history->event.x = x;
    history->event.y = y;
    history->event.time = time;
    history->pScreen = pScreen;
}

xf86PostButtonEvent()

xf86PostButtonEvent() is implemented as:

 
void
xf86PostButtonEvent(DeviceIntPtr	device,
		    int			is_absolute,
		    int			button,
		    int			is_down,
		    int			first_valuator,
		    int			num_valuators,
		    ...)
{
    va_list			var;
    int				loop;
    xEvent			xE[2];
    deviceKeyButtonPointer	*xev	        = (deviceKeyButtonPointer*) xE;
    deviceValuator		*xv	        = (deviceValuator*) xev+1;
    ValuatorClassPtr		val		= device->valuator;
    Bool			is_core		= xf86IsCorePointer(device);
    Bool			is_shared       = xf86ShareCorePointer(device);
    
    DBG(5, ErrorF("xf86PostButtonEvent BEGIN 0x%x(%s) button=%d down=%s
is_core=%s is_shared=%s is_absolute=%s\n", device, device->name, button, is_down ? "True" : "False", is_core ? "True" : "False", is_shared ? "True" : "False", is_absolute ? "True" : "False")); /* Check the core pointer button state not to send an inconsistent * event. This can happen with the AlwaysCore feature. */ if ((is_core || is_shared) && !xf86CheckButton(device->button->map[button], is_down)) { return; } if (num_valuators && (!val || (first_valuator + num_valuators > val->numAxes))) { ErrorF("Bad valuators reported for device \"%s\"\n", device->name); return; } if (!is_core) { xev->type = is_down ? DeviceButtonPress : DeviceButtonRelease; xev->detail = button; xev->deviceid = device->id | MORE_EVENTS; xv->type = DeviceValuator; xv->deviceid = device->id; xv->device_state = 0; if (num_valuators != 0) { int *axisvals = val->axisVal; va_start(var, num_valuators); for(loop=0; loopvaluator0 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; case 1: xv->valuator1 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; case 2: xv->valuator2 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; case 3: xv->valuator3 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; case 4: xv->valuator4 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; case 5: xv->valuator5 = is_absolute ? va_arg(var, int) : axisvals[loop]; break; } if ((loop % 6 == 5) || (loop == num_valuators - 1)) { xf86Info.lastEventTime = xev->time = GetTimeInMillis(); xv->num_valuators = (loop % 6) + 1; xv->first_valuator = first_valuator + (loop / 6) * 6; ENQUEUE(xE); } } va_end(var); } else { /* no valuator */ xf86Info.lastEventTime = xev->time = GetTimeInMillis(); xv->num_valuators = 0; xv->first_valuator = 0; ENQUEUE(xE); } } /* removed rootX/rootY as DIX sets these fields */ if (is_core || is_shared) { xE->u.u.type = is_down ? ButtonPress : ButtonRelease; xE->u.u.detail = device->button->map[button]; xf86Info.lastEventTime = xE->u.keyButtonPointer.time = GetTimeInMillis(); #ifdef XFreeXDGA if (!DGAStealMouseEvent(xf86EventQueue.pEnqueueScreen->myNum, xE, 0, 0)) #endif ENQUEUE(xE); } DBG(5, ErrorF("xf86PostButtonEvent END\n")); }

In xf86PostButtonEvent()we also cover only the core event part of the code (ommiting the Xinput event part).

xf86CheckButton() for the specific button (bit in button) adds it to static int variable xf86CoreButtonState. This is initial zero and also the first time the button is used it is pressed (contrary to released). Therefore the first time the check:

check = xf86CoreButtonState & bit;
is zero and the first part of the condition (therefore all the condition):
   if ((check && down) || (!check && !down)) {

becomes true. The next time with the instruction:
xf86CoreButtonState ^= bit
the xf86CoreButtonState bit becomes 1 and if all work right the next operation in the button is to be released and the second part of the condition becomes true and so on.

xf86CheckButton() is implemented as:

 
static int xf86CoreButtonState;

/***********************************************************************
 *
 * xf86CheckButton --
 *	
 *	Test if the core pointer button state is coherent with
 * the button event to send.
 *
 ***********************************************************************
 */
Bool
xf86CheckButton(int	button,
		int	down)
{
    int	check;
    int bit = (1 << (button - 1));

    check = xf86CoreButtonState & bit;
    
    DBG(5, ErrorF("xf86CheckButton "
		  "button=%d down=%d state=%d check=%d returns ",
		   button, down, xf86CoreButtonState, check));
    if ((check && down) || (!check && !down)) {
	DBG(5, ErrorF("FALSE\n"));
	return FALSE;
    }
    xf86CoreButtonState ^= bit;

    DBG(5, ErrorF("TRUE\n"));
    return TRUE;
}

The ButtonPress or ButtonRelease event is then constructed and enters the miEventQueue via mieqEnqueue().

Macro ENQUEUE is defined in xf86Events.c as:

 
#define ENQUEUE(ev, code, direction, dev_type) \
  (ev)->u.u.detail = (code); \
  (ev)->u.u.type   = (direction); \
  EqEnqueue((ev))

where __EqEnqueue() is defined in the same file as:


#ifdef XINPUT
#define __EqEnqueue(ev) xf86eqEnqueue(ev)
#else
#define __EqEnqueue(ev) mieqEnqueue(ev)
#endif

REFERENCES

Input Event Processing
X Server Input Event generation and processing
X.Org Manual pages: Section 4
Information about the XInput extension in XFree86
AIXwindows Programming Guide