XQuartz was crashing because the Appkit thread was trying to GetXXXEvents while the Xserver thread was exiting. This adds some more sanity checks and avoids that crash
861 lines
27 KiB
C
861 lines
27 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(¤t, 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;
|
|
|
|
if (*val < axes->min_value)
|
|
*val = axes->min_value;
|
|
if (axes->max_value >= 0 && *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 = ((num_valuators - i) > 6) ? 6 : (num_valuators - 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;
|
|
KeySym sym;
|
|
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 && inputInfo.keyboard->key)))
|
|
return 0;
|
|
|
|
if (key_code < 8 || key_code > 255)
|
|
return 0;
|
|
|
|
map = pDev->key->curKeySyms.map;
|
|
sym = map[key_code * pDev->key->curKeySyms.mapWidth];
|
|
|
|
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;
|
|
/* Thanks to a broken lib, we _always_ have to chase DeviceMotionNotifies
|
|
* with DeviceValuators. */
|
|
Bool sendValuators = (type == MotionNotify || flags & POINTER_ABSOLUTE);
|
|
DeviceIntPtr cp = inputInfo.pointer;
|
|
int x = 0, y = 0;
|
|
Bool coreOnly = (pDev == inputInfo.pointer);
|
|
|
|
/* Sanity checks. */
|
|
if (type != MotionNotify && type != ButtonPress && type != ButtonRelease)
|
|
return 0;
|
|
|
|
if ((type == ButtonPress || type == ButtonRelease) && !pDev->button)
|
|
return 0;
|
|
|
|
if(pDev->coreEvents && !cp)
|
|
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 && sendValuators) {
|
|
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 (pDev->coreEvents)
|
|
x = cp->valuator->lastx;
|
|
else
|
|
x = pDev->valuator->lastx;
|
|
}
|
|
|
|
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator)) {
|
|
y = valuators[1 - first_valuator];
|
|
}
|
|
else {
|
|
if (pDev->coreEvents)
|
|
y = cp->valuator->lasty;
|
|
else
|
|
y = pDev->valuator->lasty;
|
|
}
|
|
}
|
|
else {
|
|
if (flags & POINTER_ACCELERATE)
|
|
acceleratePointer(pDev, first_valuator, num_valuators,
|
|
valuators);
|
|
|
|
if (pDev->coreEvents) {
|
|
if (first_valuator == 0 && num_valuators >= 1)
|
|
x = cp->valuator->lastx + valuators[0];
|
|
else
|
|
x = cp->valuator->lastx;
|
|
|
|
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
|
|
y = cp->valuator->lasty + valuators[1 - first_valuator];
|
|
else
|
|
y = cp->valuator->lasty;
|
|
}
|
|
else {
|
|
if (first_valuator == 0 && num_valuators >= 1)
|
|
x = pDev->valuator->lastx + valuators[0];
|
|
else
|
|
x = pDev->valuator->lastx;
|
|
|
|
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
|
|
y = pDev->valuator->lasty + valuators[1 - first_valuator];
|
|
else
|
|
y = pDev->valuator->lasty;
|
|
}
|
|
}
|
|
|
|
/* Clip both x and y to the defined limits (usually co-ord space limit). */
|
|
clipAxis(pDev, 0, &x);
|
|
clipAxis(pDev, 1, &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);
|
|
|
|
/* Drop x and y back into the valuators list, if they were originally
|
|
* present. */
|
|
if (first_valuator == 0 && num_valuators >= 1)
|
|
valuators[0] = x;
|
|
if (first_valuator <= 1 && num_valuators >= (2 - first_valuator))
|
|
valuators[1 - first_valuator] = y;
|
|
|
|
updateMotionHistory(pDev, ms, first_valuator, num_valuators, valuators);
|
|
|
|
if (pDev->coreEvents) {
|
|
cp->valuator->lastx = x;
|
|
cp->valuator->lasty = y;
|
|
}
|
|
pDev->valuator->lastx = x;
|
|
pDev->valuator->lasty = y;
|
|
|
|
/* 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 = x;
|
|
kbp->root_y = y;
|
|
|
|
events++;
|
|
if (sendValuators) {
|
|
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);
|
|
}
|