xserver-multidpi/dix/getevents.c
Keith Packard 8c9234a163 Xi: avoid double button mapping.
Button events were mapped once in GetPointerEvents and then again in
UpdateDeviceState. While it might make sense to just fix up UpdateDeviceState,
it turns out to be better to leave the raw button number in the event because
DGA reports raw device events without button translation, and so when it calls
UpdateDeviceState, the button down counts get scrambled and buttons get stuck
down.

See also:
http://lists.freedesktop.org/archives/xorg/2008-June/036201.html

Signed-off-by: Peter Hutterer <peter@cs.unisa.edu.au>
2008-06-15 11:47:24 +09:30

1164 lines
36 KiB
C

/*
* Copyright © 2006 Nokia Corporation
* Copyright © 2006-2007 Daniel Stone
*
* 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.
*
* Author: Daniel Stone <daniel@fooishbar.org>
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/keysym.h>
#define NEED_EVENTS
#define NEED_REPLIES
#include <X11/Xproto.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"
#ifdef XKB
#include <X11/extensions/XKBproto.h>
#include <xkbsrv.h>
extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies);
#endif
#ifdef PANORAMIX
#include "panoramiX.h"
#include "panoramiXsrv.h"
#endif
#include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h>
#include "exglobals.h"
#include "exevents.h"
#include "exglobals.h"
#include "extnsionst.h"
#include "listdev.h" /* for sizing up DeviceClassesChangedEvent */
/* Maximum number of valuators, divided by six, rounded up, to get number
* of events. */
#define MAX_VALUATOR_EVENTS 6
/* Number of motion history events to store. */
#define MOTION_HISTORY_SIZE 256
/* InputEventList is the container list for all input events generated by the
* DDX. The DDX is expected to call GetEventList() and then pass the list into
* Get{Pointer|Keyboard}Events.
*/
EventListPtr InputEventList = NULL;
int InputEventListLen = 0;
_X_EXPORT int
GetEventList(EventListPtr* list)
{
*list = InputEventList;
return InputEventListLen;
}
/**
* Pick some arbitrary size for Xi motion history.
*/
_X_EXPORT int
GetMotionHistorySize(void)
{
return MOTION_HISTORY_SIZE;
}
static void
set_key_down(DeviceIntPtr pDev, int key_code)
{
pDev->key->postdown[key_code >> 3] |= (1 << (key_code & 7));
}
static void
set_key_up(DeviceIntPtr pDev, int key_code)
{
pDev->key->postdown[key_code >> 3] &= ~(1 << (key_code & 7));
}
static Bool
key_is_down(DeviceIntPtr pDev, int key_code)
{
return !!(pDev->key->postdown[key_code >> 3] & (1 << (key_code & 7)));
}
static Bool
key_autorepeats(DeviceIntPtr pDev, int key_code)
{
return !!(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] &
(1 << (key_code & 7)));
}
void
CreateClassesChangedEvent(EventList* event,
DeviceIntPtr master,
DeviceIntPtr slave)
{
deviceClassesChangedEvent *dcce;
int len = sizeof(xEvent);
CARD32 ms = GetTimeInMillis();
int namelen = 0; /* dummy */
/* XXX: ok, this is a bit weird. We need to alloc enough size for the
* event so it can be filled in in POE lateron. Reason being that if
* we realloc the event in POE we can get SIGABRT when we try to free
* or realloc the original pointer.
* We can only do it here as we don't have the EventList in the event
* processing any more.
*/
SizeDeviceInfo(slave, &namelen, &len);
if (event->evlen < len)
{
event->event = realloc(event->event, len);
if (!event->event)
FatalError("[dix] Cannot allocate memory for "
"DeviceClassesChangedEvent.\n");
event->evlen = len;
}
dcce = (deviceClassesChangedEvent*)event->event;
dcce->type = GenericEvent;
dcce->extension = IReqCode;
dcce->evtype = XI_DeviceClassesChangedNotify;
dcce->time = ms;
dcce->new_slave = slave->id;
dcce->length = (len - sizeof(xEvent))/4;
}
/**
* Rescale the coord between the two axis ranges.
*/
static int
rescaleValuatorAxis(int coord, AxisInfoPtr from, AxisInfoPtr to,
int defmax)
{
int fmin = 0, tmin = 0, fmax = defmax, 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;
return (int)(((float)(coord - fmin)) * (tmax - tmin + 1) /
(fmax - fmin + 1)) + 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->u.lastSlave) && lastSlave->valuator) {
for (i = 2; i < pDev->valuator->numAxes; i++) {
if (i >= lastSlave->valuator->numAxes)
pDev->last.valuators[i] = 0;
else
pDev->last.valuators[i] =
rescaleValuatorAxis(pDev->last.valuators[i],
lastSlave->valuator->axes + i,
pDev->valuator->axes + i, 0);
}
}
}
/**
* Allocate the motion history buffer.
*/
_X_EXPORT void
AllocateMotionHistory(DeviceIntPtr pDev)
{
int size;
if (pDev->valuator->motion)
xfree(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 (pDev->isMaster)
size = sizeof(INT32) * 3 * MAX_VALUATORS;
else
size = sizeof(INT32) * pDev->valuator->numAxes;
size += sizeof(Time);
pDev->valuator->motion = xcalloc(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.
*/
_X_EXPORT 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 (pDev->isMaster)
size = (sizeof(INT32) * 3 * MAX_VALUATORS) + sizeof(Time);
else
size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
*buff = xalloc(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(&current, 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 (pDev->isMaster)
{
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, &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 (first_valuator > 0):
* min_val == max_val == val == 0.
*/
static void
updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator,
int num_valuators, int *valuators)
{
char *buff = (char *) pDev->valuator->motion;
ValuatorClassPtr v;
int i;
if (!pDev->valuator->numMotionEvents)
return;
v = pDev->valuator;
if (pDev->isMaster)
{
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);
buff += 3 * sizeof(INT32) * first_valuator;
for (i = first_valuator; i < first_valuator + num_valuators; i++)
{
if (i >= v->numAxes)
break;
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 - first_valuator], 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);
buff += sizeof(INT32) * first_valuator;
memcpy(buff, valuators, sizeof(INT32) * num_valuators);
}
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,
* GetKeyboardValuatorEvents, and GetPointerEvents will ever return.
*
* Should be used in DIX as:
* xEvent *events = xcalloc(sizeof(xEvent), GetMaximumEventsNum());
*
* This MUST be absolutely constant, from init until exit.
*/
_X_EXPORT int
GetMaximumEventsNum(void) {
/* One base event -- device, plus valuator events.
* Multiply by two if we're doing non-XKB key repeats. */
int ret = 1 + MAX_VALUATOR_EVENTS;
#ifdef XKB
if (noXkbExtension)
#endif
ret *= 2;
return ret;
}
/* Originally a part of xf86PostMotionEvent; modifies valuators
* in-place. */
static void
acceleratePointer(DeviceIntPtr pDev, int first_valuator, int num_valuators,
int *valuators)
{
float mult = 0.0;
int dx = 0, dy = 0;
int *px = NULL, *py = NULL;
if (!num_valuators || !valuators)
return;
if (first_valuator == 0) {
dx = valuators[0];
px = &valuators[0];
}
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
dy = valuators[1 - first_valuator];
py = &valuators[1 - first_valuator];
}
if (!dx && !dy)
return;
if (pDev->ptrfeed && pDev->ptrfeed->ctrl.num) {
/* modeled from xf86Events.c */
if (pDev->ptrfeed->ctrl.threshold) {
if ((abs(dx) + abs(dy)) >= pDev->ptrfeed->ctrl.threshold) {
pDev->valuator->dxremaind = ((float)dx *
(float)(pDev->ptrfeed->ctrl.num)) /
(float)(pDev->ptrfeed->ctrl.den) +
pDev->valuator->dxremaind;
if (px) {
*px = (int)pDev->valuator->dxremaind;
pDev->valuator->dxremaind = pDev->valuator->dxremaind -
(float)(*px);
}
pDev->valuator->dyremaind = ((float)dy *
(float)(pDev->ptrfeed->ctrl.num)) /
(float)(pDev->ptrfeed->ctrl.den) +
pDev->valuator->dyremaind;
if (py) {
*py = (int)pDev->valuator->dyremaind;
pDev->valuator->dyremaind = pDev->valuator->dyremaind -
(float)(*py);
}
}
}
else {
mult = pow((float)dx * (float)dx + (float)dy * (float)dy,
((float)(pDev->ptrfeed->ctrl.num) /
(float)(pDev->ptrfeed->ctrl.den) - 1.0) /
2.0) / 2.0;
if (dx) {
pDev->valuator->dxremaind = mult * (float)dx +
pDev->valuator->dxremaind;
*px = (int)pDev->valuator->dxremaind;
pDev->valuator->dxremaind = pDev->valuator->dxremaind -
(float)(*px);
}
if (dy) {
pDev->valuator->dyremaind = mult * (float)dy +
pDev->valuator->dyremaind;
*py = (int)pDev->valuator->dyremaind;
pDev->valuator->dyremaind = pDev->valuator->dyremaind -
(float)(*py);
}
}
}
}
/**
* 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 = pDev->valuator->axes + axisNum;
/* InitValuatoraAxisStruct ensures that (min < max). */
/* 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, int first_valuator, int num_valuators,
int *valuators)
{
AxisInfoPtr axes = pDev->valuator->axes + first_valuator;
int i;
for (i = 0; i < num_valuators; i++, axes++)
clipAxis(pDev, i + first_valuator, &(valuators[i]));
}
/**
* Fills events with valuator events for pDev, as given by the other
* parameters.
*
* FIXME: Need to fix ValuatorClassRec to store all the valuators as
* last posted, not just x and y; otherwise relative non-x/y
* valuators, though a very narrow use case, will be broken.
*/
static EventList *
getValuatorEvents(EventList *events, DeviceIntPtr pDev,
int first_valuator, int num_valuators, int *valuators) {
deviceValuator *xv;
int i;
for (i = 0; i < num_valuators; i += 6, events++) {
xv = (deviceValuator*)events->event;
xv->type = DeviceValuator;
xv->first_valuator = first_valuator + i;
xv->num_valuators = ((num_valuators - i) > 6) ? 6 : (num_valuators - i);
xv->deviceid = pDev->id;
switch (num_valuators - i) {
case 6:
xv->valuator5 = valuators[i + 5];
case 5:
xv->valuator4 = valuators[i + 4];
case 4:
xv->valuator3 = valuators[i + 3];
case 3:
xv->valuator2 = valuators[i + 2];
case 2:
xv->valuator1 = valuators[i + 1];
case 1:
xv->valuator0 = valuators[i + 0];
}
if (i + 6 < num_valuators)
xv->deviceid |= MORE_EVENTS;
}
return events;
}
/**
* Convenience wrapper around GetKeyboardValuatorEvents, that takes no
* valuators.
*/
_X_EXPORT int
GetKeyboardEvents(EventList *events, DeviceIntPtr pDev, int type, int key_code) {
return GetKeyboardValuatorEvents(events, pDev, type, key_code, 0, 0, NULL);
}
/**
* Returns a set of keyboard events for KeyPress/KeyRelease, optionally
* also with valuator events. Handles Xi and XKB.
*
* DOES NOT GENERATE CORE EVENTS! Core events are created when processing the
* event (ProcessOtherEvent).
*
* 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 GetMaximumEventsNum(), and for freeing it.
*
* This function does not change the core keymap to that of the device;
* that is done by SwitchCoreKeyboard, which is called from
* mieqProcessInputEvents. If replacing that function, take care to call
* SetCoreKeyboard before processInputProc, so keymaps are altered to suit.
*
* Note that this function recurses! If called for non-XKB, a repeating
* key press will trigger a matching KeyRelease, as well as the
* KeyPresses.
*/
_X_EXPORT int
GetKeyboardValuatorEvents(EventList *events, DeviceIntPtr pDev, int type,
int key_code, int first_valuator,
int num_valuators, int *valuators) {
int numEvents = 0;
CARD32 ms = 0;
KeySym *map;
KeySym sym;
deviceKeyButtonPointer *kbp = NULL;
DeviceIntPtr master;
if (!events)
return 0;
/* DO NOT WANT */
if (type != KeyPress && type != KeyRelease)
return 0;
if (!pDev->key || !pDev->focus || !pDev->kbdfeed)
return 0;
numEvents = 1;
if (key_code < 8 || key_code > 255)
return 0;
map = pDev->key->curKeySyms.map;
sym = map[key_code * pDev->key->curKeySyms.mapWidth];
master = pDev->u.master;
if (master && master->u.lastSlave != pDev)
{
CreateClassesChangedEvent(events, master, pDev);
updateSlaveDeviceCoords(master, pDev);
master->u.lastSlave = pDev;
master->last.numValuators = pDev->last.numValuators;
numEvents++;
events++;
}
if (num_valuators) {
if ((num_valuators / 6) + 1 > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS;
numEvents += (num_valuators / 6) + 1;
}
#ifdef XKB
if (noXkbExtension)
#endif
{
switch (sym) {
case XK_Num_Lock:
case XK_Caps_Lock:
case XK_Scroll_Lock:
case XK_Shift_Lock:
if (type == KeyRelease)
return 0;
else if (type == KeyPress && key_is_down(pDev, key_code))
type = KeyRelease;
}
}
/* Handle core repeating, via press/release/press/release.
* FIXME: In theory, if you're repeating with two keyboards in non-XKB,
* you could get unbalanced events here. */
if (type == KeyPress && key_is_down(pDev, key_code)) {
/* 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->modifierMap[key_code])
return 0;
#ifdef XKB
if (noXkbExtension)
#endif
{
numEvents += GetKeyboardValuatorEvents(events, pDev,
KeyRelease, key_code,
first_valuator, num_valuators,
valuators);
events += numEvents;
}
}
ms = GetTimeInMillis();
kbp = (deviceKeyButtonPointer *) events->event;
kbp->time = ms;
kbp->deviceid = pDev->id;
kbp->detail = key_code;
if (type == KeyPress) {
kbp->type = DeviceKeyPress;
set_key_down(pDev, key_code);
}
else if (type == KeyRelease) {
kbp->type = DeviceKeyRelease;
set_key_up(pDev, key_code);
}
events++;
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return numEvents;
}
/**
* Initialize an event list and fill with 32 byte sized events.
* This event list is to be passed into GetPointerEvents() and
* GetKeyboardEvents().
*
* @param num_events Number of elements in list.
*/
_X_EXPORT EventListPtr
InitEventList(int num_events)
{
EventListPtr events;
int i;
events = (EventListPtr)xcalloc(num_events, sizeof(EventList));
if (!events)
return NULL;
for (i = 0; i < num_events; i++)
{
events[i].evlen = sizeof(xEvent);
events[i].event = xcalloc(1, sizeof(xEvent));
if (!events[i].event)
{
/* rollback */
while(i--)
xfree(events[i].event);
xfree(events);
events = NULL;
break;
}
}
return events;
}
/**
* Allocs min_size memory for each event in the list.
*/
_X_EXPORT void
SetMinimumEventSize(EventListPtr list, int num_events, int min_size)
{
if (!list)
return;
while(num_events--)
{
if (list[num_events].evlen < min_size)
{
list[num_events].evlen = min_size;
list[num_events].event = realloc(list[num_events].event, min_size);
if (!list[num_events].event)
{
FatalError("[dix] Failed to set event list's "
"min_size to %d.\n", min_size);
}
}
}
}
/**
* Free an event list.
*
* @param list The list to be freed.
* @param num_events Number of elements in list.
*/
_X_EXPORT void
FreeEventList(EventListPtr list, int num_events)
{
if (!list)
return;
while(num_events--)
xfree(list[num_events].event);
xfree(list);
}
/**
* Generate a series of xEvents (filled into the EventList) representing
* pointer motion, or button presses. Xi and XKB-aware.
*
* DOES NOT GENERATE CORE EVENTS! Core events are created when processing the
* event (ProcessOtherEvent).
*
* 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.
*/
_X_EXPORT int
GetPointerEvents(EventList *events, DeviceIntPtr pDev, int type, int buttons,
int flags, int first_valuator, int num_valuators,
int *valuators) {
int num_events = 1;
CARD32 ms;
deviceKeyButtonPointer *kbp = NULL;
DeviceIntPtr master;
int x, y, /* switches between device and screen coords */
cx, cy; /* only screen coordinates */
ScreenPtr scr = miPointerGetScreen(pDev);
int *v0 = NULL, *v1 = NULL;
int i;
/* Sanity checks. */
if (type != MotionNotify && type != ButtonPress && type != ButtonRelease)
return 0;
if (type != MotionNotify && !pDev->button)
return 0;
/* FIXME: I guess it should, in theory, be possible to post button events
* from devices without valuators. */
if (!pDev->valuator)
return 0;
if (type == MotionNotify && num_valuators <= 0)
return 0;
ms = GetTimeInMillis();
/* Do we need to send a DeviceValuator event? */
if (num_valuators) {
if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS * 6;
num_events += ((num_valuators - 1) / 6) + 1;
}
/* You fail. */
if (first_valuator < 0 ||
(num_valuators + first_valuator) > pDev->valuator->numAxes)
return 0;
master = pDev->u.master;
if (master && master->u.lastSlave != pDev)
{
CreateClassesChangedEvent(events, master, pDev);
updateSlaveDeviceCoords(master, pDev);
master->u.lastSlave = pDev;
master->last.numValuators = pDev->last.numValuators;
num_events++;
events++;
}
/* Fetch pointers into the valuator array for more easy to read code */
if (num_valuators >= 1 && first_valuator == 0)
v0 = valuators + 0;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
v1 = valuators + 1 - first_valuator;
/* Set x and y based on whether this is absolute or relative, and
* accelerate if we need to. */
x = pDev->last.valuators[0];
y = pDev->last.valuators[1];
if (flags & POINTER_ABSOLUTE) {
if(v0) x = *v0;
if(v1) y = *v1;
/* Clip both x and y to the defined limits (usually co-ord space limit). */
clipAxis(pDev, 0, &x);
clipAxis(pDev, 1, &y);
i = (first_valuator > 2) ? 0 : 2;
for (; i < num_valuators; i++)
{
pDev->last.valuators[i + first_valuator] = valuators[i];
clipAxis(pDev, i, &pDev->last.valuators[i + first_valuator]);
}
}
else {
if (flags & POINTER_ACCELERATE)
acceleratePointer(pDev, first_valuator, num_valuators,
valuators);
if(v0) x += *v0;
if(v1) y += *v1;
/* 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(master) {
clipAxis(pDev, 0, &x);
clipAxis(pDev, 1, &y);
}
/* calc other axes, clip, drop back into valuators */
i = (first_valuator > 2) ? 0 : 2;
for (; i < num_valuators; i++)
{
pDev->last.valuators[i + first_valuator] += valuators[i];
clipAxis(pDev, i, &pDev->last.valuators[i + first_valuator]);
valuators[i] = pDev->last.valuators[i + first_valuator];
}
}
/* scale x&y to screen */
pDev->last.valuators[0] = cx = rescaleValuatorAxis(x, pDev->valuator->axes + 0,
NULL, scr->width);
pDev->last.valuators[1] = cy = rescaleValuatorAxis(y, pDev->valuator->axes + 1,
NULL, scr->height);
/* This takes care of crossing screens for us, as well as clipping
* to the current screen. Right now, we only have one history buffer,
* so we don't set this for both the device and core.*/
miPointerSetPosition(pDev, &pDev->last.valuators[0], &pDev->last.valuators[1], ms);
if (master) {
master->last.valuators[0] = pDev->last.valuators[0];
master->last.valuators[1] = pDev->last.valuators[1];
}
if(cx != pDev->last.valuators[0])
cx = pDev->last.valuators[0];
if(cy != pDev->last.valuators[1])
cy = pDev->last.valuators[1];
/* scale x/y back to device coordinates */
scr = miPointerGetScreen(pDev);
x = rescaleValuatorAxis(pDev->last.valuators[0], NULL,
pDev->valuator->axes + 0, scr->width);
y = rescaleValuatorAxis(pDev->last.valuators[1], NULL,
pDev->valuator->axes + 1, scr->height);
updateMotionHistory(pDev, ms, first_valuator, num_valuators,
&pDev->last.valuators[first_valuator]);
if (master)
updateMotionHistory(master, ms, first_valuator, num_valuators,
&pDev->last.valuators[first_valuator]);
/* Update the valuators with the true value sent to the client*/
if(v0) *v0 = x;
if(v1) *v1 = y;
/* dropy x/y (device coordinates) back into valuators for next event */
pDev->last.valuators[0] = x;
pDev->last.valuators[1] = y;
kbp = (deviceKeyButtonPointer *) events->event;
kbp->time = ms;
kbp->deviceid = pDev->id;
if (type == MotionNotify) {
kbp->type = DeviceMotionNotify;
}
else {
if (type == ButtonPress)
kbp->type = DeviceButtonPress;
else if (type == ButtonRelease)
kbp->type = DeviceButtonRelease;
kbp->detail = buttons;
}
kbp->root_x = cx; /* root_x/y always in screen coords */
kbp->root_y = cy;
events++;
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
if (flags & POINTER_ABSOLUTE)
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return num_events;
}
/**
* Post ProximityIn/ProximityOut events, accompanied by valuators.
*
* 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 GetMaximumEventsNum(), and for freeing it.
*/
_X_EXPORT int
GetProximityEvents(EventList *events, DeviceIntPtr pDev, int type,
int first_valuator, int num_valuators, int *valuators)
{
int num_events = 1;
deviceKeyButtonPointer *kbp;
DeviceIntPtr master;
/* Sanity checks. */
if (type != ProximityIn && type != ProximityOut)
return 0;
if (!pDev->valuator)
return 0;
/* Do we need to send a DeviceValuator event? */
if ((pDev->valuator->mode & 1) == Relative)
num_valuators = 0;
if (num_valuators) {
if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS * 6;
num_events += ((num_valuators - 1) / 6) + 1;
}
/* You fail. */
if (first_valuator < 0 ||
(num_valuators + first_valuator) > pDev->valuator->numAxes)
return 0;
master = pDev->u.master;
if (master && master->u.lastSlave != pDev)
{
CreateClassesChangedEvent(events, master, pDev);
updateSlaveDeviceCoords(master, pDev);
master->u.lastSlave = pDev;
master->last.numValuators = pDev->last.numValuators;
num_events++;
events++;
}
kbp = (deviceKeyButtonPointer *) events->event;
kbp->type = type;
kbp->deviceid = pDev->id;
kbp->detail = 0;
kbp->time = GetTimeInMillis();
if (num_valuators) {
kbp->deviceid |= MORE_EVENTS;
events++;
clipValuators(pDev, first_valuator, num_valuators, valuators);
events = getValuatorEvents(events, pDev, first_valuator,
num_valuators, valuators);
}
return num_events;
}
/**
* Note that pDev was the last function to send a core pointer event.
* Currently a no-op.
*
* Call this just before processInputProc.
*/
_X_EXPORT void
SwitchCorePointer(DeviceIntPtr pDev)
{
if (pDev != dixLookupPrivate(&inputInfo.pointer->devPrivates,
CoreDevicePrivateKey))
dixSetPrivate(&inputInfo.pointer->devPrivates,
CoreDevicePrivateKey, pDev);
}
/**
* 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)
{
xEvent xE;
#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 += panoramiXdataPtr[0].x - panoramiXdataPtr[screen].x;
y += panoramiXdataPtr[0].y - panoramiXdataPtr[screen].y;
}
#endif
memset(&xE, 0, sizeof(xEvent));
xE.u.u.type = MotionNotify;
xE.u.keyButtonPointer.rootX = x;
xE.u.keyButtonPointer.rootY = y;
xE.u.keyButtonPointer.time = time;
(*pDev->public.processInputProc)(&xE, pDev, 1);
}