1548 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			1548 lines
		
	
	
		
			46 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * Copyright © 2006 Nokia Corporation
 | 
						|
 * Copyright © 2006-2007 Daniel Stone
 | 
						|
 * Copyright © 2008 Red Hat, Inc.
 | 
						|
 * Copyright © 2011 The Chromium Authors
 | 
						|
 *
 | 
						|
 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
						|
 * copy of this software and associated documentation files (the "Software"),
 | 
						|
 * to deal in the Software without restriction, including without limitation
 | 
						|
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
						|
 * and/or sell copies of the Software, and to permit persons to whom the
 | 
						|
 * Software is furnished to do so, subject to the following conditions:
 | 
						|
 *
 | 
						|
 * The above copyright notice and this permission notice (including the next
 | 
						|
 * paragraph) shall be included in all copies or substantial portions of the
 | 
						|
 * Software.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
						|
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
						|
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
						|
 * DEALINGS IN THE SOFTWARE.
 | 
						|
 *
 | 
						|
 * Authors: Daniel Stone <daniel@fooishbar.org>
 | 
						|
 *          Peter Hutterer <peter.hutterer@who-t.net>
 | 
						|
 */
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <X11/X.h>
 | 
						|
#include <X11/keysym.h>
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include <math.h>
 | 
						|
 | 
						|
#include "misc.h"
 | 
						|
#include "resource.h"
 | 
						|
#include "inputstr.h"
 | 
						|
#include "scrnintstr.h"
 | 
						|
#include "cursorstr.h"
 | 
						|
#include "dixstruct.h"
 | 
						|
#include "globals.h"
 | 
						|
#include "dixevents.h"
 | 
						|
#include "mipointer.h"
 | 
						|
#include "eventstr.h"
 | 
						|
#include "eventconvert.h"
 | 
						|
#include "inpututils.h"
 | 
						|
#include "mi.h"
 | 
						|
 | 
						|
#include <X11/extensions/XKBproto.h>
 | 
						|
#include "xkbsrv.h"
 | 
						|
 | 
						|
#ifdef PANORAMIX
 | 
						|
#include "panoramiX.h"
 | 
						|
#include "panoramiXsrv.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include <X11/extensions/XI.h>
 | 
						|
#include <X11/extensions/XI2.h>
 | 
						|
#include <X11/extensions/XIproto.h>
 | 
						|
#include <pixman.h>
 | 
						|
#include "exglobals.h"
 | 
						|
#include "exevents.h"
 | 
						|
#include "extnsionst.h"
 | 
						|
#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
 | 
						|
 | 
						|
/* Number of motion history events to store. */
 | 
						|
#define MOTION_HISTORY_SIZE 256
 | 
						|
 | 
						|
/**
 | 
						|
 * InputEventList is the storage for input events generated by
 | 
						|
 * QueuePointerEvents, QueueKeyboardEvents, and QueueProximityEvents.
 | 
						|
 * This list is allocated on startup by the DIX.
 | 
						|
 */
 | 
						|
InternalEvent* InputEventList = NULL;
 | 
						|
 | 
						|
