/* * 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 */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include #define NEED_EVENTS #define NEED_REPLIES #include #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 #include extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies); #endif #ifdef PANORAMIX #include "panoramiX.h" #include "panoramiXsrv.h" #endif #include #include #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 */ CARD32 *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 = *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 (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++) { 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. */ /* This method require at least valuator 0&1 defined on the InputDevice */ if (!pDev->valuator || pDev->valuator->numAxes < 2) 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 = pDev->button->map[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); }