diff options
Diffstat (limited to 'xorg-server/dix/devices.c')
-rw-r--r-- | xorg-server/dix/devices.c | 2114 |
1 files changed, 2114 insertions, 0 deletions
diff --git a/xorg-server/dix/devices.c b/xorg-server/dix/devices.c new file mode 100644 index 000000000..5a726afe8 --- /dev/null +++ b/xorg-server/dix/devices.c @@ -0,0 +1,2114 @@ +/************************************************************ + +Copyright 1987, 1998 The Open Group + +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 +copyright notice and this permission notice appear in supporting +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 +OPEN GROUP 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. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + +Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +********************************************************/ + + + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <X11/X.h> +#include "misc.h" +#include "resource.h" +#define NEED_EVENTS +#define NEED_REPLIES +#include <X11/Xproto.h> +#include "windowstr.h" +#include "inputstr.h" +#include "scrnintstr.h" +#include "cursorstr.h" +#include "dixstruct.h" +#include "site.h" +#ifndef XKB_IN_SERVER +#define XKB_IN_SERVER +#endif +#ifdef XKB +#include <xkbsrv.h> +#endif +#include "privates.h" +#include "xace.h" + +#include "dispatch.h" +#include "swaprep.h" +#include "dixevents.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "exglobals.h" +#include "exevents.h" + +/** @file + * This file handles input device-related stuff. + */ + +DevPrivateKey CoreDevicePrivateKey = &CoreDevicePrivateKey; + +/** + * Create a new input device and init it to sane values. The device is added + * to the server's off_devices list. + * + * @param deviceProc Callback for device control function (switch dev on/off). + * @return The newly created device. + */ +DeviceIntPtr +AddInputDevice(DeviceProc deviceProc, Bool autoStart) +{ + DeviceIntPtr dev, *prev; /* not a typo */ + DeviceIntPtr devtmp; + int devid; + char devind[MAX_DEVICES]; + + /* Find next available id */ + memset(devind, 0, sizeof(char)*MAX_DEVICES); + for (devtmp = inputInfo.devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devtmp = inputInfo.off_devices; devtmp; devtmp = devtmp->next) + devind[devtmp->id]++; + for (devid = 0; devid < MAX_DEVICES && devind[devid]; devid++) + ; + + if (devid >= MAX_DEVICES) + return (DeviceIntPtr)NULL; + dev = (DeviceIntPtr) xcalloc(sizeof(DeviceIntRec), 1); + if (!dev) + return (DeviceIntPtr)NULL; + dev->name = (char *)NULL; + dev->type = 0; + dev->id = devid; + dev->public.on = FALSE; + dev->public.processInputProc = (ProcessInputProc)NoopDDA; + dev->public.realInputProc = (ProcessInputProc)NoopDDA; + dev->public.enqueueInputProc = EnqueueEvent; + dev->deviceProc = deviceProc; + dev->startup = autoStart; + dev->sync.frozen = FALSE; + dev->sync.other = NullGrab; + dev->sync.state = NOT_GRABBED; + dev->sync.event = (xEvent *) NULL; + dev->sync.evcount = 0; + dev->grab = NullGrab; + dev->grabTime = currentTime; + dev->fromPassiveGrab = FALSE; + dev->key = (KeyClassPtr)NULL; + dev->valuator = (ValuatorClassPtr)NULL; + dev->button = (ButtonClassPtr)NULL; + dev->focus = (FocusClassPtr)NULL; + dev->proximity = (ProximityClassPtr)NULL; + dev->absolute = (AbsoluteClassPtr)NULL; + dev->kbdfeed = (KbdFeedbackPtr)NULL; + dev->ptrfeed = (PtrFeedbackPtr)NULL; + dev->intfeed = (IntegerFeedbackPtr)NULL; + dev->stringfeed = (StringFeedbackPtr)NULL; + dev->bell = (BellFeedbackPtr)NULL; + dev->leds = (LedFeedbackPtr)NULL; +#ifdef XKB + dev->xkb_interest = NULL; +#endif + dev->config_info = NULL; + dev->devPrivates = NULL; + dev->unwrapProc = NULL; + dev->coreEvents = TRUE; + dev->inited = FALSE; + dev->enabled = FALSE; + + /* security creation/labeling check + */ + if (XaceHook(XACE_DEVICE_ACCESS, serverClient, dev, DixCreateAccess)) { + xfree(dev); + return NULL; + } + + inputInfo.numDevices++; + + for (prev = &inputInfo.off_devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + return dev; +} + +/** + * Switch device ON through the driver and push it onto the global device + * list. All clients are notified about the device being enabled. + * + * A device will send events once enabled. + * + * @param The device to be enabled. + * @return TRUE on success or FALSE otherwise. + */ +Bool +EnableDevice(DeviceIntPtr dev) +{ + DeviceIntPtr *prev; + int ret; + DeviceIntRec dummyDev; + devicePresenceNotify ev; + + for (prev = &inputInfo.off_devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + if ((*prev != dev) || !dev->inited || + ((ret = (*dev->deviceProc)(dev, DEVICE_ON)) != Success)) { + ErrorF("couldn't enable device %d\n", dev->id); + return FALSE; + } + dev->enabled = TRUE; + *prev = dev->next; + + for (prev = &inputInfo.devices; *prev; prev = &(*prev)->next) + ; + *prev = dev; + dev->next = NULL; + + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = DeviceEnabled; + ev.deviceid = dev->id; + dummyDev.id = 0; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent *) &ev, 1); + + return TRUE; +} + +/** + * Switch a device off through the driver and push it onto the off_devices + * list. A device will not send events while disabled. All clients are + * notified about the device being disabled. + * + * @return TRUE on success or FALSE otherwise. + */ +Bool +DisableDevice(DeviceIntPtr dev) +{ + DeviceIntPtr *prev; + DeviceIntRec dummyDev; + devicePresenceNotify ev; + + for (prev = &inputInfo.devices; + *prev && (*prev != dev); + prev = &(*prev)->next) + ; + if (*prev != dev) + return FALSE; + (void)(*dev->deviceProc)(dev, DEVICE_OFF); + dev->enabled = FALSE; + *prev = dev->next; + dev->next = inputInfo.off_devices; + inputInfo.off_devices = dev; + + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = DeviceDisabled; + ev.deviceid = dev->id; + dummyDev.id = 0; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent *) &ev, 1); + + return TRUE; +} + +/** + * Initialise a new device through the driver and tell all clients about the + * new device. + * + * The device will NOT send events until it is enabled! + * + * @return Success or an error code on failure. + */ +int +ActivateDevice(DeviceIntPtr dev) +{ + int ret = Success; + devicePresenceNotify ev; + DeviceIntRec dummyDev; + + if (!dev || !dev->deviceProc) + return BadImplementation; + + ret = (*dev->deviceProc) (dev, DEVICE_INIT); + dev->inited = (ret == Success); + + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = DeviceAdded; + ev.deviceid = dev->id; + dummyDev.id = 0; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent *) &ev, 1); + + return ret; +} + +/** + * Ring the bell. + * The actual task of ringing the bell is the job of the DDX. + */ +static void +CoreKeyboardBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ + KeybdCtrl *ctrl = arg; + + DDXRingBell(volume, ctrl->bell_pitch, ctrl->bell_duration); +} + +static void +CoreKeyboardCtl(DeviceIntPtr pDev, KeybdCtrl *ctrl) +{ + return; +} + +/** + * Device control function for the Virtual Core Keyboard. + */ +static int +CoreKeyboardProc(DeviceIntPtr pDev, int what) +{ + CARD8 *modMap; + KeySymsRec keySyms; +#ifdef XKB + XkbComponentNamesRec names; +#endif + + switch (what) { + case DEVICE_INIT: + keySyms.minKeyCode = 8; + keySyms.maxKeyCode = 255; + keySyms.mapWidth = 4; + keySyms.map = (KeySym *)xcalloc(sizeof(KeySym), + (keySyms.maxKeyCode - + keySyms.minKeyCode + 1) * + keySyms.mapWidth); + if (!keySyms.map) { + ErrorF("Couldn't allocate core keymap\n"); + return BadAlloc; + } + + modMap = (CARD8 *)xalloc(MAP_LENGTH); + if (!modMap) { + ErrorF("Couldn't allocate core modifier map\n"); + return BadAlloc; + } + bzero((char *)modMap, MAP_LENGTH); + +#ifdef XKB + if (!noXkbExtension) { + bzero(&names, sizeof(names)); + XkbSetRulesDflts("base", "pc105", "us", NULL, NULL); + XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, modMap, + CoreKeyboardBell, CoreKeyboardCtl); + } + else +#endif + { + /* FIXME Our keymap here isn't exactly useful. */ + InitKeyboardDeviceStruct((DevicePtr)pDev, &keySyms, modMap, + CoreKeyboardBell, CoreKeyboardCtl); + } + + xfree(keySyms.map); + xfree(modMap); + + break; + + case DEVICE_CLOSE: + dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL); + break; + + default: + break; + } + return Success; +} + +/** + * Device control function for the Virtual Core Pointer. + */ +static int +CorePointerProc(DeviceIntPtr pDev, int what) +{ + BYTE map[33]; + int i = 0; + + switch (what) { + case DEVICE_INIT: + for (i = 1; i <= 32; i++) + map[i] = i; + InitPointerDeviceStruct((DevicePtr)pDev, map, 32, + GetMotionHistory, (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), 2); + pDev->valuator->axisVal[0] = screenInfo.screens[0]->width / 2; + pDev->valuator->lastx = pDev->valuator->axisVal[0]; + pDev->valuator->axisVal[1] = screenInfo.screens[0]->height / 2; + pDev->valuator->lasty = pDev->valuator->axisVal[1]; + break; + + case DEVICE_CLOSE: + dixSetPrivate(&pDev->devPrivates, CoreDevicePrivateKey, NULL); + break; + + default: + break; + } + + return Success; +} + +/** + * Initialise the two core devices, VCP and VCK (see events.c). + * The devices are activated but not enabled. + * Note that the server MUST have two core devices at all times, even if there + * is no physical device connected. + */ +void +InitCoreDevices(void) +{ + DeviceIntPtr dev; + + if (!inputInfo.keyboard) { + dev = AddInputDevice(CoreKeyboardProc, TRUE); + if (!dev) + FatalError("Failed to allocate core keyboard"); + dev->name = strdup("Virtual core keyboard"); +#ifdef XKB + dev->public.processInputProc = CoreProcessKeyboardEvent; + dev->public.realInputProc = CoreProcessKeyboardEvent; + if (!noXkbExtension) + XkbSetExtension(dev, ProcessKeyboardEvent); +#else + dev->public.processInputProc = ProcessKeyboardEvent; + dev->public.realInputProc = ProcessKeyboardEvent; +#endif + dev->ActivateGrab = ActivateKeyboardGrab; + dev->DeactivateGrab = DeactivateKeyboardGrab; + dev->coreEvents = FALSE; + (void)ActivateDevice(dev); + inputInfo.keyboard = dev; + } + + if (!inputInfo.pointer) { + dev = AddInputDevice(CorePointerProc, TRUE); + if (!dev) + FatalError("Failed to allocate core pointer"); + dev->name = strdup("Virtual core pointer"); +#ifdef XKB + dev->public.processInputProc = CoreProcessPointerEvent; + dev->public.realInputProc = CoreProcessPointerEvent; + if (!noXkbExtension) + XkbSetExtension(dev, ProcessPointerEvent); +#else + dev->public.processInputProc = ProcessPointerEvent; + dev->public.realInputProc = ProcessPointerEvent; +#endif + dev->ActivateGrab = ActivatePointerGrab; + dev->DeactivateGrab = DeactivatePointerGrab; + dev->coreEvents = FALSE; + (void)ActivateDevice(dev); + inputInfo.pointer = dev; + } +} + +/** + * Activate all switched-off devices and then enable all those devices. + * + * Will return an error if no core keyboard or core pointer is present. + * In theory this should never happen if you call InitCoreDevices() first. + * + * @return Success or error code on failure. + */ +int +InitAndStartDevices(void) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.off_devices; dev; dev = dev->next) { + DebugF("(dix) initialising device %d\n", dev->id); + if (!dev->inited) + ActivateDevice(dev); + } + for (dev = inputInfo.off_devices; dev; dev = next) + { + DebugF("(dix) enabling device %d\n", dev->id); + next = dev->next; + if (dev->inited && dev->startup) + (void)EnableDevice(dev); + } + for (dev = inputInfo.devices; + dev && (dev != inputInfo.keyboard); + dev = dev->next) + ; + if (!dev || (dev != inputInfo.keyboard)) { + ErrorF("No core keyboard\n"); + return BadImplementation; + } + for (dev = inputInfo.devices; + dev && (dev != inputInfo.pointer); + dev = dev->next) + ; + if (!dev || (dev != inputInfo.pointer)) { + ErrorF("No core pointer\n"); + return BadImplementation; + } + return Success; +} + +/** + * Close down a device and free all resources. + * Once closed down, the driver will probably not expect you that you'll ever + * enable it again and free associated structs. If you want the device to just + * be disabled, DisableDevice(). + * Don't call this function directly, use RemoveDevice() instead. + */ +static void +CloseDevice(DeviceIntPtr dev) +{ + KbdFeedbackPtr k, knext; + PtrFeedbackPtr p, pnext; + IntegerFeedbackPtr i, inext; + StringFeedbackPtr s, snext; + BellFeedbackPtr b, bnext; + LedFeedbackPtr l, lnext; + + if (dev->inited) + (void)(*dev->deviceProc)(dev, DEVICE_CLOSE); + + xfree(dev->name); + + if (dev->key) { +#ifdef XKB + if (dev->key->xkbInfo) + XkbFreeInfo(dev->key->xkbInfo); +#endif + dev->key->xkbInfo = NULL; + xfree(dev->key->curKeySyms.map); + xfree(dev->key->modifierKeyMap); + xfree(dev->key); + dev->key = NULL; + } + + if (dev->valuator) { + /* Counterpart to 'biggest hack ever' in init. */ + if (dev->valuator->motion && + dev->valuator->GetMotionProc == GetMotionHistory) + xfree(dev->valuator->motion); + xfree(dev->valuator); + } + + if (dev->button) { +#ifdef XKB + if (dev->button->xkb_acts) + xfree(dev->button->xkb_acts); +#endif + xfree(dev->button); + } + + if (dev->focus) { + xfree(dev->focus->trace); + xfree(dev->focus); + } + + if (dev->proximity) + xfree(dev->proximity); + + for (k = dev->kbdfeed; k; k = knext) { + knext = k->next; +#ifdef XKB + if (k->xkb_sli) + XkbFreeSrvLedInfo(k->xkb_sli); +#endif + xfree(k); + } + + for (p = dev->ptrfeed; p; p = pnext) { + pnext = p->next; + xfree(p); + } + + for (i = dev->intfeed; i; i = inext) { + inext = i->next; + xfree(i); + } + + for (s = dev->stringfeed; s; s = snext) { + snext = s->next; + xfree(s->ctrl.symbols_supported); + xfree(s->ctrl.symbols_displayed); + xfree(s); + } + + for (b = dev->bell; b; b = bnext) { + bnext = b->next; + xfree(b); + } + + for (l = dev->leds; l; l = lnext) { + lnext = l->next; +#ifdef XKB + if (l->xkb_sli) + XkbFreeSrvLedInfo(l->xkb_sli); +#endif + xfree(l); + } + +#ifdef XKB + while (dev->xkb_interest) + XkbRemoveResourceClient((DevicePtr)dev,dev->xkb_interest->resource); +#endif + + xfree(dev->sync.event); + dixFreePrivates(dev->devPrivates); + xfree(dev); +} + +/** + * Shut down all devices, free all resources, etc. + * Only useful if you're shutting down the server! + */ +void +CloseDownDevices(void) +{ + DeviceIntPtr dev, next; + + for (dev = inputInfo.devices; dev; dev = next) + { + next = dev->next; + DeleteInputDeviceRequest(dev); + } + for (dev = inputInfo.off_devices; dev; dev = next) + { + next = dev->next; + DeleteInputDeviceRequest(dev); + } + inputInfo.devices = NULL; + inputInfo.off_devices = NULL; + inputInfo.keyboard = NULL; + inputInfo.pointer = NULL; +} + +/** + * Remove a device from the device list, closes it and thus frees all + * resources. + * Removes both enabled and disabled devices and notifies all devices about + * the removal of the device. + */ +int +RemoveDevice(DeviceIntPtr dev) +{ + DeviceIntPtr prev,tmp,next; + int ret = BadMatch; + devicePresenceNotify ev; + DeviceIntRec dummyDev; + int deviceid; + + DebugF("(dix) removing device %d\n", dev->id); + + if (!dev || dev == inputInfo.keyboard || dev == inputInfo.pointer) + return BadImplementation; + + deviceid = dev->id; + DisableDevice(dev); + + prev = NULL; + for (tmp = inputInfo.devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + CloseDevice(tmp); + + if (prev==NULL) + inputInfo.devices = next; + else + prev->next = next; + + ret = Success; + } + } + + prev = NULL; + for (tmp = inputInfo.off_devices; tmp; (prev = tmp), (tmp = next)) { + next = tmp->next; + if (tmp == dev) { + CloseDevice(tmp); + + if (prev == NULL) + inputInfo.off_devices = next; + else + prev->next = next; + + ret = Success; + } + } + + if (ret == Success) { + inputInfo.numDevices--; + ev.type = DevicePresenceNotify; + ev.time = currentTime.milliseconds; + ev.devchange = DeviceRemoved; + ev.deviceid = deviceid; + dummyDev.id = 0; + SendEventToAllWindows(&dummyDev, DevicePresenceNotifyMask, + (xEvent *) &ev, 1); + } + + return ret; +} + +int +NumMotionEvents(void) +{ + return inputInfo.pointer->valuator->numMotionEvents; +} + +void +RegisterPointerDevice(DeviceIntPtr device) +{ + RegisterOtherDevice(device); +} + +void +RegisterKeyboardDevice(DeviceIntPtr device) +{ + RegisterOtherDevice(device); +} + +int +dixLookupDevice(DeviceIntPtr *pDev, int id, ClientPtr client, Mask access_mode) +{ + DeviceIntPtr dev; + int rc; + *pDev = NULL; + + for (dev=inputInfo.devices; dev; dev=dev->next) { + if (dev->id == (CARD8)id) + goto found; + } + for (dev=inputInfo.off_devices; dev; dev=dev->next) { + if (dev->id == (CARD8)id) + goto found; + } + return BadDevice; + +found: + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, access_mode); + if (rc == Success) + *pDev = dev; + return rc; +} + +void +QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode) +{ + if (inputInfo.keyboard) { + *minCode = inputInfo.keyboard->key->curKeySyms.minKeyCode; + *maxCode = inputInfo.keyboard->key->curKeySyms.maxKeyCode; + } +} + +Bool +SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) +{ + int i, j; + int rowDif = src->minKeyCode - dst->minKeyCode; + + /* if keysym map size changes, grow map first */ + if (src->mapWidth < dst->mapWidth) + { + for (i = src->minKeyCode; i <= src->maxKeyCode; i++) + { +#define SI(r, c) (((r-src->minKeyCode)*src->mapWidth) + (c)) +#define DI(r, c) (((r - dst->minKeyCode)*dst->mapWidth) + (c)) + for (j = 0; j < src->mapWidth; j++) + dst->map[DI(i, j)] = src->map[SI(i, j)]; + for (j = src->mapWidth; j < dst->mapWidth; j++) + dst->map[DI(i, j)] = NoSymbol; +#undef SI +#undef DI + } + return TRUE; + } + else if (src->mapWidth > dst->mapWidth) + { + KeySym *map; + int bytes = sizeof(KeySym) * src->mapWidth * + (dst->maxKeyCode - dst->minKeyCode + 1); + map = (KeySym *)xalloc(bytes); + if (!map) + return FALSE; + bzero((char *)map, bytes); + if (dst->map) + { + for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) + memmove((char *)&map[i*src->mapWidth], + (char *)&dst->map[i*dst->mapWidth], + dst->mapWidth * sizeof(KeySym)); + xfree(dst->map); + } + dst->mapWidth = src->mapWidth; + dst->map = map; + } + memmove((char *)&dst->map[rowDif * dst->mapWidth], + (char *)src->map, + (int)(src->maxKeyCode - src->minKeyCode + 1) * + dst->mapWidth * sizeof(KeySym)); + return TRUE; +} + +static Bool +InitModMap(KeyClassPtr keyc) +{ + int i, j; + CARD8 keysPerModifier[8]; + CARD8 mask; + + keyc->maxKeysPerModifier = 0; + for (i = 0; i < 8; i++) + keysPerModifier[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) + { + for (j = 0, mask = 1; j < 8; j++, mask <<= 1) + { + if (mask & keyc->modifierMap[i]) + { + if (++keysPerModifier[j] > keyc->maxKeysPerModifier) + keyc->maxKeysPerModifier = keysPerModifier[j]; + } + } + } + keyc->modifierKeyMap = (KeyCode *)xalloc(8*keyc->maxKeysPerModifier); + if (!keyc->modifierKeyMap && keyc->maxKeysPerModifier) + return (FALSE); + bzero((char *)keyc->modifierKeyMap, 8*(int)keyc->maxKeysPerModifier); + for (i = 0; i < 8; i++) + keysPerModifier[i] = 0; + for (i = 8; i < MAP_LENGTH; i++) + { + for (j = 0, mask = 1; j < 8; j++, mask <<= 1) + { + if (mask & keyc->modifierMap[i]) + { + keyc->modifierKeyMap[(j*keyc->maxKeysPerModifier) + + keysPerModifier[j]] = i; + keysPerModifier[j]++; + } + } + } + return TRUE; +} + +_X_EXPORT Bool +InitKeyClassDeviceStruct(DeviceIntPtr dev, KeySymsPtr pKeySyms, CARD8 pModifiers[]) +{ + int i; + KeyClassPtr keyc; + + keyc = (KeyClassPtr)xalloc(sizeof(KeyClassRec)); + if (!keyc) + return FALSE; + keyc->curKeySyms.map = (KeySym *)NULL; + keyc->curKeySyms.mapWidth = 0; + keyc->curKeySyms.minKeyCode = pKeySyms->minKeyCode; + keyc->curKeySyms.maxKeyCode = pKeySyms->maxKeyCode; + keyc->modifierKeyMap = (KeyCode *)NULL; + keyc->state = 0; + keyc->prev_state = 0; + if (pModifiers) + memmove((char *)keyc->modifierMap, (char *)pModifiers, MAP_LENGTH); + else + bzero((char *)keyc->modifierMap, MAP_LENGTH); + bzero((char *)keyc->down, DOWN_LENGTH); + bzero((char *)keyc->postdown, DOWN_LENGTH); + for (i = 0; i < 8; i++) + keyc->modifierKeyCount[i] = 0; + if (!SetKeySymsMap(&keyc->curKeySyms, pKeySyms) || !InitModMap(keyc)) + { + xfree(keyc->curKeySyms.map); + xfree(keyc->modifierKeyMap); + xfree(keyc); + return FALSE; + } + dev->key = keyc; +#ifdef XKB + dev->key->xkbInfo= NULL; + if (!noXkbExtension) XkbInitDevice(dev); +#endif + return TRUE; +} + +_X_EXPORT Bool +InitButtonClassDeviceStruct(DeviceIntPtr dev, int numButtons, + CARD8 *map) +{ + ButtonClassPtr butc; + int i; + + butc = (ButtonClassPtr)xalloc(sizeof(ButtonClassRec)); + if (!butc) + return FALSE; + butc->numButtons = numButtons; + for (i = 1; i <= numButtons; i++) + butc->map[i] = map[i]; + butc->buttonsDown = 0; + butc->state = 0; + butc->motionMask = 0; + bzero((char *)butc->down, DOWN_LENGTH); +#ifdef XKB + butc->xkb_acts= NULL; +#endif + dev->button = butc; + return TRUE; +} + +_X_EXPORT Bool +InitValuatorClassDeviceStruct(DeviceIntPtr dev, int numAxes, + ValuatorMotionProcPtr motionProc, + int numMotionEvents, int mode) +{ + int i; + ValuatorClassPtr valc; + + if (!dev) + return FALSE; + + valc = (ValuatorClassPtr)xalloc(sizeof(ValuatorClassRec) + + numAxes * sizeof(AxisInfo) + + numAxes * sizeof(unsigned int)); + if (!valc) + return FALSE; + + valc->motion = NULL; + valc->first_motion = 0; + valc->last_motion = 0; + valc->GetMotionProc = motionProc; + + valc->numMotionEvents = numMotionEvents; + valc->motionHintWindow = NullWindow; + valc->numAxes = numAxes; + valc->mode = mode; + valc->axes = (AxisInfoPtr)(valc + 1); + valc->axisVal = (int *)(valc->axes + numAxes); + valc->lastx = 0; + valc->lasty = 0; + valc->dxremaind = 0; + valc->dyremaind = 0; + dev->valuator = valc; + + /* biggest hack ever. */ + if (motionProc == GetMotionHistory) + AllocateMotionHistory(dev); + + for (i=0; i<numAxes; i++) { + InitValuatorAxisStruct(dev, i, 0, -1, 0, 0, 0); + valc->axisVal[i]=0; + } + return TRUE; +} + +_X_EXPORT Bool +InitAbsoluteClassDeviceStruct(DeviceIntPtr dev) +{ + AbsoluteClassPtr abs; + + abs = (AbsoluteClassPtr)xalloc(sizeof(AbsoluteClassRec)); + if (!abs) + return FALSE; + + /* we don't do anything sensible with these, but should */ + abs->min_x = -1; + abs->min_y = -1; + abs->max_x = -1; + abs->max_y = -1; + abs->flip_x = 0; + abs->flip_y = 0; + abs->rotation = 0; + abs->button_threshold = 0; + + abs->offset_x = 0; + abs->offset_y = 0; + abs->width = -1; + abs->height = -1; + abs->following = 0; + abs->screen = 0; + + dev->absolute = abs; + + return TRUE; +} + +_X_EXPORT Bool +InitFocusClassDeviceStruct(DeviceIntPtr dev) +{ + FocusClassPtr focc; + + focc = (FocusClassPtr)xalloc(sizeof(FocusClassRec)); + if (!focc) + return FALSE; + focc->win = PointerRootWin; + focc->revert = None; + focc->time = currentTime; + focc->trace = (WindowPtr *)NULL; + focc->traceSize = 0; + focc->traceGood = 0; + dev->focus = focc; + return TRUE; +} + +_X_EXPORT Bool +InitKbdFeedbackClassDeviceStruct(DeviceIntPtr dev, BellProcPtr bellProc, + KbdCtrlProcPtr controlProc) +{ + KbdFeedbackPtr feedc; + + feedc = (KbdFeedbackPtr)xalloc(sizeof(KbdFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->BellProc = bellProc; + feedc->CtrlProc = controlProc; +#ifdef XKB + defaultKeyboardControl.autoRepeat = TRUE; +#endif + feedc->ctrl = defaultKeyboardControl; + feedc->ctrl.id = 0; + if ((feedc->next = dev->kbdfeed) != 0) + feedc->ctrl.id = dev->kbdfeed->ctrl.id + 1; + dev->kbdfeed = feedc; +#ifdef XKB + feedc->xkb_sli= NULL; + if (!noXkbExtension) + XkbFinishDeviceInit(dev); +#endif + (*dev->kbdfeed->CtrlProc)(dev,&dev->kbdfeed->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitPtrFeedbackClassDeviceStruct(DeviceIntPtr dev, PtrCtrlProcPtr controlProc) +{ + PtrFeedbackPtr feedc; + + feedc = (PtrFeedbackPtr)xalloc(sizeof(PtrFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultPointerControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->ptrfeed) ) + feedc->ctrl.id = dev->ptrfeed->ctrl.id + 1; + dev->ptrfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + + +static LedCtrl defaultLedControl = { + DEFAULT_LEDS, DEFAULT_LEDS_MASK, 0}; + +static BellCtrl defaultBellControl = { + DEFAULT_BELL, + DEFAULT_BELL_PITCH, + DEFAULT_BELL_DURATION, + 0}; + +static IntegerCtrl defaultIntegerControl = { + DEFAULT_INT_RESOLUTION, + DEFAULT_INT_MIN_VALUE, + DEFAULT_INT_MAX_VALUE, + DEFAULT_INT_DISPLAYED, + 0}; + +_X_EXPORT Bool +InitStringFeedbackClassDeviceStruct ( + DeviceIntPtr dev, StringCtrlProcPtr controlProc, + int max_symbols, int num_symbols_supported, KeySym *symbols) +{ + int i; + StringFeedbackPtr feedc; + + feedc = (StringFeedbackPtr)xalloc(sizeof(StringFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl.num_symbols_supported = num_symbols_supported; + feedc->ctrl.num_symbols_displayed = 0; + feedc->ctrl.max_symbols = max_symbols; + feedc->ctrl.symbols_supported = (KeySym *) + xalloc (sizeof (KeySym) * num_symbols_supported); + feedc->ctrl.symbols_displayed = (KeySym *) + xalloc (sizeof (KeySym) * max_symbols); + if (!feedc->ctrl.symbols_supported || !feedc->ctrl.symbols_displayed) + { + if (feedc->ctrl.symbols_supported) + xfree(feedc->ctrl.symbols_supported); + if (feedc->ctrl.symbols_displayed) + xfree(feedc->ctrl.symbols_displayed); + xfree(feedc); + return FALSE; + } + for (i=0; i<num_symbols_supported; i++) + *(feedc->ctrl.symbols_supported+i) = *symbols++; + for (i=0; i<max_symbols; i++) + *(feedc->ctrl.symbols_displayed+i) = (KeySym) NULL; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->stringfeed) ) + feedc->ctrl.id = dev->stringfeed->ctrl.id + 1; + dev->stringfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitBellFeedbackClassDeviceStruct (DeviceIntPtr dev, BellProcPtr bellProc, + BellCtrlProcPtr controlProc) +{ + BellFeedbackPtr feedc; + + feedc = (BellFeedbackPtr)xalloc(sizeof(BellFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->BellProc = bellProc; + feedc->ctrl = defaultBellControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->bell) ) + feedc->ctrl.id = dev->bell->ctrl.id + 1; + dev->bell = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitLedFeedbackClassDeviceStruct (DeviceIntPtr dev, LedCtrlProcPtr controlProc) +{ + LedFeedbackPtr feedc; + + feedc = (LedFeedbackPtr)xalloc(sizeof(LedFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultLedControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->leds) ) + feedc->ctrl.id = dev->leds->ctrl.id + 1; +#ifdef XKB + feedc->xkb_sli= NULL; +#endif + dev->leds = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitIntegerFeedbackClassDeviceStruct (DeviceIntPtr dev, IntegerCtrlProcPtr controlProc) +{ + IntegerFeedbackPtr feedc; + + feedc = (IntegerFeedbackPtr)xalloc(sizeof(IntegerFeedbackClassRec)); + if (!feedc) + return FALSE; + feedc->CtrlProc = controlProc; + feedc->ctrl = defaultIntegerControl; + feedc->ctrl.id = 0; + if ( (feedc->next = dev->intfeed) ) + feedc->ctrl.id = dev->intfeed->ctrl.id + 1; + dev->intfeed = feedc; + (*controlProc)(dev, &feedc->ctrl); + return TRUE; +} + +_X_EXPORT Bool +InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons, + ValuatorMotionProcPtr motionProc, + PtrCtrlProcPtr controlProc, int numMotionEvents, + int numAxes) +{ + DeviceIntPtr dev = (DeviceIntPtr)device; + + return(InitButtonClassDeviceStruct(dev, numButtons, map) && + InitValuatorClassDeviceStruct(dev, numAxes, motionProc, + numMotionEvents, 0) && + InitPtrFeedbackClassDeviceStruct(dev, controlProc)); +} + +_X_EXPORT Bool +InitKeyboardDeviceStruct(DevicePtr device, KeySymsPtr pKeySyms, + CARD8 pModifiers[], BellProcPtr bellProc, + KbdCtrlProcPtr controlProc) +{ + DeviceIntPtr dev = (DeviceIntPtr)device; + + return(InitKeyClassDeviceStruct(dev, pKeySyms, pModifiers) && + InitFocusClassDeviceStruct(dev) && + InitKbdFeedbackClassDeviceStruct(dev, bellProc, controlProc)); +} + +_X_EXPORT void +SendMappingNotify(unsigned request, unsigned firstKeyCode, unsigned count, + ClientPtr client) +{ + int i; + xEvent event; + + event.u.u.type = MappingNotify; + event.u.mappingNotify.request = request; + if (request == MappingKeyboard) + { + event.u.mappingNotify.firstKeyCode = firstKeyCode; + event.u.mappingNotify.count = count; + } +#ifdef XKB + if (!noXkbExtension && + ((request == MappingKeyboard) || (request == MappingModifier))) + XkbApplyMappingChange(inputInfo.keyboard, request, firstKeyCode, count, + client); +#endif + + /* 0 is the server client */ + for (i=1; i<currentMaxClients; i++) + { + if (clients[i] && clients[i]->clientState == ClientStateRunning) + { +#ifdef XKB + if (!noXkbExtension && + (request == MappingKeyboard) && + (clients[i]->xkbClientFlags != 0) && + (clients[i]->mapNotifyMask&XkbKeySymsMask)) + continue; +#endif + event.u.u.sequenceNumber = clients[i]->sequence; + WriteEventsToClient(clients[i], 1, &event); + } + } +} + +/* + * n-squared algorithm. n < 255 and don't want to copy the whole thing and + * sort it to do the checking. How often is it called? Just being lazy? + */ +Bool +BadDeviceMap(BYTE *buff, int length, unsigned low, unsigned high, XID *errval) +{ + int i, j; + + for (i = 0; i < length; i++) + if (buff[i]) /* only check non-zero elements */ + { + if ((low > buff[i]) || (high < buff[i])) + { + *errval = buff[i]; + return TRUE; + } + for (j = i + 1; j < length; j++) + if (buff[i] == buff[j]) + { + *errval = buff[i]; + return TRUE; + } + } + return FALSE; +} + +Bool +AllModifierKeysAreUp(dev, map1, per1, map2, per2) + DeviceIntPtr dev; + CARD8 *map1, *map2; + int per1, per2; +{ + int i, j, k; + CARD8 *down = dev->key->down; + + for (i = 8; --i >= 0; map2 += per2) + { + for (j = per1; --j >= 0; map1++) + { + if (*map1 && BitIsOn(down, *map1)) + { + for (k = per2; (--k >= 0) && (*map1 != map2[k]);) + ; + if (k < 0) + return FALSE; + } + } + } + return TRUE; +} + +static int +DoSetModifierMapping(ClientPtr client, KeyCode *inputMap, + int numKeyPerModifier, xSetModifierMappingReply *rep) +{ + DeviceIntPtr pDev = NULL; + int rc, i = 0, inputMapLen = numKeyPerModifier * 8; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { + for (i = 0; i < inputMapLen; i++) { + /* Check that all the new modifiers fall within the advertised + * keycode range, and are okay with the DDX. */ + if (inputMap[i] && ((inputMap[i] < pDev->key->curKeySyms.minKeyCode || + inputMap[i] > pDev->key->curKeySyms.maxKeyCode) || + !LegalModifier(inputMap[i], pDev))) { + client->errorValue = inputMap[i]; + return BadValue; + } + } + + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + return rc; + + /* None of the modifiers (old or new) may be down while we change + * the map. */ + if (!AllModifierKeysAreUp(pDev, pDev->key->modifierKeyMap, + pDev->key->maxKeysPerModifier, + inputMap, numKeyPerModifier) || + !AllModifierKeysAreUp(pDev, inputMap, numKeyPerModifier, + pDev->key->modifierKeyMap, + pDev->key->maxKeysPerModifier)) { + rep->success = MappingBusy; + return Success; + } + } + } + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { + bzero(pDev->key->modifierMap, MAP_LENGTH); + + /* Annoyingly, we lack a modifierKeyMap size, so we have to just free + * and re-alloc it every time. */ + if (pDev->key->modifierKeyMap) + xfree(pDev->key->modifierKeyMap); + + if (inputMapLen) { + pDev->key->modifierKeyMap = (KeyCode *) xalloc(inputMapLen); + if (!pDev->key->modifierKeyMap) + return BadAlloc; + + memcpy(pDev->key->modifierKeyMap, inputMap, inputMapLen); + pDev->key->maxKeysPerModifier = numKeyPerModifier; + + for (i = 0; i < inputMapLen; i++) { + if (inputMap[i]) { + pDev->key->modifierMap[inputMap[i]] |= + (1 << (((unsigned int)i) / numKeyPerModifier)); + } + } + } + else { + pDev->key->modifierKeyMap = NULL; + pDev->key->maxKeysPerModifier = 0; + } + } + } + + rep->success = Success; + return Success; +} + +int +ProcSetModifierMapping(ClientPtr client) +{ + xSetModifierMappingReply rep; + DeviceIntPtr dev; + int rc; + REQUEST(xSetModifierMappingReq); + REQUEST_AT_LEAST_SIZE(xSetModifierMappingReq); + + if (client->req_len != ((stuff->numKeyPerModifier << 1) + + (sizeof (xSetModifierMappingReq) >> 2))) + return BadLength; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = DoSetModifierMapping(client, (KeyCode *)&stuff[1], + stuff->numKeyPerModifier, &rep); + if (rc != Success) + return rc; + + SendMappingNotify(MappingModifier, 0, 0, client); + for (dev = inputInfo.devices; dev; dev = dev->next) + if (dev->key && dev->coreEvents) + SendDeviceMappingNotify(client, MappingModifier, 0, 0, dev); + WriteReplyToClient(client, sizeof(xSetModifierMappingReply), &rep); + return client->noClientException; +} + +int +ProcGetModifierMapping(ClientPtr client) +{ + xGetModifierMappingReply rep; + KeyClassPtr keyc = inputInfo.keyboard->key; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, + DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.numKeyPerModifier = keyc->maxKeysPerModifier; + rep.sequenceNumber = client->sequence; + /* length counts 4 byte quantities - there are 8 modifiers 1 byte big */ + rep.length = keyc->maxKeysPerModifier << 1; + + WriteReplyToClient(client, sizeof(xGetModifierMappingReply), &rep); + + /* Use the (modified by DDX) map that SetModifierMapping passed in */ + (void)WriteToClient(client, (int)(keyc->maxKeysPerModifier << 3), + (char *)keyc->modifierKeyMap); + return client->noClientException; +} + +int +ProcChangeKeyboardMapping(ClientPtr client) +{ + REQUEST(xChangeKeyboardMappingReq); + unsigned len; + KeySymsRec keysyms; + KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + DeviceIntPtr pDev = NULL; + int rc; + REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); + + len = client->req_len - (sizeof(xChangeKeyboardMappingReq) >> 2); + if (len != (stuff->keyCodes * stuff->keySymsPerKeyCode)) + return BadLength; + + if ((stuff->firstKeyCode < curKeySyms->minKeyCode) || + (stuff->firstKeyCode > curKeySyms->maxKeyCode)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + + } + if (((unsigned)(stuff->firstKeyCode + stuff->keyCodes - 1) > + curKeySyms->maxKeyCode) || (stuff->keySymsPerKeyCode == 0)) { + client->errorValue = stuff->keySymsPerKeyCode; + return BadValue; + } + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (rc != Success) + return rc; + } + } + + keysyms.minKeyCode = stuff->firstKeyCode; + keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1; + keysyms.mapWidth = stuff->keySymsPerKeyCode; + keysyms.map = (KeySym *)&stuff[1]; + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) + if (!SetKeySymsMap(&pDev->key->curKeySyms, &keysyms)) + return BadAlloc; + + SendMappingNotify(MappingKeyboard, stuff->firstKeyCode, stuff->keyCodes, + client); + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) + if (pDev->key && pDev->coreEvents) + SendDeviceMappingNotify(client, MappingKeyboard, + stuff->firstKeyCode, stuff->keyCodes, + pDev); + + return client->noClientException; +} + +static int +DoSetPointerMapping(ClientPtr client, DeviceIntPtr device, BYTE *map, int n) +{ + int rc, i = 0; + DeviceIntPtr dev = NULL; + + if (!device || !device->button) + return BadDevice; + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixManageAccess); + if (rc != Success) + return rc; + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { + for (i = 0; i < n; i++) { + if ((device->button->map[i + 1] != map[i]) && + BitIsOn(device->button->down, i + 1)) { + return MappingBusy; + } + } + } + } + + for (dev = inputInfo.devices; dev; dev = dev->next) { + if ((dev->coreEvents || dev == inputInfo.pointer) && dev->button) { + for (i = 0; i < n; i++) + dev->button->map[i + 1] = map[i]; + } + } + + return Success; +} + +int +ProcSetPointerMapping(ClientPtr client) +{ + BYTE *map; + int ret; + xSetPointerMappingReply rep; + REQUEST(xSetPointerMappingReq); + REQUEST_AT_LEAST_SIZE(xSetPointerMappingReq); + + if (client->req_len != (sizeof(xSetPointerMappingReq)+stuff->nElts+3) >> 2) + return BadLength; + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.success = MappingSuccess; + map = (BYTE *)&stuff[1]; + + /* So we're bounded here by the number of core buttons. This check + * probably wants disabling through XFixes. */ + if (stuff->nElts != inputInfo.pointer->button->numButtons) { + client->errorValue = stuff->nElts; + return BadValue; + } + if (BadDeviceMap(&map[0], (int)stuff->nElts, 1, 255, &client->errorValue)) + return BadValue; + + ret = DoSetPointerMapping(client, inputInfo.pointer, map, stuff->nElts); + if (ret != Success) { + rep.success = ret; + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; + } + + /* FIXME: Send mapping notifies for all the extended devices as well. */ + SendMappingNotify(MappingPointer, 0, 0, client); + WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); + return Success; +} + +int +ProcGetKeyboardMapping(ClientPtr client) +{ + xGetKeyboardMappingReply rep; + KeySymsPtr curKeySyms = &inputInfo.keyboard->key->curKeySyms; + int rc; + REQUEST(xGetKeyboardMappingReq); + REQUEST_SIZE_MATCH(xGetKeyboardMappingReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, + DixGetAttrAccess); + if (rc != Success) + return rc; + + if ((stuff->firstKeyCode < curKeySyms->minKeyCode) || + (stuff->firstKeyCode > curKeySyms->maxKeyCode)) { + client->errorValue = stuff->firstKeyCode; + return BadValue; + } + if (stuff->firstKeyCode + stuff->count > + (unsigned)(curKeySyms->maxKeyCode + 1)) { + client->errorValue = stuff->count; + return BadValue; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.keySymsPerKeyCode = curKeySyms->mapWidth; + /* length is a count of 4 byte quantities and KeySyms are 4 bytes */ + rep.length = (curKeySyms->mapWidth * stuff->count); + WriteReplyToClient(client, sizeof(xGetKeyboardMappingReply), &rep); + client->pSwapReplyFunc = (ReplySwapPtr) CopySwap32Write; + WriteSwappedDataToClient( + client, + curKeySyms->mapWidth * stuff->count * sizeof(KeySym), + &curKeySyms->map[(stuff->firstKeyCode - curKeySyms->minKeyCode) * + curKeySyms->mapWidth]); + + return client->noClientException; +} + +int +ProcGetPointerMapping(ClientPtr client) +{ + xGetPointerMappingReply rep; + ButtonClassPtr butc = inputInfo.pointer->button; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.pointer, + DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.nElts = butc->numButtons; + rep.length = ((unsigned)rep.nElts + (4-1))/4; + WriteReplyToClient(client, sizeof(xGetPointerMappingReply), &rep); + (void)WriteToClient(client, (int)rep.nElts, (char *)&butc->map[1]); + return Success; +} + +void +NoteLedState(DeviceIntPtr keybd, int led, Bool on) +{ + KeybdCtrl *ctrl = &keybd->kbdfeed->ctrl; + if (on) + ctrl->leds |= ((Leds)1 << (led - 1)); + else + ctrl->leds &= ~((Leds)1 << (led - 1)); +} + +_X_EXPORT int +Ones(unsigned long mask) /* HACKMEM 169 */ +{ + unsigned long y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +} + +static int +DoChangeKeyboardControl (ClientPtr client, DeviceIntPtr keybd, XID *vlist, + BITS32 vmask) +{ +#define DO_ALL (-1) + KeybdCtrl ctrl; + int t; + int led = DO_ALL; + int key = DO_ALL; + BITS32 index2; + int mask = vmask, i; + + ctrl = keybd->kbdfeed->ctrl; + while (vmask) { + index2 = (BITS32) lowbit (vmask); + vmask &= ~index2; + switch (index2) { + case KBKeyClickPercent: + t = (INT8)*vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.click; + } + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.click = t; + break; + case KBBellPercent: + t = (INT8)*vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.bell; + } + else if (t < 0 || t > 100) { + client->errorValue = t; + return BadValue; + } + ctrl.bell = t; + break; + case KBBellPitch: + t = (INT16)*vlist; + vlist++; + if (t == -1) { + t = defaultKeyboardControl.bell_pitch; + } + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_pitch = t; + break; + case KBBellDuration: + t = (INT16)*vlist; + vlist++; + if (t == -1) + t = defaultKeyboardControl.bell_duration; + else if (t < 0) { + client->errorValue = t; + return BadValue; + } + ctrl.bell_duration = t; + break; + case KBLed: + led = (CARD8)*vlist; + vlist++; + if (led < 1 || led > 32) { + client->errorValue = led; + return BadValue; + } + if (!(mask & KBLedMode)) + return BadMatch; + break; + case KBLedMode: + t = (CARD8)*vlist; + vlist++; + if (t == LedModeOff) { + if (led == DO_ALL) + ctrl.leds = 0x0; + else + ctrl.leds &= ~(((Leds)(1)) << (led - 1)); + } + else if (t == LedModeOn) { + if (led == DO_ALL) + ctrl.leds = ~0L; + else + ctrl.leds |= (((Leds)(1)) << (led - 1)); + } + else { + client->errorValue = t; + return BadValue; + } +#ifdef XKB + if (!noXkbExtension) { + XkbEventCauseRec cause; + XkbSetCauseCoreReq(&cause,X_ChangeKeyboardControl,client); + XkbSetIndicators(keybd,((led == DO_ALL) ? ~0L : (1L<<(led-1))), + ctrl.leds, &cause); + ctrl.leds = keybd->kbdfeed->ctrl.leds; + } +#endif + break; + case KBKey: + key = (KeyCode)*vlist; + vlist++; + if ((KeyCode)key < inputInfo.keyboard->key->curKeySyms.minKeyCode || + (KeyCode)key > inputInfo.keyboard->key->curKeySyms.maxKeyCode) { + client->errorValue = key; + return BadValue; + } + if (!(mask & KBAutoRepeatMode)) + return BadMatch; + break; + case KBAutoRepeatMode: + i = (key >> 3); + mask = (1 << (key & 7)); + t = (CARD8)*vlist; + vlist++; +#ifdef XKB + if (!noXkbExtension && key != DO_ALL) + XkbDisableComputedAutoRepeats(keybd,key); +#endif + if (t == AutoRepeatModeOff) { + if (key == DO_ALL) + ctrl.autoRepeat = FALSE; + else + ctrl.autoRepeats[i] &= ~mask; + } + else if (t == AutoRepeatModeOn) { + if (key == DO_ALL) + ctrl.autoRepeat = TRUE; + else + ctrl.autoRepeats[i] |= mask; + } + else if (t == AutoRepeatModeDefault) { + if (key == DO_ALL) + ctrl.autoRepeat = defaultKeyboardControl.autoRepeat; + else + ctrl.autoRepeats[i] = + (ctrl.autoRepeats[i] & ~mask) | + (defaultKeyboardControl.autoRepeats[i] & mask); + } + else { + client->errorValue = t; + return BadValue; + } + break; + default: + client->errorValue = mask; + return BadValue; + } + } + keybd->kbdfeed->ctrl = ctrl; + +#ifdef XKB + /* The XKB RepeatKeys control and core protocol global autorepeat */ + /* value are linked */ + if (!noXkbExtension) + XkbSetRepeatKeys(keybd, key, keybd->kbdfeed->ctrl.autoRepeat); + else +#endif + (*keybd->kbdfeed->CtrlProc)(keybd, &keybd->kbdfeed->ctrl); + + return Success; + +#undef DO_ALL +} + +int +ProcChangeKeyboardControl (ClientPtr client) +{ + XID *vlist; + BITS32 vmask; + int ret = Success, error = Success; + DeviceIntPtr pDev = NULL; + REQUEST(xChangeKeyboardControlReq); + + REQUEST_AT_LEAST_SIZE(xChangeKeyboardControlReq); + + vmask = stuff->mask; + vlist = (XID *)&stuff[1]; + + if (client->req_len != (sizeof(xChangeKeyboardControlReq)>>2)+Ones(vmask)) + return BadLength; + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && + pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess); + if (ret != Success) + return ret; + } + } + + for (pDev = inputInfo.devices; pDev; pDev = pDev->next) { + if ((pDev->coreEvents || pDev == inputInfo.keyboard) && + pDev->kbdfeed && pDev->kbdfeed->CtrlProc) { + ret = DoChangeKeyboardControl(client, pDev, vlist, vmask); + if (ret != Success) + error = ret; + } + } + + return error; +} + +int +ProcGetKeyboardControl (ClientPtr client) +{ + int rc, i; + KeybdCtrl *ctrl = &inputInfo.keyboard->kbdfeed->ctrl; + xGetKeyboardControlReply rep; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, + DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 5; + rep.sequenceNumber = client->sequence; + rep.globalAutoRepeat = ctrl->autoRepeat; + rep.keyClickPercent = ctrl->click; + rep.bellPercent = ctrl->bell; + rep.bellPitch = ctrl->bell_pitch; + rep.bellDuration = ctrl->bell_duration; + rep.ledMask = ctrl->leds; + for (i = 0; i < 32; i++) + rep.map[i] = ctrl->autoRepeats[i]; + WriteReplyToClient(client, sizeof(xGetKeyboardControlReply), &rep); + return Success; +} + +int +ProcBell(ClientPtr client) +{ + DeviceIntPtr keybd = inputInfo.keyboard; + int base = keybd->kbdfeed->ctrl.bell; + int newpercent; + int rc; + REQUEST(xBellReq); + REQUEST_SIZE_MATCH(xBellReq); + + if (!keybd->kbdfeed->BellProc) + return BadDevice; + + if (stuff->percent < -100 || stuff->percent > 100) { + client->errorValue = stuff->percent; + return BadValue; + } + + newpercent = (base * stuff->percent) / 100; + if (stuff->percent < 0) + newpercent = base + newpercent; + else + newpercent = base - newpercent + stuff->percent; + + for (keybd = inputInfo.devices; keybd; keybd = keybd->next) { + if ((keybd->coreEvents || keybd == inputInfo.keyboard) && + keybd->kbdfeed && keybd->kbdfeed->BellProc) { + + rc = XaceHook(XACE_DEVICE_ACCESS, client, keybd, DixBellAccess); + if (rc != Success) + return rc; +#ifdef XKB + if (!noXkbExtension) + XkbHandleBell(FALSE, FALSE, keybd, newpercent, + &keybd->kbdfeed->ctrl, 0, None, NULL, client); + else +#endif + (*keybd->kbdfeed->BellProc)(newpercent, keybd, + &keybd->kbdfeed->ctrl, 0); + } + } + + return Success; +} + +int +ProcChangePointerControl(ClientPtr client) +{ + DeviceIntPtr mouse = inputInfo.pointer; + PtrCtrl ctrl; /* might get BadValue part way through */ + int rc; + REQUEST(xChangePointerControlReq); + REQUEST_SIZE_MATCH(xChangePointerControlReq); + + if (!mouse->ptrfeed->CtrlProc) + return BadDevice; + + ctrl = mouse->ptrfeed->ctrl; + if ((stuff->doAccel != xTrue) && (stuff->doAccel != xFalse)) { + client->errorValue = stuff->doAccel; + return(BadValue); + } + if ((stuff->doThresh != xTrue) && (stuff->doThresh != xFalse)) { + client->errorValue = stuff->doThresh; + return(BadValue); + } + if (stuff->doAccel) { + if (stuff->accelNum == -1) { + ctrl.num = defaultPointerControl.num; + } + else if (stuff->accelNum < 0) { + client->errorValue = stuff->accelNum; + return BadValue; + } + else { + ctrl.num = stuff->accelNum; + } + + if (stuff->accelDenum == -1) { + ctrl.den = defaultPointerControl.den; + } + else if (stuff->accelDenum <= 0) { + client->errorValue = stuff->accelDenum; + return BadValue; + } + else { + ctrl.den = stuff->accelDenum; + } + } + if (stuff->doThresh) { + if (stuff->threshold == -1) { + ctrl.threshold = defaultPointerControl.threshold; + } + else if (stuff->threshold < 0) { + client->errorValue = stuff->threshold; + return BadValue; + } + else { + ctrl.threshold = stuff->threshold; + } + } + + for (mouse = inputInfo.devices; mouse; mouse = mouse->next) { + if ((mouse->coreEvents || mouse == inputInfo.pointer) && + mouse->ptrfeed && mouse->ptrfeed->CtrlProc) { + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixManageAccess); + if (rc != Success) + return rc; + } + } + + for (mouse = inputInfo.devices; mouse; mouse = mouse->next) { + if ((mouse->coreEvents || mouse == inputInfo.pointer) && + mouse->ptrfeed && mouse->ptrfeed->CtrlProc) { + mouse->ptrfeed->ctrl = ctrl; + (*mouse->ptrfeed->CtrlProc)(mouse, &mouse->ptrfeed->ctrl); + } + } + + return Success; +} + +int +ProcGetPointerControl(ClientPtr client) +{ + PtrCtrl *ctrl = &inputInfo.pointer->ptrfeed->ctrl; + xGetPointerControlReply rep; + int rc; + REQUEST_SIZE_MATCH(xReq); + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.pointer, + DixGetAttrAccess); + if (rc != Success) + return rc; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.threshold = ctrl->threshold; + rep.accelNumerator = ctrl->num; + rep.accelDenominator = ctrl->den; + WriteReplyToClient(client, sizeof(xGenericReply), &rep); + return Success; +} + +void +MaybeStopHint(DeviceIntPtr dev, ClientPtr client) +{ + GrabPtr grab = dev->grab; + + if ((grab && SameClient(grab, client) && + ((grab->eventMask & PointerMotionHintMask) || + (grab->ownerEvents && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask)))) || + (!grab && + (EventMaskForClient(dev->valuator->motionHintWindow, client) & + PointerMotionHintMask))) + dev->valuator->motionHintWindow = NullWindow; +} + +int +ProcGetMotionEvents(ClientPtr client) +{ + WindowPtr pWin; + xTimecoord * coords = (xTimecoord *) NULL; + xGetMotionEventsReply rep; + int i, count, xmin, xmax, ymin, ymax, rc; + unsigned long nEvents; + DeviceIntPtr mouse = inputInfo.pointer; + TimeStamp start, stop; + REQUEST(xGetMotionEventsReq); + REQUEST_SIZE_MATCH(xGetMotionEventsReq); + + rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); + if (rc != Success) + return rc; + rc = XaceHook(XACE_DEVICE_ACCESS, client, mouse, DixReadAccess); + if (rc != Success) + return rc; + + if (mouse->valuator->motionHintWindow) + MaybeStopHint(mouse, client); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + nEvents = 0; + start = ClientTimeToServerTime(stuff->start); + stop = ClientTimeToServerTime(stuff->stop); + if ((CompareTimeStamps(start, stop) != LATER) && + (CompareTimeStamps(start, currentTime) != LATER) && + mouse->valuator->numMotionEvents) + { + if (CompareTimeStamps(stop, currentTime) == LATER) + stop = currentTime; + coords = (xTimecoord *)xalloc(mouse->valuator->numMotionEvents + * sizeof(xTimecoord)); + if (!coords) + return BadAlloc; + count = (*mouse->valuator->GetMotionProc) (mouse, coords, + start.milliseconds, + stop.milliseconds, + pWin->drawable.pScreen); + xmin = pWin->drawable.x - wBorderWidth (pWin); + xmax = pWin->drawable.x + (int)pWin->drawable.width + + wBorderWidth (pWin); + ymin = pWin->drawable.y - wBorderWidth (pWin); + ymax = pWin->drawable.y + (int)pWin->drawable.height + + wBorderWidth (pWin); + for (i = 0; i < count; i++) + if ((xmin <= coords[i].x) && (coords[i].x < xmax) && + (ymin <= coords[i].y) && (coords[i].y < ymax)) + { + coords[nEvents].time = coords[i].time; + coords[nEvents].x = coords[i].x - pWin->drawable.x; + coords[nEvents].y = coords[i].y - pWin->drawable.y; + nEvents++; + } + } + rep.length = nEvents * (sizeof(xTimecoord) >> 2); + rep.nEvents = nEvents; + WriteReplyToClient(client, sizeof(xGetMotionEventsReply), &rep); + if (nEvents) + { + client->pSwapReplyFunc = (ReplySwapPtr) SwapTimeCoordWrite; + WriteSwappedDataToClient(client, nEvents * sizeof(xTimecoord), + (char *)coords); + } + if (coords) + xfree(coords); + return Success; +} + +int +ProcQueryKeymap(ClientPtr client) +{ + xQueryKeymapReply rep; + int rc, i; + CARD8 *down = inputInfo.keyboard->key->down; + + REQUEST_SIZE_MATCH(xReq); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 2; + + rc = XaceHook(XACE_DEVICE_ACCESS, client, inputInfo.keyboard, + DixReadAccess); + if (rc != Success) + return rc; + + for (i = 0; i<32; i++) + rep.map[i] = down[i]; + + WriteReplyToClient(client, sizeof(xQueryKeymapReply), &rep); + return Success; +} |