1377 lines
41 KiB
C
1377 lines
41 KiB
C
/*
|
|
* Copyright © 2006 Nokia Corporation
|
|
* Copyright © 2006-2007 Daniel Stone
|
|
* Copyright © 2008 Red Hat, Inc.
|
|
*
|
|
* 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/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_event(DeviceIntPtr dev, DeviceEvent* event, Time ms)
|
|
{
|
|
memset(event, 0, sizeof(DeviceEvent));
|
|
event->header = ET_Internal;
|
|
event->length = sizeof(DeviceEvent);
|
|
event->time = ms;
|
|
event->deviceid = dev->id;
|
|
event->sourceid = dev->id;
|
|
}
|
|
|
|
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, int32_t* 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(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(mask, i);
|
|
event->valuators.data_frac[i] =
|
|
dev->last.remainder[i] * (1 << 16) * (1 << 16);
|
|
}
|
|
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 int
|
|
rescaleValuatorAxis(int coord, float remainder, float *remainder_return, AxisInfoPtr from, AxisInfoPtr to,
|
|
int defmax)
|
|
{
|
|
int fmin = 0, tmin = 0, fmax = defmax, tmax = defmax, coord_return;
|
|
float value;
|
|
|
|
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) {
|
|
if (remainder_return)
|
|
*remainder_return = remainder;
|
|
return coord;
|
|
}
|
|
|
|
if(fmax == fmin) { /* avoid division by 0 */
|
|
if (remainder_return)
|
|
*remainder_return = 0.0;
|
|
return 0;
|
|
}
|
|
|
|
value = (coord + remainder - fmin) * (tmax - tmin) / (fmax - fmin) + tmin;
|
|
coord_return = lroundf(value);
|
|
if (remainder_return)
|
|
*remainder_return = value - coord_return;
|
|
return coord_return;
|
|
}
|
|
|
|
/**
|
|
* 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];
|
|
pDev->last.remainder[0] = master->last.remainder[0];
|
|
pDev->last.remainder[1] = master->last.remainder[1];
|
|
|
|
if (!pDev->valuator)
|
|
return;
|
|
|
|
/* scale back to device coordinates */
|
|
if(pDev->valuator->numAxes > 0)
|
|
pDev->last.valuators[0] = rescaleValuatorAxis(pDev->last.valuators[0], pDev->last.remainder[0],
|
|
&pDev->last.remainder[0], NULL, pDev->valuator->axes + 0, scr->width);
|
|
if(pDev->valuator->numAxes > 1)
|
|
pDev->last.valuators[1] = rescaleValuatorAxis(pDev->last.valuators[1], pDev->last.remainder[1],
|
|
&pDev->last.remainder[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;
|
|
pDev->last.remainder[i] = 0;
|
|
}
|
|
else
|
|
{
|
|
pDev->last.valuators[i] =
|
|
rescaleValuatorAxis(pDev->last.valuators[i],
|
|
pDev->last.remainder[i],
|
|
&pDev->last.remainder[i],
|
|
lastSlave->valuator->axes + i,
|
|
pDev->valuator->axes + i, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
int dflt;
|
|
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, 0.0, NULL, &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, 0.0, NULL, &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;
|
|
|
|
if (j == 0 && (to->max_value < to->min_value))
|
|
dflt = pScreen->width;
|
|
else if (j == 1 && (to->max_value < to->min_value))
|
|
dflt = pScreen->height;
|
|
else
|
|
dflt = 0;
|
|
|
|
/* scale from stored range into current range */
|
|
coord = rescaleValuatorAxis(coord, 0.0, NULL, &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,
|
|
int *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++)
|
|
{
|
|
/* 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);
|
|
memcpy(buff, &valuators[i], 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++)
|
|
{
|
|
if (valuator_mask_size(mask) <= i || !valuator_mask_isset(mask, i))
|
|
{
|
|
buff += sizeof(INT32);
|
|
continue;
|
|
}
|
|
memcpy(buff, &valuators[i], 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
|
|
*/
|
|
return 3;
|
|
}
|
|
|
|
|
|
/**
|
|
* Clip an axis to its bounds, which are declared in the call to
|
|
* InitValuatorAxisClassStruct.
|
|
*/
|
|
static void
|
|
clipAxis(DeviceIntPtr pDev, int axisNum, int *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))
|
|
{
|
|
int val = valuator_mask_get(mask, i);
|
|
clipAxis(pDev, i, &val);
|
|
valuator_mask_set(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 which's pointer is to be moved.
|
|
* @param x Returns the x position of the pointer after the move.
|
|
* @param y Returns the y position of the pointer after the move.
|
|
* @param mask Bit mask of valid valuators.
|
|
* @param valuators Valuator data for each axis between @first and
|
|
* @first+@num.
|
|
*/
|
|
static void
|
|
moveAbsolute(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
|
|
{
|
|
int i;
|
|
|
|
if (valuator_mask_isset(mask, 0))
|
|
*x = valuator_mask_get(mask, 0);
|
|
else
|
|
*x = dev->last.valuators[0];
|
|
|
|
if (valuator_mask_isset(mask, 1))
|
|
*y = valuator_mask_get(mask, 1);
|
|
else
|
|
*y = dev->last.valuators[1];
|
|
|
|
clipAxis(dev, 0, x);
|
|
clipAxis(dev, 1, y);
|
|
|
|
for (i = 2; i < valuator_mask_size(mask); i++)
|
|
{
|
|
if (valuator_mask_isset(mask, i))
|
|
{
|
|
dev->last.valuators[i] = valuator_mask_get(mask, i);
|
|
clipAxis(dev, i, &dev->last.valuators[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Move the device's pointer by the values given in @valuators.
|
|
*
|
|
* @param dev The device which's pointer is to be moved.
|
|
* @param x Returns the x position of the pointer after the move.
|
|
* @param y Returns the y position of the pointer after the move.
|
|
* @param mask Bit mask of valid valuators.
|
|
* @param valuators Valuator data for each axis between @first and
|
|
* @first+@num.
|
|
*/
|
|
static void
|
|
moveRelative(DeviceIntPtr dev, int *x, int *y, ValuatorMask *mask)
|
|
{
|
|
int i;
|
|
|
|
*x = dev->last.valuators[0];
|
|
*y = dev->last.valuators[1];
|
|
|
|
if (valuator_mask_isset(mask, 0))
|
|
*x += valuator_mask_get(mask, 0);
|
|
|
|
if (valuator_mask_isset(mask, 1))
|
|
*y += valuator_mask_get(mask, 1);
|
|
|
|
/* if attached, clip both x and y to the defined limits (usually
|
|
* co-ord space limit). If it is attached, we need x/y to go over the
|
|
* limits to be able to change screens. */
|
|
if (dev->valuator && (IsMaster(dev) || !IsFloating(dev))) {
|
|
if (valuator_get_mode(dev, 0) == Absolute)
|
|
clipAxis(dev, 0, x);
|
|
if (valuator_get_mode(dev, 1) == Absolute)
|
|
clipAxis(dev, 1, y);
|
|
}
|
|
|
|
/* calc other axes, clip, drop back into valuators */
|
|
for (i = 2; i < valuator_mask_size(mask); i++)
|
|
{
|
|
if (valuator_mask_isset(mask, i))
|
|
{
|
|
dev->last.valuators[i] += valuator_mask_get(mask, i);
|
|
if (valuator_get_mode(dev, i) == Absolute)
|
|
clipAxis(dev, i, &dev->last.valuators[i]);
|
|
valuator_mask_set(mask, i, dev->last.valuators[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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 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 x Pointer to current x-axis value, may be modified.
|
|
* @param y Pointer to current y-axis value, may be modified.
|
|
* @param x_frac Fractional part of current x-axis value, may be modified.
|
|
* @param y_frac Fractional part of current y-axis value, may be modified.
|
|
* @param scr Screen the device's sprite is currently on.
|
|
* @param screenx Screen x coordinate the sprite is on after the update.
|
|
* @param screeny Screen y coordinate the sprite is on after the update.
|
|
* @param screenx_frac Fractional part of screen x coordinate, as above.
|
|
* @param screeny_frac Fractional part of screen y coordinate, as above.
|
|
*/
|
|
static void
|
|
positionSprite(DeviceIntPtr dev, int mode,
|
|
int *x, int *y, float x_frac, float y_frac,
|
|
ScreenPtr scr, int *screenx, int *screeny, float *screenx_frac, float *screeny_frac)
|
|
{
|
|
int old_screenx, old_screeny;
|
|
|
|
/* scale x&y to screen */
|
|
if (dev->valuator && dev->valuator->numAxes > 0) {
|
|
*screenx = rescaleValuatorAxis(*x, x_frac, screenx_frac,
|
|
dev->valuator->axes + 0, NULL, scr->width);
|
|
} else {
|
|
*screenx = dev->last.valuators[0];
|
|
*screenx_frac = dev->last.remainder[0];
|
|
}
|
|
|
|
if (dev->valuator && dev->valuator->numAxes > 1) {
|
|
*screeny = rescaleValuatorAxis(*y, y_frac, screeny_frac,
|
|
dev->valuator->axes + 1, NULL, scr->height);
|
|
} else {
|
|
*screeny = dev->last.valuators[1];
|
|
*screeny_frac = dev->last.remainder[1];
|
|
}
|
|
|
|
/* Hit the left screen edge? */
|
|
if (*screenx <= 0 && *screenx_frac < 0.0f)
|
|
{
|
|
*screenx_frac = 0.0f;
|
|
x_frac = 0.0f;
|
|
}
|
|
if (*screeny <= 0 && *screeny_frac < 0.0f)
|
|
{
|
|
*screeny_frac = 0.0f;
|
|
y_frac = 0.0f;
|
|
}
|
|
|
|
|
|
old_screenx = *screenx;
|
|
old_screeny = *screeny;
|
|
/* This takes care of crossing screens for us, as well as clipping
|
|
* to the current screen. */
|
|
miPointerSetPosition(dev, mode, screenx, screeny);
|
|
|
|
if(!IsMaster(dev) && !IsFloating(dev)) {
|
|
DeviceIntPtr master = GetMaster(dev, MASTER_POINTER);
|
|
master->last.valuators[0] = *screenx;
|
|
master->last.valuators[1] = *screeny;
|
|
master->last.remainder[0] = *screenx_frac;
|
|
master->last.remainder[1] = *screeny_frac;
|
|
}
|
|
|
|
if (dev->valuator)
|
|
{
|
|
/* Crossed screen? Scale back to device coordiantes */
|
|
if(*screenx != old_screenx)
|
|
{
|
|
scr = miPointerGetScreen(dev);
|
|
*x = rescaleValuatorAxis(*screenx, *screenx_frac, &x_frac, NULL,
|
|
dev->valuator->axes + 0, scr->width);
|
|
}
|
|
if(*screeny != old_screeny)
|
|
{
|
|
scr = miPointerGetScreen(dev);
|
|
*y = rescaleValuatorAxis(*screeny, *screeny_frac, &y_frac, NULL,
|
|
dev->valuator->axes + 1, scr->height);
|
|
}
|
|
}
|
|
|
|
/* dropy x/y (device coordinates) back into valuators for next event */
|
|
dev->last.valuators[0] = *x;
|
|
dev->last.valuators[1] = *y;
|
|
dev->last.remainder[0] = x_frac;
|
|
dev->last.remainder[1] = y_frac;
|
|
}
|
|
|
|
/**
|
|
* 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]);
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
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_event(pDev, event, 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);
|
|
|
|
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, int *x, int *y)
|
|
{
|
|
struct pixman_f_vector p = {.v = {*x, *y, 1}};
|
|
pixman_f_transform_point(m, &p);
|
|
|
|
*x = lround(p.v[0]);
|
|
*y = lround(p.v[1]);
|
|
}
|
|
|
|
static void
|
|
transformAbsolute(DeviceIntPtr dev, ValuatorMask *mask)
|
|
{
|
|
int x, y, ox, oy;
|
|
|
|
ox = x = valuator_mask_isset(mask, 0) ? valuator_mask_get(mask, 0) :
|
|
dev->last.valuators[0];
|
|
oy = y = valuator_mask_isset(mask, 1) ? valuator_mask_get(mask, 1) :
|
|
dev->last.valuators[1];
|
|
|
|
transform(&dev->transform, &x, &y);
|
|
|
|
if (valuator_mask_isset(mask, 0) || ox != x)
|
|
valuator_mask_set(mask, 0, x);
|
|
|
|
if (valuator_mask_isset(mask, 1) || oy != y)
|
|
valuator_mask_set(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);
|
|
}
|
|
|
|
/**
|
|
* Generate a series of InternalEvents representing pointer motion, or
|
|
* button presses.
|
|
*
|
|
* The DDX is responsible for allocating the events 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.
|
|
*
|
|
* @return the number of events written into events.
|
|
*/
|
|
int
|
|
GetPointerEvents(InternalEvent *events, DeviceIntPtr pDev, int type, int buttons,
|
|
int flags, const ValuatorMask *mask_in) {
|
|
int num_events = 1;
|
|
CARD32 ms;
|
|
DeviceEvent *event;
|
|
RawDeviceEvent *raw;
|
|
int x = 0, y = 0, /* device coords */
|
|
cx, cy; /* only screen coordinates */
|
|
float x_frac = 0.0, y_frac = 0.0, cx_frac, cy_frac;
|
|
ScreenPtr scr = miPointerGetScreen(pDev);
|
|
ValuatorMask mask;
|
|
|
|
/* refuse events from disabled devices */
|
|
if (!pDev->enabled)
|
|
return 0;
|
|
|
|
if (!scr)
|
|
return 0;
|
|
|
|
switch (type)
|
|
{
|
|
case MotionNotify:
|
|
if (!mask_in || valuator_mask_num_valuators(mask_in) <= 0)
|
|
return 0;
|
|
break;
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
if (!pDev->button || !buttons)
|
|
return 0;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
ms = GetTimeInMillis(); /* before pointer update to help precision */
|
|
|
|
events = UpdateFromMaster(events, pDev, DEVCHANGE_POINTER_EVENT, &num_events);
|
|
|
|
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 */
|
|
{
|
|
int scaled;
|
|
|
|
if (valuator_mask_isset(&mask, 0))
|
|
{
|
|
scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 0),
|
|
0.0, &x_frac, NULL,
|
|
pDev->valuator->axes + 0,
|
|
scr->width);
|
|
valuator_mask_set(&mask, 0, scaled);
|
|
}
|
|
if (valuator_mask_isset(&mask, 1))
|
|
{
|
|
scaled = rescaleValuatorAxis(valuator_mask_get(&mask, 1),
|
|
0.0, &y_frac, NULL,
|
|
pDev->valuator->axes + 1,
|
|
scr->height);
|
|
valuator_mask_set(&mask, 1, scaled);
|
|
}
|
|
}
|
|
|
|
transformAbsolute(pDev, &mask);
|
|
moveAbsolute(pDev, &x, &y, &mask);
|
|
} else {
|
|
if (flags & POINTER_ACCELERATE) {
|
|
accelPointer(pDev, &mask, ms);
|
|
/* The pointer acceleration code modifies the fractional part
|
|
* in-place, so we need to extract this information first */
|
|
x_frac = pDev->last.remainder[0];
|
|
y_frac = pDev->last.remainder[1];
|
|
}
|
|
moveRelative(pDev, &x, &y, &mask);
|
|
}
|
|
|
|
if ((flags & POINTER_NORAW) == 0)
|
|
set_raw_valuators(raw, &mask, raw->valuators.data);
|
|
|
|
positionSprite(pDev, (flags & POINTER_ABSOLUTE) ? Absolute : Relative,
|
|
&x, &y, x_frac, y_frac, scr, &cx, &cy, &cx_frac, &cy_frac);
|
|
updateHistory(pDev, &mask, ms);
|
|
|
|
/* Update the valuators with the true value sent to the client*/
|
|
if (valuator_mask_isset(&mask, 0))
|
|
valuator_mask_set(&mask, 0, x);
|
|
if (valuator_mask_isset(&mask, 1))
|
|
valuator_mask_set(&mask, 1, y);
|
|
|
|
clipValuators(pDev, &mask);
|
|
|
|
event = &events->device_event;
|
|
init_event(pDev, event, 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;
|
|
}
|
|
|
|
event->root_x = cx; /* root_x/y always in screen coords */
|
|
event->root_y = cy;
|
|
event->root_x_frac = cx_frac;
|
|
event->root_y_frac = cy_frac;
|
|
|
|
set_valuators(pDev, event, &mask);
|
|
|
|
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 || !pDev->proximity)
|
|
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_event(pDev, event, 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_event(pDev, &ev, 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);
|
|
}
|