diff options
author | Daniel Stone <daniel@fooishbar.org> | 2006-10-14 22:14:07 +0300 |
---|---|---|
committer | Daniel Stone <daniels@endtroducing.fooishbar.org> | 2006-10-14 22:14:07 +0300 |
commit | 4d8030076ed1a7680bdfcb7b89af1045bdc40304 (patch) | |
tree | a96f5ce2b00f11956788eed1b0d96ee276c3d359 /dix/getevents.c | |
parent | 6afc7c284690b1e2bb7544b5bc4f31a3f6a05519 (diff) |
dix: move GetKeyboardEvents/GetPointerEvents to a new file, export symbols
Move GKE and GPE to a separate file, to help stem the events.c explosion.
Mark GKE/GKVE/GPE as _X_EXPORT.
Diffstat (limited to 'dix/getevents.c')
-rw-r--r-- | dix/getevents.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/dix/getevents.c b/dix/getevents.c new file mode 100644 index 000000000..4f9608053 --- /dev/null +++ b/dix/getevents.c @@ -0,0 +1,530 @@ +/* + * Copyright © 2006 Nokia Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that this copyright notice and this permission notice appear in + * supporting electronic documentation. + * + * The above copyright notice and this permission notice 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 COPYRIGHT HOLDERS OR AUTHORS 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> +#include "misc.h" +#include "resource.h" +#define NEED_EVENTS +#define NEED_REPLIES +#include <X11/Xproto.h> +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" + +#include "dixstruct.h" +#include "globals.h" + +#include "mipointer.h" + +#ifdef XKB +#include <X11/extensions/XKBproto.h> +#include <X11/extensions/XKBsrv.h> +extern Bool XkbFilterEvents(ClientPtr, int, xEvent *); +extern Bool XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies); +#endif + +#ifdef XACE +#include "xace.h" +#endif + +#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. */ +#define MAX_VALUATOR_EVENTS 6 + +/** + * 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() { + /* 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; +} + +/** + * 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. + * + * If pDev is set to send core events, then the keymap on the core + * keyboard will be pivoted to that of the new keyboard and the appropriate + * MapNotify events (both core and XKB) will be sent. + * + * 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, ms = 0, i = 0; + int final_valuator = first_valuator + num_valuators; + KeySym sym = pDev->key->curKeySyms.map[key_code * + pDev->key->curKeySyms.mapWidth]; + deviceKeyButtonPointer *kbp = NULL; + deviceValuator *xv = NULL; + KeyClassPtr ckeyc; + + if (!events) + return 0; + + if (type != KeyPress && type != KeyRelease) + return 0; + + if (!pDev->key || !pDev->focus || !pDev->kbdfeed || + (pDev->coreEvents && !inputInfo.keyboard->key)) + 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 && + (pDev->key->down[key_code >> 3] & (key_code & 7)) & 1) + type = KeyRelease; + } + } + + /* Handle core repeating, via press/release/press/release. + * FIXME: In theory, if you're repeating with two keyboards, + * you could get unbalanced events here. */ + if (type == KeyPress && + (((pDev->key->down[key_code >> 3] & (key_code & 7))) & 1)) { + if (!pDev->kbdfeed->ctrl.autoRepeat || + pDev->key->modifierMap[key_code] || + !(pDev->kbdfeed->ctrl.autoRepeats[key_code >> 3] + & (1 << (key_code & 7)))) + 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; + kbp->time = ms; + kbp->deviceid = pDev->id; + if (type == KeyPress) + kbp->type = DeviceKeyPress; + else if (type == KeyRelease) + kbp->type = DeviceKeyRelease; + + if (num_valuators) { + kbp->deviceid |= MORE_EVENTS; + for (i = first_valuator; i < final_valuator; i += 6) { + xv = (deviceValuator *) ++events; + xv->type = DeviceValuator; + xv->first_valuator = i; + xv->num_valuators = num_valuators; + xv->deviceid = kbp->deviceid; + switch (num_valuators - first_valuator) { + 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 (pDev->coreEvents) { + events++; + events->u.keyButtonPointer.time = ms; + events->u.u.type = type; + events->u.u.detail = key_code; + + if (inputInfo.keyboard->devPrivates[CoreDevicePrivatesIndex].ptr != + pDev) { + ckeyc = inputInfo.keyboard->key; + 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); +#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; + } + } + + return numEvents; +} + +/* Originally a part of xf86PostMotionEvent. */ +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; + + /* + * Accelerate + */ + 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 * dx + dy * 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); + } + } + } +} + +/** + * 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, ms = 0, final_valuator = 0, i = 0; + deviceKeyButtonPointer *kbp = NULL; + deviceValuator *xv = NULL; + AxisInfoPtr axes = NULL; + Bool sendValuators = (type == MotionNotify || flags & POINTER_ABSOLUTE); + DeviceIntPtr cp = inputInfo.pointer; + int x = 0, y = 0; + + if (type != MotionNotify && type != ButtonPress && type != ButtonRelease) + return 0; + + if (!pDev->button || (pDev->coreEvents && (!cp->button || !cp->valuator))) + return 0; + + /* You fail. */ + if (first_valuator < 0) + return 0; + + if (pDev->coreEvents) + num_events = 2; + else + num_events = 1; + + /* Do we need to send a DeviceValuator event? */ + if ((num_valuators + first_valuator) >= 2 && sendValuators) { + if (((num_valuators / 6) + 1) > MAX_VALUATOR_EVENTS) + num_valuators = MAX_VALUATOR_EVENTS; + num_events += (num_valuators / 6) + 1; + } + else if (type == MotionNotify && num_valuators <= 0) { + return 0; + } + + final_valuator = num_valuators + first_valuator; + + ms = GetTimeInMillis(); + + kbp = (deviceKeyButtonPointer *) events; + kbp->time = ms; + kbp->deviceid = pDev->id; + + 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) + x = 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; + } + } + + + axes = pDev->valuator->axes; + if (x < axes->min_value) + x = axes->min_value; + if (axes->max_value > 0 && x > axes->max_value) + x = axes->max_value; + + axes++; + if (y < axes->min_value) + y = axes->min_value; + if (axes->max_value > 0 && y > axes->max_value) + y = axes->max_value; + + /* 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) { + cp->valuator->lastx = x; + cp->valuator->lasty = y; + } + pDev->valuator->lastx = x; + pDev->valuator->lasty = y; + + 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; + + if (final_valuator > 2 && sendValuators) { + kbp->deviceid |= MORE_EVENTS; + for (i = first_valuator; i < final_valuator; i += 6) { + xv = (deviceValuator *) ++events; + xv->type = DeviceValuator; + xv->first_valuator = i; + xv->num_valuators = num_valuators; + xv->deviceid = kbp->deviceid; + 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: + /* x and y may have been accelerated. */ + if (i == 0) + xv->valuator1 = kbp->root_y; + else + xv->valuator1 = valuators[i+1]; + case 1: + /* x and y may have been accelerated. */ + if (i == 0) + xv->valuator0 = kbp->root_x; + else + xv->valuator0 = valuators[i]; + } + } + } + + if (pDev->coreEvents) { + events++; + 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; + } + + if (inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr != + pDev) + inputInfo.pointer->devPrivates[CoreDevicePrivatesIndex].ptr = pDev; + } + + return num_events; +} |