/* * Copyright © 2009 Red Hat, Inc. * * 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. * * Authors: Peter Hutterer * */ /** * @file Protocol handling for the XIQueryDevice request/reply. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include "inputstr.h" #include #include #include "xkbstr.h" #include "xkbsrv.h" #include "xserver-properties.h" #include "exevents.h" #include "querydev.h" static int ListDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); static int SizeDeviceInfo(DeviceIntPtr dev); static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); int SProcXIQueryDevice(ClientPtr client) { char n; REQUEST(xXIQueryDeviceReq); swaps(&stuff->length, n); swaps(&stuff->deviceid, n); return ProcXIQueryDevice(client); } int ProcXIQueryDevice(ClientPtr client) { xXIQueryDeviceReply rep; DeviceIntPtr dev = NULL; int rc = Success; int len = 0; char *info, *ptr; REQUEST(xXIQueryDeviceReq); REQUEST_SIZE_MATCH(xXIQueryDeviceReq); if (stuff->deviceid > 0xFF) /* FIXME */ { client->errorValue = stuff->deviceid; return BadImplementation; } if (stuff->deviceid != XIAllDevices && stuff->deviceid != XIAllMasterDevices) { rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); if (rc != Success) { client->errorValue = stuff->deviceid; return rc; } } if (dev) len += SizeDeviceInfo(dev); else { len = 0; for (dev = inputInfo.devices; dev; dev = dev->next) { if (stuff->deviceid == XIAllDevices || (stuff->deviceid == XIAllMasterDevices && IsMaster(dev))) len += SizeDeviceInfo(dev); } for (dev = inputInfo.off_devices; dev; dev = dev->next) { if (stuff->deviceid == XIAllDevices || (stuff->deviceid == XIAllMasterDevices && IsMaster(dev))) len += SizeDeviceInfo(dev); } dev = NULL; } info = xcalloc(1, len); if (!info) return BadAlloc; memset(&rep, 0, sizeof(xXIQueryDeviceReply)); rep.repType = X_Reply; rep.RepType = X_XIQueryDevice; rep.sequenceNumber = client->sequence; rep.length = len/4; rep.num_devices = 0; ptr = info; if (dev) { len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); if (client->swapped) SwapDeviceInfo(dev, (xXIDeviceInfo*)info); info += len; rep.num_devices = 1; } else { for (dev = inputInfo.devices; dev; dev = dev->next) { if (stuff->deviceid == XIAllDevices || (stuff->deviceid == XIAllMasterDevices && IsMaster(dev))) { len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); if (client->swapped) SwapDeviceInfo(dev, (xXIDeviceInfo*)info); info += len; rep.num_devices++; } } for (dev = inputInfo.off_devices; dev; dev = dev->next) { if (stuff->deviceid == XIAllDevices || (stuff->deviceid == XIAllMasterDevices && IsMaster(dev))) { len = ListDeviceInfo(dev, (xXIDeviceInfo*)info); if (client->swapped) SwapDeviceInfo(dev, (xXIDeviceInfo*)info); info += len; rep.num_devices++; } } } WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); WriteToClient(client, rep.length * 4, ptr); return rc; } void SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) { char n; swaps(&rep->sequenceNumber, n); swapl(&rep->length, n); swaps(&rep->num_devices, n); /* Device info is already swapped, see ProcXIQueryDevice */ WriteToClient(client, size, (char *)rep); } /** * @return The number of bytes needed to store this device's xXIDeviceInfo * (and its classes). */ static int SizeDeviceInfo(DeviceIntPtr dev) { int len = sizeof(xXIDeviceInfo); /* 4-padded name */ len += (((strlen(dev->name) + 3)/4)*4); return len + SizeDeviceClasses(dev); } /* * @return The number of bytes needed to store this device's classes. */ int SizeDeviceClasses(DeviceIntPtr dev) { int len = 0; if (dev->button) { len += sizeof(xXIButtonInfo); len += dev->button->numButtons * sizeof(Atom); } if (dev->key) { XkbDescPtr xkb = dev->key->xkbInfo->desc; len += sizeof(xXIKeyInfo); len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); } if (dev->valuator) len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; return len; } /** * Write button information into info. * @return Number of bytes written into info. */ int ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) { info->type = ButtonClass; info->num_buttons = dev->button->numButtons; info->length = 2 + info->num_buttons; /** XXX: button labels */ return info->length * 4; } static void SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) { char n; Atom *btn; int i; swaps(&info->type, n); swaps(&info->length, n); for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) swaps(btn, n); swaps(&info->num_buttons, n); } /** * Write key information into info. * @return Number of bytes written into info. */ int ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) { int i; XkbDescPtr xkb = dev->key->xkbInfo->desc; uint32_t *kc; info->type = KeyClass; info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; info->length = 2 + info->num_keycodes; kc = (uint32_t*)&info[1]; for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) *kc = i; return info->length * 4; } static void SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) { char n; uint32_t *key; int i; swaps(&info->type, n); swaps(&info->length, n); for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) swaps(key, n); swaps(&info->num_keycodes, n); } /** * List axis information for the given axis. * * @return The number of bytes written into info. */ int ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber) { ValuatorClassPtr v = dev->valuator; info->type = ValuatorClass; info->length = sizeof(xXIValuatorInfo)/4; info->name = XIGetKnownProperty(AXIS_LABEL_PROP_REL_MISC); /* XXX */ info->min.integral = v->axes[axisnumber].min_value; info->min.frac = 0; info->max.integral = v->axes[axisnumber].max_value; info->max.frac = 0; info->resolution = v->axes[axisnumber].resolution; info->number = axisnumber; info->mode = v->mode; /* Server doesn't have per-axis mode yet */ return info->length * 4; } static void SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) { char n; swaps(&info->type, n); swaps(&info->length, n); swapl(&info->name, n); swapl(&info->min.integral, n); swapl(&info->min.frac, n); swapl(&info->max.integral, n); swapl(&info->max.frac, n); swaps(&info->number, n); } int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) { DeviceIntPtr master = dev->u.master; int use; if (IsMaster(dev)) { DeviceIntPtr paired = GetPairedDevice(dev); use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; *attachment = (paired ? paired->id : 0); } else if (master) { use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; *attachment = master->id; } else use = XIFloatingSlave; return use; } /** * Write the info for device dev into the buffer pointed to by info. * * @return The number of bytes used. */ static int ListDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) { char *any = (char*)&info[1]; int len = 0, total_len = 0; info->deviceid = dev->id; info->use = GetDeviceUse(dev, &info->attachment); info->num_classes = 0; info->name_len = strlen(dev->name); info->enabled = dev->enabled; total_len = sizeof(xXIDeviceInfo); len = ((info->name_len + 3)/4) * 4; memset(any, 0, len); strncpy(any, dev->name, info->name_len); any += len; total_len += len; return total_len + ListDeviceClasses(dev, any, &info->num_classes); } /** * Write the class info of the device into the memory pointed to by any, set * nclasses to the number of classes in total and return the number of bytes * written. */ int ListDeviceClasses(DeviceIntPtr dev, char *any, uint16_t *nclasses) { int total_len = 0; int len; int i; if (dev->button) { (*nclasses)++; len = ListButtonInfo(dev, (xXIButtonInfo*)any); any += len; total_len += len; } if (dev->key) { (*nclasses)++; len = ListKeyInfo(dev, (xXIKeyInfo*)any); any += len; total_len += len; } for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) { (*nclasses)++; len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i); any += len; total_len += len; } return total_len; } static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) { char n; char *any = (char*)&info[1]; int i; /* Skip over name */ any += (((info->name_len + 3)/4) * 4); for (i = 0; i < info->num_classes; i++) { switch(((xXIAnyInfo*)any)->type) { case ButtonClass: SwapButtonInfo(dev, (xXIButtonInfo*)any); break; case KeyClass: SwapKeyInfo(dev, (xXIKeyInfo*)any); break; case ValuatorClass: SwapValuatorInfo(dev, (xXIValuatorInfo*)any); break; } any += (((xXIAnyInfo*)any)->length * 4); } swaps(&info->deviceid, n); swaps(&info->use, n); swaps(&info->attachment, n); swaps(&info->num_classes, n); swaps(&info->name_len, n); }