/**
 | 
						|
 * Pick some arbitrary size for Xi motion history.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetMotionHistorySize(void)
 | 
						|
{
 | 
						|
    return MOTION_HISTORY_SIZE;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
set_button_down(DeviceIntPtr pDev, int button, int type)
 | 
						|
{
 | 
						|
    if (type == BUTTON_PROCESSED)
 | 
						|
        SetBit(pDev->button->down, button);
 | 
						|
    else
 | 
						|
        SetBit(pDev->button->postdown, button);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
set_button_up(DeviceIntPtr pDev, int button, int type)
 | 
						|
{
 | 
						|
    if (type == BUTTON_PROCESSED)
 | 
						|
        ClearBit(pDev->button->down, button);
 | 
						|
    else
 | 
						|
        ClearBit(pDev->button->postdown, button);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
button_is_down(DeviceIntPtr pDev, int button, int type)
 | 
						|
{
 | 
						|
    Bool ret = FALSE;
 | 
						|
 | 
						|
    if (type & BUTTON_PROCESSED)
 | 
						|
        ret = ret || BitIsOn(pDev->button->down, button);
 | 
						|
    if (type & BUTTON_POSTED)
 | 
						|
        ret = ret || BitIsOn(pDev->button->postdown, button);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
set_key_down(DeviceIntPtr pDev, int key_code, int type)
 | 
						|
{
 | 
						|
    if (type == KEY_PROCESSED)
 | 
						|
        SetBit(pDev->key->down, key_code);
 | 
						|
    else
 | 
						|
        SetBit(pDev->key->postdown, key_code);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
set_key_up(DeviceIntPtr pDev, int key_code, int type)
 | 
						|
{
 | 
						|
    if (type == KEY_PROCESSED)
 | 
						|
        ClearBit(pDev->key->down, key_code);
 | 
						|
    else
 | 
						|
        ClearBit(pDev->key->postdown, key_code);
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
key_is_down(DeviceIntPtr pDev, int key_code, int type)
 | 
						|
{
 | 
						|
    Bool ret = FALSE;
 | 
						|
 | 
						|
    if (type & KEY_PROCESSED)
 | 
						|
        ret = ret || BitIsOn(pDev->key->down, key_code);
 | 
						|
    if (type & KEY_POSTED)
 | 
						|
        ret = ret || BitIsOn(pDev->key->postdown, key_code);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
static Bool
 | 
						|
key_autorepeats(DeviceIntPtr pDev, int key_code)
 | 
						|
{
 | 
						|
    return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
 | 
						|
              (1 << (key_code & 7)));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
init_raw(DeviceIntPtr dev, RawDeviceEvent *event, Time ms, int type, int detail)
 | 
						|
{
 | 
						|
    memset(event, 0, sizeof(RawDeviceEvent));
 | 
						|
    event->header = ET_Internal;
 | 
						|
    event->length = sizeof(RawDeviceEvent);
 | 
						|
    event->type = ET_RawKeyPress - ET_KeyPress + type;
 | 
						|
    event->time = ms;
 | 
						|
    event->deviceid = dev->id;
 | 
						|
    event->sourceid = dev->id;
 | 
						|
    event->detail.button = detail;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_raw_valuators(RawDeviceEvent *event, ValuatorMask *mask, double* data)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < valuator_mask_size(mask); i++)
 | 
						|
    {
 | 
						|
        if (valuator_mask_isset(mask, i))
 | 
						|
        {
 | 
						|
            SetBit(event->valuators.mask, i);
 | 
						|
            data[i] = valuator_mask_get_double(mask, i);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
set_valuators(DeviceIntPtr dev, DeviceEvent* event, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    /* Set the data to the previous value for unset absolute axes. The values
 | 
						|
     * may be used when sent as part of an XI 1.x valuator event. */
 | 
						|
    for (i = 0; i < valuator_mask_size(mask); i++)
 | 
						|
    {
 | 
						|
        if (valuator_mask_isset(mask, i))
 | 
						|
        {
 | 
						|
            SetBit(event->valuators.mask, i);
 | 
						|
            if (valuator_get_mode(dev, i) == Absolute)
 | 
						|
                SetBit(event->valuators.mode, i);
 | 
						|
            event->valuators.data[i] = valuator_mask_get_double(mask, i);
 | 
						|
        }
 | 
						|
        else if (valuator_get_mode(dev, i) == Absolute)
 | 
						|
            event->valuators.data[i] = dev->valuator->axisVal[i];
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
CreateClassesChangedEvent(InternalEvent* event,
 | 
						|
                          DeviceIntPtr master,
 | 
						|
                          DeviceIntPtr slave,
 | 
						|
                          int type)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    DeviceChangedEvent *dce;
 | 
						|
    CARD32 ms = GetTimeInMillis();
 | 
						|
 | 
						|
    dce = &event->changed_event;
 | 
						|
    memset(dce, 0, sizeof(DeviceChangedEvent));
 | 
						|
    dce->deviceid = slave->id;
 | 
						|
    dce->masterid = master->id;
 | 
						|
    dce->header = ET_Internal;
 | 
						|
    dce->length = sizeof(DeviceChangedEvent);
 | 
						|
    dce->type = ET_DeviceChanged;
 | 
						|
    dce->time = ms;
 | 
						|
    dce->flags = type;
 | 
						|
    dce->flags |= DEVCHANGE_SLAVE_SWITCH;
 | 
						|
    dce->sourceid = slave->id;
 | 
						|
 | 
						|
    if (slave->button)
 | 
						|
    {
 | 
						|
        dce->buttons.num_buttons = slave->button->numButtons;
 | 
						|
        for (i = 0; i < dce->buttons.num_buttons; i++)
 | 
						|
            dce->buttons.names[i] = slave->button->labels[i];
 | 
						|
    }
 | 
						|
    if (slave->valuator)
 | 
						|
    {
 | 
						|
        dce->num_valuators = slave->valuator->numAxes;
 | 
						|
        for (i = 0; i < dce->num_valuators; i++)
 | 
						|
        {
 | 
						|
            dce->valuators[i].min = slave->valuator->axes[i].min_value;
 | 
						|
            dce->valuators[i].max = slave->valuator->axes[i].max_value;
 | 
						|
            dce->valuators[i].resolution = slave->valuator->axes[i].resolution;
 | 
						|
            dce->valuators[i].mode = slave->valuator->axes[i].mode;
 | 
						|
            dce->valuators[i].name = slave->valuator->axes[i].label;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (slave->key)
 | 
						|
    {
 | 
						|
        dce->keys.min_keycode = slave->key->xkbInfo->desc->min_key_code;
 | 
						|
        dce->keys.max_keycode = slave->key->xkbInfo->desc->max_key_code;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Rescale the coord between the two axis ranges.
 | 
						|
 */
 | 
						|
static double
 | 
						|
rescaleValuatorAxis(double coord, AxisInfoPtr from, AxisInfoPtr to,
 | 
						|
                    double defmax)
 | 
						|
{
 | 
						|
    double fmin = 0.0, fmax = defmax;
 | 
						|
    double tmin = 0.0, tmax = defmax;
 | 
						|
 | 
						|
    if (from && from->min_value < from->max_value) {
 | 
						|
        fmin = from->min_value;
 | 
						|
        fmax = from->max_value;
 | 
						|
    }
 | 
						|
    if (to && to->min_value < to->max_value) {
 | 
						|
        tmin = to->min_value;
 | 
						|
        tmax = to->max_value;
 | 
						|
    }
 | 
						|
 | 
						|
    if (fmin == tmin && fmax == tmax)
 | 
						|
        return coord;
 | 
						|
 | 
						|
    if (fmax == fmin) /* avoid division by 0 */
 | 
						|
        return 0.0;
 | 
						|
 | 
						|
    return (coord - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Update all coordinates when changing to a different SD
 | 
						|
 * to ensure that relative reporting will work as expected
 | 
						|
 * without loss of precision.
 | 
						|
 *
 | 
						|
 * pDev->last.valuators will be in absolute device coordinates after this
 | 
						|
 * function.
 | 
						|
 */
 | 
						|
static void
 | 
						|
updateSlaveDeviceCoords(DeviceIntPtr master, DeviceIntPtr pDev)
 | 
						|
{
 | 
						|
    ScreenPtr scr = miPointerGetScreen(pDev);
 | 
						|
    int i;
 | 
						|
    DeviceIntPtr lastSlave;
 | 
						|
 | 
						|
    /* master->last.valuators[0]/[1] is in screen coords and the actual
 | 
						|
     * position of the pointer */
 | 
						|
    pDev->last.valuators[0] = master->last.valuators[0];
 | 
						|
    pDev->last.valuators[1] = master->last.valuators[1];
 | 
						|
 | 
						|
    if (!pDev->valuator)
 | 
						|
        return;
 | 
						|
 | 
						|
    /* scale back to device coordinates */
 | 
						|
    if(pDev->valuator->numAxes > 0)
 | 
						|
    {
 | 
						|
        pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0],
 | 
						|
                                                      NULL,
 | 
						|
                                                      pDev->valuator->axes + 0,
 | 
						|
                                                      scr->width);
 | 
						|
    }
 | 
						|
    if(pDev->valuator->numAxes > 1)
 | 
						|
    {
 | 
						|
        pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1],
 | 
						|
                                                      NULL,
 | 
						|
                                                      pDev->valuator->axes + 1,
 | 
						|
                                                      scr->height);
 | 
						|
    }
 | 
						|
 | 
						|
    /* calculate the other axis as well based on info from the old
 | 
						|
     * slave-device. If the old slave had less axes than this one,
 | 
						|
     * last.valuators is reset to 0.
 | 
						|
     */
 | 
						|
    if ((lastSlave = master->last.slave) && lastSlave->valuator) {
 | 
						|
        for (i = 2; i < pDev->valuator->numAxes; i++) {
 | 
						|
            if (i >= lastSlave->valuator->numAxes)
 | 
						|
            {
 | 
						|
                pDev->last.valuators[i] = 0;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                double val = pDev->last.valuators[i];
 | 
						|
                val = rescaleValuatorAxis(val, lastSlave->valuator->axes + i,
 | 
						|
                                          pDev->valuator->axes + i, 0);
 | 
						|
                pDev->last.valuators[i] = val;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Allocate the motion history buffer.
 | 
						|
 */
 | 
						|
void
 | 
						|
AllocateMotionHistory(DeviceIntPtr pDev)
 | 
						|
{
 | 
						|
    int size;
 | 
						|
    free(pDev->valuator->motion);
 | 
						|
 | 
						|
    if (pDev->valuator->numMotionEvents < 1)
 | 
						|
        return;
 | 
						|
 | 
						|
    /* An MD must have a motion history size large enough to keep all
 | 
						|
     * potential valuators, plus the respective range of the valuators.
 | 
						|
     * 3 * INT32 for (min_val, max_val, curr_val))
 | 
						|
     */
 | 
						|
    if (IsMaster(pDev))
 | 
						|
        size = sizeof(INT32) * 3 * MAX_VALUATORS;
 | 
						|
    else {
 | 
						|
        ValuatorClassPtr v = pDev->valuator;
 | 
						|
        int numAxes;
 | 
						|
        /* XI1 doesn't understand mixed mode devices */
 | 
						|
        for (numAxes = 0; numAxes < v->numAxes; numAxes++)
 | 
						|
            if (valuator_get_mode(pDev, numAxes) != valuator_get_mode(pDev, 0))
 | 
						|
                break;
 | 
						|
        size = sizeof(INT32) * numAxes;
 | 
						|
    }
 | 
						|
 | 
						|
    size += sizeof(Time);
 | 
						|
 | 
						|
    pDev->valuator->motion = calloc(pDev->valuator->numMotionEvents, size);
 | 
						|
    pDev->valuator->first_motion = 0;
 | 
						|
    pDev->valuator->last_motion = 0;
 | 
						|
    if (!pDev->valuator->motion)
 | 
						|
        ErrorF("[dix] %s: Failed to alloc motion history (%d bytes).\n",
 | 
						|
                pDev->name, size * pDev->valuator->numMotionEvents);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Dump the motion history between start and stop into the supplied buffer.
 | 
						|
 * Only records the event for a given screen in theory, but in practice, we
 | 
						|
 * sort of ignore this.
 | 
						|
 *
 | 
						|
 * If core is set, we only generate x/y, in INT16, scaled to screen coords.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetMotionHistory(DeviceIntPtr pDev, xTimecoord **buff, unsigned long start,
 | 
						|
                 unsigned long stop, ScreenPtr pScreen, BOOL core)
 | 
						|
{
 | 
						|
    char *ibuff = NULL, *obuff;
 | 
						|
    int i = 0, ret = 0;
 | 
						|
    int j, coord;
 | 
						|
    Time current;
 | 
						|
    /* The size of a single motion event. */
 | 
						|
    int size;
 | 
						|
    AxisInfo from, *to; /* for scaling */
 | 
						|
    INT32 *ocbuf, *icbuf; /* pointer to coordinates for copying */
 | 
						|
    INT16 *corebuf;
 | 
						|
    AxisInfo core_axis = {0};
 | 
						|
 | 
						|
    if (!pDev->valuator || !pDev->valuator->numMotionEvents)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (core && !pScreen)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (IsMaster(pDev))
 | 
						|
        size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
 | 
						|
    else
 | 
						|
        size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
 | 
						|
 | 
						|
    *buff = malloc(size * pDev->valuator->numMotionEvents);
 | 
						|
    if (!(*buff))
 | 
						|
        return 0;
 | 
						|
    obuff = (char *)*buff;
 | 
						|
 | 
						|
    for (i = pDev->valuator->first_motion;
 | 
						|
         i != pDev->valuator->last_motion;
 | 
						|
         i = (i + 1) % pDev->valuator->numMotionEvents) {
 | 
						|
        /* We index the input buffer by which element we're accessing, which
 | 
						|
         * is not monotonic, and the output buffer by how many events we've
 | 
						|
         * written so far. */
 | 
						|
        ibuff = (char *) pDev->valuator->motion + (i * size);
 | 
						|
        memcpy(¤t, ibuff, sizeof(Time));
 | 
						|
 | 
						|
        if (current > stop) {
 | 
						|
            return ret;
 | 
						|
        }
 | 
						|
        else if (current >= start) {
 | 
						|
            if (core)
 | 
						|
            {
 | 
						|
                memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
 | 
						|
 | 
						|
                icbuf = (INT32*)(ibuff + sizeof(Time));
 | 
						|
                corebuf = (INT16*)(obuff + sizeof(Time));
 | 
						|
 | 
						|
                /* fetch x coordinate + range */
 | 
						|
                memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | 
						|
                memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | 
						|
                memcpy(&coord, icbuf++, sizeof(INT32));
 | 
						|
 | 
						|
                /* scale to screen coords */
 | 
						|
                to = &core_axis;
 | 
						|
                to->max_value = pScreen->width;
 | 
						|
                coord = rescaleValuatorAxis(coord, &from, to, pScreen->width);
 | 
						|
 | 
						|
                memcpy(corebuf, &coord, sizeof(INT16));
 | 
						|
                corebuf++;
 | 
						|
 | 
						|
                /* fetch y coordinate + range */
 | 
						|
                memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | 
						|
                memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | 
						|
                memcpy(&coord, icbuf++, sizeof(INT32));
 | 
						|
 | 
						|
                to->max_value = pScreen->height;
 | 
						|
                coord = rescaleValuatorAxis(coord, &from, to, pScreen->height);
 | 
						|
                memcpy(corebuf, &coord, sizeof(INT16));
 | 
						|
 | 
						|
            } else if (IsMaster(pDev))
 | 
						|
            {
 | 
						|
                memcpy(obuff, ibuff, sizeof(Time)); /* copy timestamp */
 | 
						|
 | 
						|
                ocbuf = (INT32*)(obuff + sizeof(Time));
 | 
						|
                icbuf = (INT32*)(ibuff + sizeof(Time));
 | 
						|
                for (j = 0; j < MAX_VALUATORS; j++)
 | 
						|
                {
 | 
						|
                    if (j >= pDev->valuator->numAxes)
 | 
						|
                        break;
 | 
						|
 | 
						|
                    /* fetch min/max/coordinate */
 | 
						|
                    memcpy(&from.min_value, icbuf++, sizeof(INT32));
 | 
						|
                    memcpy(&from.max_value, icbuf++, sizeof(INT32));
 | 
						|
                    memcpy(&coord, icbuf++, sizeof(INT32));
 | 
						|
 | 
						|
                    to = (j < pDev->valuator->numAxes) ? &pDev->valuator->axes[j] : NULL;
 | 
						|
 | 
						|
                    /* x/y scaled to screen if no range is present */
 | 
						|
                    if (j == 0 && (from.max_value < from.min_value))
 | 
						|
                        from.max_value = pScreen->width;
 | 
						|
                    else if (j == 1 && (from.max_value < from.min_value))
 | 
						|
                        from.max_value = pScreen->height;
 | 
						|
 | 
						|
                    /* scale from stored range into current range */
 | 
						|
                    coord = rescaleValuatorAxis(coord, &from, to, 0);
 | 
						|
                    memcpy(ocbuf, &coord, sizeof(INT32));
 | 
						|
                    ocbuf++;
 | 
						|
                }
 | 
						|
            } else
 | 
						|
                memcpy(obuff, ibuff, size);
 | 
						|
 | 
						|
            /* don't advance by size here. size may be different to the
 | 
						|
             * actually written size if the MD has less valuators than MAX */
 | 
						|
            if (core)
 | 
						|
                obuff += sizeof(INT32) + sizeof(Time);
 | 
						|
            else
 | 
						|
                obuff += (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
 | 
						|
            ret++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Update the motion history for a specific device, with the list of
 | 
						|
 * valuators.
 | 
						|
 *
 | 
						|
 * Layout of the history buffer:
 | 
						|
 *   for SDs: [time] [val0] [val1] ... [valn]
 | 
						|
 *   for MDs: [time] [min_val0] [max_val0] [val0] [min_val1] ... [valn]
 | 
						|
 *
 | 
						|
 * For events that have some valuators unset:
 | 
						|
 *      min_val == max_val == val == 0.
 | 
						|
 */
 | 
						|
static void
 | 
						|
updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, ValuatorMask *mask,
 | 
						|
                    double *valuators)
 | 
						|
{
 | 
						|
    char *buff = (char *) pDev->valuator->motion;
 | 
						|
    ValuatorClassPtr v;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (!pDev->valuator->numMotionEvents)
 | 
						|
        return;
 | 
						|
 | 
						|
    v = pDev->valuator;
 | 
						|
    if (IsMaster(pDev))
 | 
						|
    {
 | 
						|
        buff += ((sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(CARD32)) *
 | 
						|
                v->last_motion;
 | 
						|
 | 
						|
        memcpy(buff, &ms, sizeof(Time));
 | 
						|
        buff += sizeof(Time);
 | 
						|
 | 
						|
        memset(buff, 0, sizeof(INT32) * 3 * MAX_VALUATORS);
 | 
						|
 | 
						|
        for (i = 0; i < v->numAxes; i++)
 | 
						|
        {
 | 
						|
            int val;
 | 
						|
            /* XI1 doesn't support mixed mode devices */
 | 
						|
            if (valuator_get_mode(pDev, i) != valuator_get_mode(pDev, 0))
 | 
						|
                break;
 | 
						|
            if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
 | 
						|
            {
 | 
						|
                buff += 3 * sizeof(INT32);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            memcpy(buff, &v->axes[i].min_value, sizeof(INT32));
 | 
						|
            buff += sizeof(INT32);
 | 
						|
            memcpy(buff, &v->axes[i].max_value, sizeof(INT32));
 | 
						|
            buff += sizeof(INT32);
 | 
						|
            val = valuators[i];
 | 
						|
            memcpy(buff, &val, sizeof(INT32));
 | 
						|
            buff += sizeof(INT32);
 | 
						|
        }
 | 
						|
    } else
 | 
						|
    {
 | 
						|
 | 
						|
        buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
 | 
						|
            pDev->valuator->last_motion;
 | 
						|
 | 
						|
        memcpy(buff, &ms, sizeof(Time));
 | 
						|
        buff += sizeof(Time);
 | 
						|
 | 
						|
        memset(buff, 0, sizeof(INT32) * pDev->valuator->numAxes);
 | 
						|
 | 
						|
        for (i = 0; i < MAX_VALUATORS; i++)
 | 
						|
        {
 | 
						|
            int val;
 | 
						|
            if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
 | 
						|
            {
 | 
						|
                buff += sizeof(INT32);
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            val = valuators[i];
 | 
						|
            memcpy(buff, &val, sizeof(INT32));
 | 
						|
            buff += sizeof(INT32);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pDev->valuator->last_motion = (pDev->valuator->last_motion + 1) %
 | 
						|
        pDev->valuator->numMotionEvents;
 | 
						|
    /* If we're wrapping around, just keep the circular buffer going. */
 | 
						|
    if (pDev->valuator->first_motion == pDev->valuator->last_motion)
 | 
						|
        pDev->valuator->first_motion = (pDev->valuator->first_motion + 1) %
 | 
						|
                                       pDev->valuator->numMotionEvents;
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns the maximum number of events GetKeyboardEvents
 | 
						|
 * and GetPointerEvents will ever return.
 | 
						|
 *
 | 
						|
 * This MUST be absolutely constant, from init until exit.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetMaximumEventsNum(void) {
 | 
						|
    /* One raw event
 | 
						|
     * One device event
 | 
						|
     * One possible device changed event
 | 
						|
     * Lots of possible separate button scroll events (horiz + vert)
 | 
						|
     * Lots of possible separate raw button scroll events (horiz + vert)
 | 
						|
     */
 | 
						|
    return 100;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Clip an axis to its bounds, which are declared in the call to
 | 
						|
 * InitValuatorAxisClassStruct.
 | 
						|
 */
 | 
						|
static void
 | 
						|
clipAxis(DeviceIntPtr pDev, int axisNum, double *val)
 | 
						|
{
 | 
						|
    AxisInfoPtr axis;
 | 
						|
 | 
						|
    if (axisNum >= pDev->valuator->numAxes)
 | 
						|
        return;
 | 
						|
 | 
						|
    axis = pDev->valuator->axes + axisNum;
 | 
						|
 | 
						|
    /* If a value range is defined, clip. If not, do nothing */
 | 
						|
    if (axis->max_value <= axis->min_value)
 | 
						|
        return;
 | 
						|
 | 
						|
    if (*val < axis->min_value)
 | 
						|
        *val = axis->min_value;
 | 
						|
    if (*val > axis->max_value)
 | 
						|
        *val = axis->max_value;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Clip every axis in the list of valuators to its bounds.
 | 
						|
 */
 | 
						|
static void
 | 
						|
clipValuators(DeviceIntPtr pDev, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < valuator_mask_size(mask); i++)
 | 
						|
        if (valuator_mask_isset(mask, i))
 | 
						|
        {
 | 
						|
            double val = valuator_mask_get_double(mask, i);
 | 
						|
            clipAxis(pDev, i, &val);
 | 
						|
            valuator_mask_set_double(mask, i, val);
 | 
						|
        }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Create the DCCE event (does not update the master's device state yet, this
 | 
						|
 * is done in the event processing).
 | 
						|
 * Pull in the coordinates from the MD if necessary.
 | 
						|
 *
 | 
						|
 * @param events Pointer to a pre-allocated event array.
 | 
						|
 * @param dev The slave device that generated an event.
 | 
						|
 * @param type Either DEVCHANGE_POINTER_EVENT and/or DEVCHANGE_KEYBOARD_EVENT
 | 
						|
 * @param num_events The current number of events, returns the number of
 | 
						|
 *        events if a DCCE was generated.
 | 
						|
 * @return The updated @events pointer.
 | 
						|
 */
 | 
						|
InternalEvent*
 | 
						|
UpdateFromMaster(InternalEvent* events, DeviceIntPtr dev, int type, int *num_events)
 | 
						|
{
 | 
						|
    DeviceIntPtr master;
 | 
						|
 | 
						|
    master = GetMaster(dev, (type & DEVCHANGE_POINTER_EVENT) ?  MASTER_POINTER : MASTER_KEYBOARD);
 | 
						|
 | 
						|
    if (master && master->last.slave != dev)
 | 
						|
    {
 | 
						|
        CreateClassesChangedEvent(events, master, dev, type);
 | 
						|
        if (IsPointerDevice(master))
 | 
						|
        {
 | 
						|
            updateSlaveDeviceCoords(master, dev);
 | 
						|
            master->last.numValuators = dev->last.numValuators;
 | 
						|
        }
 | 
						|
        master->last.slave = dev;
 | 
						|
        (*num_events)++;
 | 
						|
        events++;
 | 
						|
    }
 | 
						|
    return events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Move the device's pointer to the position given in the valuators.
 | 
						|
 *
 | 
						|
 * @param dev The device whose pointer is to be moved.
 | 
						|
 * @param mask Valuator data for this event.
 | 
						|
 */
 | 
						|
static void
 | 
						|
clipAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < valuator_mask_size(mask); i++)
 | 
						|
    {
 | 
						|
        double val;
 | 
						|
 | 
						|
        if (!valuator_mask_isset(mask, i))
 | 
						|
            continue;
 | 
						|
        val = valuator_mask_get_double(mask, i);
 | 
						|
        clipAxis(dev, i, &val);
 | 
						|
        valuator_mask_set_double(mask, i, val);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Move the device's pointer by the values given in @valuators.
 | 
						|
 *
 | 
						|
 * @param dev The device whose pointer is to be moved.
 | 
						|
 * @param[in,out] mask Valuator data for this event, modified in-place.
 | 
						|
 */
 | 
						|
static void
 | 
						|
moveRelative(DeviceIntPtr dev, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    Bool clip_xy = IsMaster(dev) || !IsFloating(dev);
 | 
						|
 | 
						|
    /* calc other axes, clip, drop back into valuators */
 | 
						|
    for (i = 0; i < valuator_mask_size(mask); i++)
 | 
						|
    {
 | 
						|
        double val = dev->last.valuators[i];
 | 
						|
 | 
						|
        if (!valuator_mask_isset(mask, i))
 | 
						|
            continue;
 | 
						|
        val += valuator_mask_get_double(mask, i);
 | 
						|
        /* x & y need to go over the limits to cross screens if the SD
 | 
						|
         * isn't currently attached; otherwise, clip to screen bounds. */
 | 
						|
        if (valuator_get_mode(dev, i) == Absolute &&
 | 
						|
            ((i != 0 && i != 1) || clip_xy))
 | 
						|
            clipAxis(dev, i, &val);
 | 
						|
        valuator_mask_set_double(mask, i, val);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Accelerate the data in valuators based on the device's acceleration scheme.
 | 
						|
 *
 | 
						|
 * @param dev The device which's pointer is to be moved.
 | 
						|
 * @param valuators Valuator mask
 | 
						|
 * @param ms Current time.
 | 
						|
 */
 | 
						|
static void
 | 
						|
accelPointer(DeviceIntPtr dev, ValuatorMask* valuators, CARD32 ms)
 | 
						|
{
 | 
						|
    if (dev->valuator->accelScheme.AccelSchemeProc)
 | 
						|
        dev->valuator->accelScheme.AccelSchemeProc(dev, valuators, ms);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Scale from absolute screen coordinates to absolute coordinates in the
 | 
						|
 * device's coordinate range.
 | 
						|
 *
 | 
						|
 * @param dev The device to scale for.
 | 
						|
 * @param[in, out] mask The mask in sceen coordinates, modified in place to
 | 
						|
 * contain device coordinate range.
 | 
						|
 */
 | 
						|
static void
 | 
						|
scale_from_screen(DeviceIntPtr dev, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    double scaled;
 | 
						|
    ScreenPtr scr = miPointerGetScreen(dev);
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 0))
 | 
						|
    {
 | 
						|
        scaled = rescaleValuatorAxis(valuator_mask_get_double(mask, 0),
 | 
						|
                                     NULL, dev->valuator->axes + 0,
 | 
						|
                                     scr->width);
 | 
						|
        valuator_mask_set_double(mask, 0, scaled);
 | 
						|
    }
 | 
						|
    if (valuator_mask_isset(mask, 1))
 | 
						|
    {
 | 
						|
        scaled = rescaleValuatorAxis(valuator_mask_get_double(mask, 1),
 | 
						|
                                     NULL, dev->valuator->axes + 1,
 | 
						|
                                     scr->height);
 | 
						|
        valuator_mask_set_double(mask, 1, scaled);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * If we have HW cursors, this actually moves the visible sprite. If not, we
 | 
						|
 * just do all the screen crossing, etc.
 | 
						|
 *
 | 
						|
 * We scale from device to screen coordinates here, call
 | 
						|
 * miPointerSetPosition() and then scale back into device coordinates (if
 | 
						|
 * needed). miPSP will change x/y if the screen was crossed.
 | 
						|
 *
 | 
						|
 * The coordinates provided are always absolute. The parameter mode
 | 
						|
 * specifies whether it was relative or absolute movement that landed us at
 | 
						|
 * those coordinates.
 | 
						|
 *
 | 
						|
 * @param dev The device to be moved.
 | 
						|
 * @param mode Movement mode (Absolute or Relative)
 | 
						|
 * @param mask Mask of axis values for this event
 | 
						|
 * @param screenx Screen x coordinate the sprite is on after the update.
 | 
						|
 * @param screeny Screen y coordinate the sprite is on after the update.
 | 
						|
 */
 | 
						|
static ScreenPtr
 | 
						|
positionSprite(DeviceIntPtr dev, int mode, ValuatorMask *mask,
 | 
						|
               double *screenx, double *screeny)
 | 
						|
{
 | 
						|
    double x, y;
 | 
						|
    double tmpx, tmpy;
 | 
						|
    ScreenPtr scr = miPointerGetScreen(dev);
 | 
						|
 | 
						|
    if (!dev->valuator || dev->valuator->numAxes < 2)
 | 
						|
        return scr;
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 0))
 | 
						|
        x = valuator_mask_get_double(mask, 0);
 | 
						|
    else
 | 
						|
        x = dev->last.valuators[0];
 | 
						|
    if (valuator_mask_isset(mask, 1))
 | 
						|
        y = valuator_mask_get_double(mask, 1);
 | 
						|
    else
 | 
						|
        y = dev->last.valuators[1];
 | 
						|
 | 
						|
    /* scale x&y to screen */
 | 
						|
    *screenx = rescaleValuatorAxis(x, dev->valuator->axes + 0, NULL,
 | 
						|
                                   scr->width);
 | 
						|
    *screeny = rescaleValuatorAxis(y, dev->valuator->axes + 1, NULL,
 | 
						|
                                   scr->height);
 | 
						|
 | 
						|
    tmpx = *screenx;
 | 
						|
    tmpy = *screeny;
 | 
						|
    /* miPointerSetPosition takes care of crossing screens for us, as well as
 | 
						|
     * clipping to the current screen. */
 | 
						|
    scr = miPointerSetPosition(dev, mode, screenx, screeny);
 | 
						|
 | 
						|
    /* If we were constrained, rescale x/y from the screen coordinates so
 | 
						|
     * the device valuators reflect the correct position. For screen
 | 
						|
     * crossing this doesn't matter much, the coords would be 0 or max.
 | 
						|
     */
 | 
						|
    if (tmpx != *screenx)
 | 
						|
        x = rescaleValuatorAxis(*screenx, NULL, dev->valuator->axes + 0,
 | 
						|
                                scr->width);
 | 
						|
    if (tmpy != *screeny)
 | 
						|
        y = rescaleValuatorAxis(*screeny, NULL, dev->valuator->axes + 1,
 | 
						|
                                scr->height);
 | 
						|
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 0))
 | 
						|
        valuator_mask_set_double(mask, 0, x);
 | 
						|
    if (valuator_mask_isset(mask, 1))
 | 
						|
        valuator_mask_set_double(mask, 1, y);
 | 
						|
 | 
						|
    return scr;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Update the motion history for the device and (if appropriate) for its
 | 
						|
 * master device.
 | 
						|
 * @param dev Slave device to update.
 | 
						|
 * @param mask Bit mask of valid valuators to append to history.
 | 
						|
 * @param num Total number of valuators to append to history.
 | 
						|
 * @param ms Current time
 | 
						|
 */
 | 
						|
static void
 | 
						|
updateHistory(DeviceIntPtr dev, ValuatorMask *mask, CARD32 ms)
 | 
						|
{
 | 
						|
    if (!dev->valuator)
 | 
						|
        return;
 | 
						|
 | 
						|
    updateMotionHistory(dev, ms, mask, dev->last.valuators);
 | 
						|
    if(!IsMaster(dev) && !IsFloating(dev))
 | 
						|
    {
 | 
						|
        DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
 | 
						|
        updateMotionHistory(master, ms, mask, dev->last.valuators);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
queueEventList(DeviceIntPtr device, InternalEvent *events, int nevents)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    for (i = 0; i < nevents; i++)
 | 
						|
        mieqEnqueue(device, &events[i]);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
event_set_root_coordinates(DeviceEvent* event, double x, double y)
 | 
						|
{
 | 
						|
    event->root_x = trunc(x);
 | 
						|
    event->root_y = trunc(y);
 | 
						|
    event->root_x_frac = x - trunc(x);
 | 
						|
    event->root_y_frac = y - trunc(y);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate internal events representing this keyboard event and enqueue
 | 
						|
 * them on the event queue.
 | 
						|
 *
 | 
						|
 * This function is not reentrant. Disable signals before calling.
 | 
						|
 *
 | 
						|
 * FIXME: flags for relative/abs motion?
 | 
						|
 *
 | 
						|
 * @param device The device to generate the event for
 | 
						|
 * @param type Event type, one of KeyPress or KeyRelease
 | 
						|
 * @param keycode Key code of the pressed/released key
 | 
						|
 * @param mask Valuator mask for valuators present for this event.
 | 
						|
 *
 | 
						|
 */
 | 
						|
void
 | 
						|
QueueKeyboardEvents(DeviceIntPtr device, int type,
 | 
						|
                    int keycode, const ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int nevents;
 | 
						|
 | 
						|
    nevents = GetKeyboardEvents(InputEventList, device, type, keycode, mask);
 | 
						|
    queueEventList(device, InputEventList, nevents);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Returns a set of InternalEvents for KeyPress/KeyRelease, optionally
 | 
						|
 * also with valuator events.
 | 
						|
 *
 | 
						|
 * The DDX is responsible for allocating the event list in the first
 | 
						|
 * place via InitEventList(), and for freeing it.
 | 
						|
 *
 | 
						|
 * @return the number of events written into events.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetKeyboardEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 | 
						|
                  int key_code, const ValuatorMask *mask_in) {
 | 
						|
    int num_events = 0;
 | 
						|
    CARD32 ms = 0;
 | 
						|
    DeviceEvent *event;
 | 
						|
    RawDeviceEvent *raw;
 | 
						|
    ValuatorMask mask;
 | 
						|
 | 
						|
    /* refuse events from disabled devices */
 | 
						|
    if (!pDev->enabled)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (!events ||!pDev->key || !pDev->focus || !pDev->kbdfeed ||
 | 
						|
       (type != KeyPress && type != KeyRelease) ||
 | 
						|
       (key_code < 8 || key_code > 255))
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (mask_in && valuator_mask_size(mask_in) > 1) {
 | 
						|
        ErrorF("[dix] the server does not handle valuator masks with "
 | 
						|
                "keyboard events. This is a bug. You may fix it.\n");
 | 
						|
    }
 | 
						|
 | 
						|
    num_events = 1;
 | 
						|
 | 
						|
    events = UpdateFromMaster(events, pDev, DEVCHANGE_KEYBOARD_EVENT, &num_events);
 | 
						|
 | 
						|
    /* Handle core repeating, via press/release/press/release. */
 | 
						|
    if (type == KeyPress && key_is_down(pDev, key_code, KEY_POSTED)) {
 | 
						|
        /* If autorepeating is disabled either globally or just for that key,
 | 
						|
         * or we have a modifier, don't generate a repeat event. */
 | 
						|
        if (!pDev->kbdfeed->ctrl.autoRepeat ||
 | 
						|
            !key_autorepeats(pDev, key_code) ||
 | 
						|
            pDev->key->xkbInfo->desc->map->modmap[key_code])
 | 
						|
            return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    ms = GetTimeInMillis();
 | 
						|
 | 
						|
    raw = &events->raw_event;
 | 
						|
    events++;
 | 
						|
    num_events++;
 | 
						|
 | 
						|
    valuator_mask_copy(&mask, mask_in);
 | 
						|
 | 
						|
    init_raw(pDev, raw, ms, type, key_code);
 | 
						|
    set_raw_valuators(raw, &mask, raw->valuators.data_raw);
 | 
						|
 | 
						|
    clipValuators(pDev, &mask);
 | 
						|
 | 
						|
    set_raw_valuators(raw, &mask, raw->valuators.data);
 | 
						|
 | 
						|
    event = &events->device_event;
 | 
						|
    init_device_event(event, pDev, ms);
 | 
						|
    event->detail.key = key_code;
 | 
						|
 | 
						|
    if (type == KeyPress) {
 | 
						|
        event->type = ET_KeyPress;
 | 
						|
	set_key_down(pDev, key_code, KEY_POSTED);
 | 
						|
    }
 | 
						|
    else if (type == KeyRelease) {
 | 
						|
        event->type = ET_KeyRelease;
 | 
						|
	set_key_up(pDev, key_code, KEY_POSTED);
 | 
						|
    }
 | 
						|
 | 
						|
    clipValuators(pDev, &mask);
 | 
						|
 | 
						|
    set_valuators(pDev, event, &mask);
 | 
						|
 | 
						|
    if (!IsFloating(pDev)) {
 | 
						|
            DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
 | 
						|
            event_set_root_coordinates(event,
 | 
						|
                                       master->last.valuators[0],
 | 
						|
                                       master->last.valuators[1]);
 | 
						|
    }
 | 
						|
 | 
						|
    return num_events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Initialize an event array large enough for num_events arrays.
 | 
						|
 * This event list is to be passed into GetPointerEvents() and
 | 
						|
 * GetKeyboardEvents().
 | 
						|
 *
 | 
						|
 * @param num_events Number of elements in list.
 | 
						|
 */
 | 
						|
InternalEvent*
 | 
						|
InitEventList(int num_events)
 | 
						|
{
 | 
						|
    InternalEvent *events = calloc(num_events, sizeof(InternalEvent));
 | 
						|
    return events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Free an event list.
 | 
						|
 *
 | 
						|
 * @param list The list to be freed.
 | 
						|
 * @param num_events Number of elements in list.
 | 
						|
 */
 | 
						|
void
 | 
						|
FreeEventList(InternalEvent *list, int num_events)
 | 
						|
{
 | 
						|
    free(list);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Transform vector x/y according to matrix m and drop the rounded coords
 | 
						|
 * back into x/y.
 | 
						|
 */
 | 
						|
static void
 | 
						|
transform(struct pixman_f_transform *m, double *x, double *y)
 | 
						|
{
 | 
						|
    struct pixman_f_vector p = {.v = {*x, *y, 1}};
 | 
						|
    pixman_f_transform_point(m, &p);
 | 
						|
 | 
						|
    *x = p.v[0];
 | 
						|
    *y = p.v[1];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Apply the device's transformation matrix to the valuator mask and replace
 | 
						|
 * the scaled values in mask. This transformation only applies to valuators
 | 
						|
 * 0 and 1, others will be untouched.
 | 
						|
 *
 | 
						|
 * @param dev The device the valuators came from
 | 
						|
 * @param[in,out] mask The valuator mask.
 | 
						|
 */
 | 
						|
static void
 | 
						|
transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
 | 
						|
{
 | 
						|
    double x, y, ox, oy;
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 0))
 | 
						|
        ox = x = valuator_mask_get_double(mask, 0);
 | 
						|
    else
 | 
						|
        ox = x = dev->last.valuators[0];
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 1))
 | 
						|
        oy = y = valuator_mask_get_double(mask, 1);
 | 
						|
    else
 | 
						|
        oy = y = dev->last.valuators[1];
 | 
						|
 | 
						|
    transform(&dev->transform, &x, &y);
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 0) || ox != x)
 | 
						|
        valuator_mask_set_double(mask, 0, x);
 | 
						|
 | 
						|
    if (valuator_mask_isset(mask, 1) || oy != y)
 | 
						|
        valuator_mask_set_double(mask, 1, y);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate internal events representing this pointer event and enqueue them
 | 
						|
 * on the event queue.
 | 
						|
 *
 | 
						|
 * This function is not reentrant. Disable signals before calling.
 | 
						|
 *
 | 
						|
 * @param device The device to generate the event for
 | 
						|
 * @param type Event type, one of ButtonPress, ButtonRelease, MotionNotify
 | 
						|
 * @param buttons Button number of the buttons modified. Must be 0 for
 | 
						|
 * MotionNotify
 | 
						|
 * @param flags Event modification flags
 | 
						|
 * @param mask Valuator mask for valuators present for this event.
 | 
						|
 */
 | 
						|
void
 | 
						|
QueuePointerEvents(DeviceIntPtr device, int type,
 | 
						|
                   int buttons, int flags, const ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int nevents;
 | 
						|
 | 
						|
    nevents = GetPointerEvents(InputEventList, device, type, buttons, flags, mask);
 | 
						|
    queueEventList(device, InputEventList, nevents);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Helper function for GetPointerEvents, which only generates motion and
 | 
						|
 * raw motion events for the slave device: does not update the master device.
 | 
						|
 *
 | 
						|
 * Should not be called by anyone other than GetPointerEvents.
 | 
						|
 *
 | 
						|
 * @return the number of events written into events.
 | 
						|
 */
 | 
						|
static int
 | 
						|
fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
 | 
						|
                    int buttons, CARD32 ms, int flags,
 | 
						|
                    const ValuatorMask *mask_in)
 | 
						|
{
 | 
						|
    int num_events = 1, i;
 | 
						|
    DeviceEvent *event;
 | 
						|
    RawDeviceEvent *raw;
 | 
						|
    double screenx = 0.0, screeny = 0.0;
 | 
						|
    ValuatorMask mask;
 | 
						|
 | 
						|
    switch (type)
 | 
						|
    {
 | 
						|
        case MotionNotify:
 | 
						|
            if (!pDev->valuator)
 | 
						|
            {
 | 
						|
                ErrorF("[dix] motion events from device %d without valuators\n", pDev->id);
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
 | 
						|
                return 0;
 | 
						|
            break;
 | 
						|
        case ButtonPress:
 | 
						|
        case ButtonRelease:
 | 
						|
            if (!pDev->button || !buttons)
 | 
						|
                return 0;
 | 
						|
            if (mask_in && valuator_mask_size(mask_in) > 0 && !pDev->valuator)
 | 
						|
            {
 | 
						|
                ErrorF("[dix] button event with valuator from device %d without valuators\n", pDev->id);
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    valuator_mask_copy(&mask, mask_in);
 | 
						|
 | 
						|
    if ((flags & POINTER_NORAW) == 0)
 | 
						|
    {
 | 
						|
	raw = &events->raw_event;
 | 
						|
	events++;
 | 
						|
	num_events++;
 | 
						|
 | 
						|
	init_raw(pDev, raw, ms, type, buttons);
 | 
						|
        set_raw_valuators(raw, &mask, raw->valuators.data_raw);
 | 
						|
    }
 | 
						|
 | 
						|
    if (flags & POINTER_ABSOLUTE)
 | 
						|
    {
 | 
						|
        if (flags & POINTER_SCREEN) /* valuators are in screen coords */
 | 
						|
            scale_from_screen(pDev, &mask);
 | 
						|
 | 
						|
        transformAbsolute(pDev, &mask);
 | 
						|
        clipAbsolute(pDev, &mask);
 | 
						|
    } else {
 | 
						|
        if (flags & POINTER_ACCELERATE)
 | 
						|
            accelPointer(pDev, &mask, ms);
 | 
						|
        moveRelative(pDev, &mask);
 | 
						|
    }
 | 
						|
 | 
						|
    if ((flags & POINTER_NORAW) == 0)
 | 
						|
        set_raw_valuators(raw, &mask, raw->valuators.data);
 | 
						|
 | 
						|
    positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
 | 
						|
                   &mask, &screenx, &screeny);
 | 
						|
    updateHistory(pDev, &mask, ms);
 | 
						|
 | 
						|
    clipValuators(pDev, &mask);
 | 
						|
 | 
						|
    for (i = 0; i < valuator_mask_size(&mask); i++)
 | 
						|
    {
 | 
						|
        if (valuator_mask_isset(&mask, i))
 | 
						|
            pDev->last.valuators[i] = valuator_mask_get_double(&mask, i);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Update the MD's co-ordinates, which are always in screen space. */
 | 
						|
    if (!IsMaster(pDev) || !IsFloating(pDev)) {
 | 
						|
        DeviceIntPtr master = GetMaster(pDev, MASTER_POINTER);
 | 
						|
        master->last.valuators[0] = screenx;
 | 
						|
        master->last.valuators[1] = screeny;
 | 
						|
    }
 | 
						|
 | 
						|
    event = &events->device_event;
 | 
						|
    init_device_event(event, pDev, ms);
 | 
						|
 | 
						|
    if (type == MotionNotify) {
 | 
						|
        event->type = ET_Motion;
 | 
						|
        event->detail.button = 0;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        if (type == ButtonPress) {
 | 
						|
            event->type = ET_ButtonPress;
 | 
						|
            set_button_down(pDev, buttons, BUTTON_POSTED);
 | 
						|
        }
 | 
						|
        else if (type == ButtonRelease) {
 | 
						|
            event->type = ET_ButtonRelease;
 | 
						|
            set_button_up(pDev, buttons, BUTTON_POSTED);
 | 
						|
        }
 | 
						|
        event->detail.button = buttons;
 | 
						|
    }
 | 
						|
 | 
						|
    /* root_x and root_y must be in screen co-ordinates */
 | 
						|
    event_set_root_coordinates(event, screenx, screeny);
 | 
						|
 | 
						|
    if (flags & POINTER_EMULATED) {
 | 
						|
        raw->flags = XIPointerEmulated;
 | 
						|
        event->flags = XIPointerEmulated;
 | 
						|
    }
 | 
						|
 | 
						|
    set_valuators(pDev, event, &mask);
 | 
						|
 | 
						|
    return num_events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate events for each scroll axis that changed between before/after
 | 
						|
 * for the device.
 | 
						|
 *
 | 
						|
 * @param events The pointer to the event list to fill the events
 | 
						|
 * @param dev The device to generate the events for
 | 
						|
 * @param type The real type of the event
 | 
						|
 * @param axis The axis number to generate events for
 | 
						|
 * @param mask State before this event in absolute coords
 | 
						|
 * @param[in,out] last Last scroll state posted in absolute coords (modified
 | 
						|
 * in-place)
 | 
						|
 * @param ms Current time in ms
 | 
						|
 * @param max_events Max number of events to be generated
 | 
						|
 * @return The number of events generated
 | 
						|
 */
 | 
						|
static int
 | 
						|
emulate_scroll_button_events(InternalEvent *events,
 | 
						|
                             DeviceIntPtr dev,
 | 
						|
                             int type,
 | 
						|
                             int axis,
 | 
						|
                             const ValuatorMask *mask,
 | 
						|
                             ValuatorMask *last,
 | 
						|
                             CARD32 ms,
 | 
						|
                             int max_events)
 | 
						|
{
 | 
						|
    AxisInfoPtr ax;
 | 
						|
    double delta;
 | 
						|
    double incr;
 | 
						|
    int num_events = 0;
 | 
						|
    double total;
 | 
						|
    int b;
 | 
						|
    int flags = 0;
 | 
						|
 | 
						|
    if (dev->valuator->axes[axis].scroll.type == SCROLL_TYPE_NONE)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (!valuator_mask_isset(mask, axis))
 | 
						|
        return 0;
 | 
						|
 | 
						|
    ax = &dev->valuator->axes[axis];
 | 
						|
    incr = ax->scroll.increment;
 | 
						|
 | 
						|
    if (type != ButtonPress && type != ButtonRelease)
 | 
						|
        flags |= POINTER_EMULATED;
 | 
						|
 | 
						|
    if (!valuator_mask_isset(last, axis))
 | 
						|
        valuator_mask_set_double(last, axis, 0);
 | 
						|
 | 
						|
    delta = valuator_mask_get_double(mask, axis) - valuator_mask_get_double(last, axis);
 | 
						|
    total = delta;
 | 
						|
    b = (ax->scroll.type == SCROLL_TYPE_VERTICAL) ? 5 : 7;
 | 
						|
 | 
						|
    if ((incr > 0 && delta < 0) ||
 | 
						|
        (incr < 0 && delta > 0))
 | 
						|
        b--; /* we're scrolling up or left → button 4 or 6 */
 | 
						|
 | 
						|
    while (fabs(delta) >= fabs(incr))
 | 
						|
    {
 | 
						|
        int nev_tmp;
 | 
						|
 | 
						|
        if (delta > 0)
 | 
						|
            delta -= fabs(incr);
 | 
						|
        else if (delta < 0)
 | 
						|
            delta += fabs(incr);
 | 
						|
 | 
						|
        /* fill_pointer_events() generates four events: one normal and one raw
 | 
						|
         * event for button press and button release.
 | 
						|
         * We may get a bigger scroll delta than we can generate events
 | 
						|
         * for. In that case, we keep decreasing delta, but skip events.
 | 
						|
         */
 | 
						|
        if (num_events + 4 < max_events)
 | 
						|
        {
 | 
						|
            if (type != ButtonRelease)
 | 
						|
            {
 | 
						|
                nev_tmp = fill_pointer_events(events, dev, ButtonPress, b, ms,
 | 
						|
                                              flags, NULL);
 | 
						|
                events += nev_tmp;
 | 
						|
                num_events += nev_tmp;
 | 
						|
            }
 | 
						|
            if (type != ButtonPress)
 | 
						|
            {
 | 
						|
                nev_tmp = fill_pointer_events(events, dev, ButtonRelease, b, ms,
 | 
						|
                                              flags, NULL);
 | 
						|
                events += nev_tmp;
 | 
						|
                num_events += nev_tmp;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* We emulated, update last.scroll */
 | 
						|
    if (total != delta)
 | 
						|
    {
 | 
						|
        total -= delta;
 | 
						|
        valuator_mask_set_double(last, axis,
 | 
						|
                                 valuator_mask_get_double(last, axis) + total);
 | 
						|
    }
 | 
						|
 | 
						|
    return num_events;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate a complete series of InternalEvents (filled into the EventList)
 | 
						|
 * representing pointer motion, or button presses.  If the device is a slave
 | 
						|
 * device, also potentially generate a DeviceClassesChangedEvent to update
 | 
						|
 * the master device.
 | 
						|
 *
 | 
						|
 * events is not NULL-terminated; the return value is the number of events.
 | 
						|
 * The DDX is responsible for allocating the event structure in the first
 | 
						|
 * place via InitEventList() and GetMaximumEventsNum(), and for freeing it.
 | 
						|
 *
 | 
						|
 * In the generated events rootX/Y will be in absolute screen coords and
 | 
						|
 * the valuator information in the absolute or relative device coords.
 | 
						|
 *
 | 
						|
 * last.valuators[x] of the device is always in absolute device coords.
 | 
						|
 * last.valuators[x] of the master device is in absolute screen coords.
 | 
						|
 *
 | 
						|
 * master->last.valuators[x] for x > 2 is undefined.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type,
 | 
						|
                 int buttons, int flags, const ValuatorMask *mask_in)
 | 
						|
{
 | 
						|
    CARD32 ms = GetTimeInMillis();
 | 
						|
    int num_events = 0, nev_tmp;
 | 
						|
    int h_scroll_axis = pDev->valuator->h_scroll_axis;
 | 
						|
    int v_scroll_axis = pDev->valuator->v_scroll_axis;
 | 
						|
    ValuatorMask mask;
 | 
						|
    ValuatorMask scroll;
 | 
						|
    int i;
 | 
						|
    int realtype = type;
 | 
						|
 | 
						|
    /* refuse events from disabled devices */
 | 
						|
    if (!pDev->enabled)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    if (!miPointerGetScreen(pDev))
 | 
						|
        return 0;
 | 
						|
 | 
						|
    events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT,
 | 
						|
                              &num_events);
 | 
						|
 | 
						|
    valuator_mask_copy(&mask, mask_in);
 | 
						|
 | 
						|
    /* Turn a scroll button press into a smooth-scrolling event if
 | 
						|
     * necessary. This only needs to cater for the XIScrollFlagPreferred
 | 
						|
     * axis (if more than one scrolling axis is present) */
 | 
						|
    if (type == ButtonPress)
 | 
						|
    {
 | 
						|
        double val, adj;
 | 
						|
        int axis;
 | 
						|
 | 
						|
        /* Up is negative on valuators, down positive */
 | 
						|
        switch (buttons) {
 | 
						|
        case 4:
 | 
						|
            adj = -1.0;
 | 
						|
            axis = v_scroll_axis;
 | 
						|
            break;
 | 
						|
        case 5:
 | 
						|
            adj = 1.0;
 | 
						|
            axis = v_scroll_axis;
 | 
						|
            break;
 | 
						|
        case 6:
 | 
						|
            adj = -1.0;
 | 
						|
            axis = h_scroll_axis;
 | 
						|
            break;
 | 
						|
        case 7:
 | 
						|
            adj = 1.0;
 | 
						|
            axis = h_scroll_axis;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            adj = 0.0;
 | 
						|
            axis = -1;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        if (adj != 0.0 && axis != -1)
 | 
						|
        {
 | 
						|
            adj *= pDev->valuator->axes[axis].scroll.increment;
 | 
						|
            val = valuator_mask_get_double(&mask, axis) + adj;
 | 
						|
            valuator_mask_set_double(&mask, axis, val);
 | 
						|
            type = MotionNotify;
 | 
						|
            buttons = 0;
 | 
						|
            flags |= POINTER_EMULATED;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* First fill out the original event set, with smooth-scrolling axes. */
 | 
						|
    nev_tmp = fill_pointer_events(events, pDev, type, buttons, ms, flags,
 | 
						|
                                  &mask);
 | 
						|
    events += nev_tmp;
 | 
						|
    num_events += nev_tmp;
 | 
						|
 | 
						|
    valuator_mask_zero(&scroll);
 | 
						|
 | 
						|
    /* Now turn the smooth-scrolling axes back into emulated button presses
 | 
						|
     * for legacy clients, based on the integer delta between before and now */
 | 
						|
    for (i = 0; i < valuator_mask_size(&mask); i++) {
 | 
						|
        if (!valuator_mask_isset(&mask, i))
 | 
						|
            continue;
 | 
						|
 | 
						|
        valuator_mask_set_double(&scroll, i, pDev->last.valuators[i]);
 | 
						|
 | 
						|
        nev_tmp = emulate_scroll_button_events(events, pDev, realtype, i, &scroll,
 | 
						|
                                               pDev->last.scroll, ms,
 | 
						|
                                               GetMaximumEventsNum() - num_events);
 | 
						|
        events += nev_tmp;
 | 
						|
        num_events += nev_tmp;
 | 
						|
    }
 | 
						|
 | 
						|
    return num_events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate internal events representing this proximity event and enqueue
 | 
						|
 * them on the event queue.
 | 
						|
 *
 | 
						|
 * This function is not reentrant. Disable signals before calling.
 | 
						|
 *
 | 
						|
 * @param device The device to generate the event for
 | 
						|
 * @param type Event type, one of ProximityIn or ProximityOut
 | 
						|
 * @param keycode Key code of the pressed/released key
 | 
						|
 * @param mask Valuator mask for valuators present for this event.
 | 
						|
 *
 | 
						|
 */
 | 
						|
void
 | 
						|
QueueProximityEvents(DeviceIntPtr device, int type,
 | 
						|
                     const ValuatorMask *mask)
 | 
						|
{
 | 
						|
    int nevents;
 | 
						|
 | 
						|
    nevents = GetProximityEvents(InputEventList, device, type, mask);
 | 
						|
    queueEventList(device, InputEventList, nevents);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Generate ProximityIn/ProximityOut InternalEvents, accompanied by
 | 
						|
 * valuators.
 | 
						|
 *
 | 
						|
 * The DDX is responsible for allocating the events in the first place via
 | 
						|
 * InitEventList(), and for freeing it.
 | 
						|
 *
 | 
						|
 * @return the number of events written into events.
 | 
						|
 */
 | 
						|
int
 | 
						|
GetProximityEvents(InternalEvent *events, DeviceIntPtr pDev, int type, const ValuatorMask *mask_in)
 | 
						|
{
 | 
						|
    int num_events = 1, i;
 | 
						|
    DeviceEvent *event;
 | 
						|
    ValuatorMask mask;
 | 
						|
 | 
						|
    /* refuse events from disabled devices */
 | 
						|
    if (!pDev->enabled)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* Sanity checks. */
 | 
						|
    if ((type != ProximityIn && type != ProximityOut) || !mask_in)
 | 
						|
        return 0;
 | 
						|
    if (!pDev->valuator)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    valuator_mask_copy(&mask, mask_in);
 | 
						|
 | 
						|
    /* ignore relative axes for proximity. */
 | 
						|
    for (i = 0; i < valuator_mask_size(&mask); i++)
 | 
						|
    {
 | 
						|
        if (valuator_mask_isset(&mask, i) &&
 | 
						|
            valuator_get_mode(pDev, i) == Relative)
 | 
						|
            valuator_mask_unset(&mask, i);
 | 
						|
    }
 | 
						|
 | 
						|
    /* FIXME: posting proximity events with relative valuators only results
 | 
						|
     * in an empty event, EventToXI() will fail to convert → no event sent
 | 
						|
     * to client. */
 | 
						|
 | 
						|
    events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
 | 
						|
 | 
						|
    event = &events->device_event;
 | 
						|
    init_device_event(event, pDev, GetTimeInMillis());
 | 
						|
    event->type = (type == ProximityIn) ? ET_ProximityIn : ET_ProximityOut;
 | 
						|
 | 
						|
    clipValuators(pDev, &mask);
 | 
						|
 | 
						|
    set_valuators(pDev, event, &mask);
 | 
						|
 | 
						|
    return num_events;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Synthesize a single motion event for the core pointer.
 | 
						|
 *
 | 
						|
 * Used in cursor functions, e.g. when cursor confinement changes, and we need
 | 
						|
 * to shift the pointer to get it inside the new bounds.
 | 
						|
 */
 | 
						|
void
 | 
						|
PostSyntheticMotion(DeviceIntPtr pDev,
 | 
						|
                    int x,
 | 
						|
                    int y,
 | 
						|
                    int screen,
 | 
						|
                    unsigned long time)
 | 
						|
{
 | 
						|
    DeviceEvent ev;
 | 
						|
 | 
						|
#ifdef PANORAMIX
 | 
						|
    /* Translate back to the sprite screen since processInputProc
 | 
						|
       will translate from sprite screen to screen 0 upon reentry
 | 
						|
       to the DIX layer. */
 | 
						|
    if (!noPanoramiXExtension) {
 | 
						|
        x += screenInfo.screens[0]->x - screenInfo.screens[screen]->x;
 | 
						|
        y += screenInfo.screens[0]->y - screenInfo.screens[screen]->y;
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    memset(&ev, 0, sizeof(DeviceEvent));
 | 
						|
    init_device_event(&ev, pDev, time);
 | 
						|
    ev.root_x = x;
 | 
						|
    ev.root_y = y;
 | 
						|
    ev.type = ET_Motion;
 | 
						|
    ev.time = time;
 | 
						|
 | 
						|
    /* FIXME: MD/SD considerations? */
 | 
						|
    (*pDev->public.processInputProc)((InternalEvent*)&ev, pDev);
 | 
						|
}
 |