xenocara/xserver/dix/getevents.c

932 lines
30 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"
/* 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
/**
* 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)));
}
/**
* Allocate the motion history buffer.
*/
_X_EXPORT void
AllocateMotionHistory(DeviceIntPtr pDev)
{
if (pDev->valuator->motion)
xfree(pDev->valuator->motion);
if (pDev->valuator->numMotionEvents < 1)
return;
pDev->valuator->motion = xalloc(((sizeof(INT32) * pDev->valuator->numAxes) +
sizeof(Time)) *
pDev->valuator->numMotionEvents);
pDev->valuator->first_motion = 0;
pDev->valuator->last_motion = 0;
}
/**
* 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.
*/
_X_EXPORT int
GetMotionHistory(DeviceIntPtr pDev, xTimecoord *buff, unsigned long start,
unsigned long stop, ScreenPtr pScreen)
{
char *ibuff = NULL, *obuff = (char *) buff;
int i = 0, ret = 0;
Time current;
/* The size of a single motion event. */
int size = (sizeof(INT32) * pDev->valuator->numAxes) + sizeof(Time);
if (!pDev->valuator || !pDev->valuator->numMotionEvents)
return 0;
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) {
memcpy(obuff, ibuff, size);
obuff += size;
ret++;
}
}
return ret;
}
/**
* Update the motion history for a specific device, with the list of
* valuators.
*/
static void
updateMotionHistory(DeviceIntPtr pDev, CARD32 ms, int first_valuator,
int num_valuators, int *valuators)
{
char *buff = (char *) pDev->valuator->motion;
if (!pDev->valuator->numMotionEvents)
return;
buff += ((sizeof(INT32) * pDev->valuator->numAxes) + sizeof(CARD32)) *
pDev->valuator->last_motion;
memcpy(buff, &ms, sizeof(Time));
buff += sizeof(Time);
bzero(buff, 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());
*/
_X_EXPORT int
GetMaximumEventsNum(void) {
/* Two base events -- core and device, plus valuator events. Multiply
* by two if we're doing key repeats. */
int ret = 2 + 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 axes = pDev->valuator->axes + axisNum;
/* No clipping if the value-range <= 0 */
if(axes->min_value < axes->min_value) {
if (*val < axes->min_value)
*val = axes->min_value;
if (*val > axes->max_value)
*val = axes->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 xEvent *
getValuatorEvents(xEvent *events, DeviceIntPtr pDev, int first_valuator,
int num_valuators, int *valuators) {
deviceValuator *xv = (deviceValuator *) events;
int i = 0, final_valuator = first_valuator + num_valuators;
for (i = first_valuator; i < final_valuator; i += 6, xv++, events++) {
xv->type = DeviceValuator;
xv->first_valuator = i;
xv->num_valuators = ((final_valuator - i) > 6) ? 6 : (final_valuator - i);
xv->deviceid = pDev->id;
switch (final_valuator - 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];
}
if (i + 6 < final_valuator)
xv->deviceid |= MORE_EVENTS;
}
return events;
}
/**
* Convenience wrapper around GetKeyboardValuatorEvents, that takes no
* valuators.
*/
_X_EXPORT int
GetKeyboardEvents(xEvent *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.
*
* 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(xEvent *events, DeviceIntPtr pDev, int type,
int key_code, int first_valuator,
int num_valuators, int *valuators) {
int numEvents = 0;
CARD32 ms = 0;
KeySym *map = pDev->key->curKeySyms.map;
KeySym sym = map[key_code * pDev->key->curKeySyms.mapWidth];
deviceKeyButtonPointer *kbp = NULL;
if (!events)
return 0;
/* DO NOT WANT */
if (type != KeyPress && type != KeyRelease)
return 0;
if (!pDev->key || !pDev->focus || !pDev->kbdfeed ||
(pDev->coreEvents && !inputInfo.keyboard->key))
return 0;
if (key_code < 8 || key_code > 255)
return 0;
if (pDev->coreEvents)
numEvents = 2;
else
numEvents = 1;
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();
if (pDev->coreEvents) {
events->u.keyButtonPointer.time = ms;
events->u.u.type = type;
events->u.u.detail = key_code;
if (type == KeyPress)
set_key_down(inputInfo.keyboard, key_code);
else if (type == KeyRelease)
set_key_up(inputInfo.keyboard, key_code);
events++;
}
kbp = (deviceKeyButtonPointer *) events;
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;
}
/**
* Generate a series of xEvents (returned in xE) representing pointer
* motion, or button presses. Xi and XKB-aware.
*
* 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
GetPointerEvents(xEvent *events, DeviceIntPtr pDev, int type, int buttons,
int flags, int first_valuator, int num_valuators,
int *valuators) {
int num_events = 0, final_valuator = 0;
CARD32 ms = 0;
deviceKeyButtonPointer *kbp = NULL;
DeviceIntPtr cp = inputInfo.pointer;
int x = 0, y = 0;
Bool coreOnly = (pDev == inputInfo.pointer);
ScreenPtr scr = miPointerGetScreen(pDev);
/* Sanity checks. */
if (type != MotionNotify && type != ButtonPress && type != ButtonRelease)
return 0;
if ((type == ButtonPress || type == ButtonRelease) && !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 (!coreOnly && pDev->coreEvents)
num_events = 2;
else
num_events = 1;
if (type == MotionNotify && num_valuators <= 0)
return 0;
/* Do we need to send a DeviceValuator event? */
if (!coreOnly && num_valuators) {
if ((((num_valuators - 1) / 6) + 1) > MAX_VALUATOR_EVENTS)
num_valuators = MAX_VALUATOR_EVENTS * 6;
num_events += ((num_valuators - 1) / 6) + 1;
}
final_valuator = num_valuators + first_valuator;
/* You fail. */
if (first_valuator < 0 || final_valuator > pDev->valuator->numAxes)
return 0;
ms = GetTimeInMillis();
/* Set x and y based on whether this is absolute or relative, and
* accelerate if we need to. */
if (flags & POINTER_ABSOLUTE) {
if (num_valuators >= 1 && first_valuator == 0) {
x = valuators[0];
}
else {
/* If we're sending core events but didn't provide a value,
* translate the core value (but use the device coord if
* it translates to the same coord to preserve sub-pixel
* coord information). If we're not sending core events use
* whatever value we have */
x = pDev->valuator->lastx;
if(pDev->coreEvents) {
int min = pDev->valuator->axes[0].min_value;
int max = pDev->valuator->axes[0].max_value;
if(min < max) {
if((int)((float)(x-min)*scr->width/(max-min+1)) != cp->valuator->lastx)
x = (int)((float)(cp->valuator->lastx)*(max-min+1)/scr->width)+min;
}
else
x = cp->valuator->lastx;
}
}
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
y = valuators[1 - first_valuator];
}
else {
y = pDev->valuator->lasty;
if(pDev->coreEvents) {
int min = pDev->valuator->axes[1].min_value;
int max = pDev->valuator->axes[1].max_value;
if(min < max) {
if((int)((float)(y-min)*scr->height/(max-min+1)) != cp->valuator->lasty)
y = (int)((float)(cp->valuator->lasty)*(max-min+1)/scr->height)+min;
}
else
y = cp->valuator->lasty;
}
}
/* Clip both x and y to the defined limits (usually co-ord space limit). */
clipAxis(pDev, 0, &x);
clipAxis(pDev, 1, &y);
}
else {
if (flags & POINTER_ACCELERATE)
acceleratePointer(pDev, first_valuator, num_valuators,
valuators);
if (pDev->coreEvents) {
/* Get and convert the core pointer coordinate space into
* device coordinates. Use the device coords if it translates
* into the same position as the core to preserve relative sub-
* pixel movements from the device. */
int min = pDev->valuator->axes[0].min_value;
int max = pDev->valuator->axes[0].max_value;
if(min < max) {
x = pDev->valuator->lastx;
if((int)((float)(x-min)*scr->width/(max-min+1)) != cp->valuator->lastx)
x = (int)((float)(cp->valuator->lastx)*(max-min+1)/scr->width)+min;
}
else
x = cp->valuator->lastx;
min = pDev->valuator->axes[1].min_value;
max = pDev->valuator->axes[1].max_value;
if(min < max) {
y = pDev->valuator->lasty;
if((int)((float)(y-min)*scr->height/(max-min+1)) != cp->valuator->lasty)
y = (int)((float)(cp->valuator->lasty)*(max-min+1)/scr->height)+min;
}
else
y = cp->valuator->lasty;
/* Add relative movement */
if (first_valuator == 0 && num_valuators >= 1)
x += valuators[0];
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
y += valuators[1 - first_valuator];
}
else {
x = pDev->valuator->lastx;
y = pDev->valuator->lasty;
if (first_valuator == 0 && num_valuators >= 1)
x += valuators[0];
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
y += valuators[1 - first_valuator];
if(!coreOnly) {
/* Since we're not sending core-events we must clip both x and y
* to the defined limits so we don't run outside the box. */
clipAxis(pDev, 0, &x);
clipAxis(pDev, 1, &y);
}
}
}
pDev->valuator->lastx = x;
pDev->valuator->lasty = y;
/* Convert the dev coord back to screen coord if we're
* sending core events */
if (pDev->coreEvents) {
int min = pDev->valuator->axes[0].min_value;
int max = pDev->valuator->axes[0].max_value;
if(min < max)
x = (int)((float)(x-min)*scr->width/(max-min+1));
cp->valuator->lastx = x;
min = pDev->valuator->axes[1].min_value;
max = pDev->valuator->axes[1].max_value;
if(min < max)
y = (int)((float)(y-min)*scr->height/(max-min+1));
cp->valuator->lasty = y;
}
/* 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, &x, &y, ms);
if (pDev->coreEvents) {
/* miPointerSetPosition may have changed screen */
scr = miPointerGetScreen(pDev);
if(x != cp->valuator->lastx) {
int min = pDev->valuator->axes[0].min_value;
int max = pDev->valuator->axes[0].max_value;
cp->valuator->lastx = pDev->valuator->lastx = x;
if(min < max)
pDev->valuator->lastx = (int)((float)(x)*(max-min+1)/scr->width)+min;
}
if(y != cp->valuator->lasty) {
int min = pDev->valuator->axes[1].min_value;
int max = pDev->valuator->axes[1].max_value;
cp->valuator->lasty = pDev->valuator->lasty = y;
if(min < max)
pDev->valuator->lasty = (int)((float)(y)*(max-min+1)/scr->height)+min;
}
}
else if (coreOnly) {
cp->valuator->lastx = x;
cp->valuator->lasty = y;
}
/* Drop x and y back into the valuators list, if they were originally
* present. */
if (first_valuator == 0 && num_valuators >= 1)
valuators[0] = pDev->valuator->lastx;
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
valuators[1 - first_valuator] = pDev->valuator->lasty;
updateMotionHistory(pDev, ms, first_valuator, num_valuators, valuators);
/* for some reason inputInfo.pointer does not have coreEvents set */
if (coreOnly || pDev->coreEvents) {
events->u.u.type = type;
events->u.keyButtonPointer.time = ms;
events->u.keyButtonPointer.rootX = x;
events->u.keyButtonPointer.rootY = y;
if (type == ButtonPress || type == ButtonRelease) {
/* We hijack SetPointerMapping to work on all core-sending
* devices, so we use the device-specific map here instead of
* the core one. */
events->u.u.detail = pDev->button->map[buttons];
}
else {
events->u.u.detail = 0;
}
events++;
}
if (!coreOnly) {
kbp = (deviceKeyButtonPointer *) events;
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 = pDev->valuator->lastx;
kbp->root_y = pDev->valuator->lasty;
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 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(xEvent *events, DeviceIntPtr pDev, int type,
int first_valuator, int num_valuators, int *valuators)
{
int num_events = 1;
deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer *) events;
/* 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;
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 device to send a core event. This function
* copies the complete keymap from the originating device to the core
* device, and makes sure the appropriate notifications are generated.
*
* Call this just before processInputProc.
*/
_X_EXPORT void
SwitchCoreKeyboard(DeviceIntPtr pDev)
{
KeyClassPtr ckeyc = inputInfo.keyboard->key;
int i = 0;
if (inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr != pDev) {
memcpy(ckeyc->modifierMap, pDev->key->modifierMap, MAP_LENGTH);
if (ckeyc->modifierKeyMap)
xfree(ckeyc->modifierKeyMap);
ckeyc->modifierKeyMap = xalloc(8 * pDev->key->maxKeysPerModifier);
memcpy(ckeyc->modifierKeyMap, pDev->key->modifierKeyMap,
(8 * pDev->key->maxKeysPerModifier));
ckeyc->maxKeysPerModifier = pDev->key->maxKeysPerModifier;
ckeyc->curKeySyms.minKeyCode = pDev->key->curKeySyms.minKeyCode;
ckeyc->curKeySyms.maxKeyCode = pDev->key->curKeySyms.maxKeyCode;
SetKeySymsMap(&ckeyc->curKeySyms, &pDev->key->curKeySyms);
/*
* Copy state from the extended keyboard to core. If you omit this,
* holding Ctrl on keyboard one, and pressing Q on keyboard two, will
* cause your app to quit. This feels wrong to me, hence the below
* code.
*
* XXX: If you synthesise core modifier events, the state will get
* clobbered here. You'll have to work out something sensible
* to fix that. Good luck.
*/
#define KEYBOARD_MASK (ShiftMask | LockMask | ControlMask | Mod1Mask | \
Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)
ckeyc->state &= ~(KEYBOARD_MASK);
ckeyc->state |= (pDev->key->state & KEYBOARD_MASK);
#undef KEYBOARD_MASK
for (i = 0; i < 8; i++)
ckeyc->modifierKeyCount[i] = pDev->key->modifierKeyCount[i];
#ifdef XKB
if (!noXkbExtension && pDev->key->xkbInfo && pDev->key->xkbInfo->desc) {
if (!XkbCopyKeymap(pDev->key->xkbInfo->desc, ckeyc->xkbInfo->desc,
True))
FatalError("Couldn't pivot keymap from device to core!\n");
}
#endif
SendMappingNotify(MappingKeyboard, ckeyc->curKeySyms.minKeyCode,
(ckeyc->curKeySyms.maxKeyCode -
ckeyc->curKeySyms.minKeyCode),
serverClient);
inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr = pDev;
}
}
/**
* 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 (inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr != pDev)
inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr = 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(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;
(*inputInfo.pointer->public.processInputProc)(&xE, inputInfo.pointer, 1);
}