1/* 2 * Copyright © 2009 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: Peter Hutterer 24 * 25 */ 26 27/** 28 * @file Protocol handling for the XIQueryDevice request/reply. 29 */ 30 31#ifdef HAVE_DIX_CONFIG_H 32#include <dix-config.h> 33#endif 34 35#include "inputstr.h" 36#include <X11/X.h> 37#include <X11/Xatom.h> 38#include <X11/extensions/XI2proto.h> 39#include "xkbstr.h" 40#include "xkbsrv.h" 41#include "xserver-properties.h" 42#include "exevents.h" 43#include "xace.h" 44 45#include "xiquerydevice.h" 46 47static Bool ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr d); 48static int 49ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info); 50static int SizeDeviceInfo(DeviceIntPtr dev); 51static void SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info); 52int 53SProcXIQueryDevice(ClientPtr client) 54{ 55 char n; 56 57 REQUEST(xXIQueryDeviceReq); 58 REQUEST_SIZE_MATCH(xXIQueryDeviceReq); 59 60 swaps(&stuff->length, n); 61 swaps(&stuff->deviceid, n); 62 63 return ProcXIQueryDevice(client); 64} 65 66int 67ProcXIQueryDevice(ClientPtr client) 68{ 69 xXIQueryDeviceReply rep; 70 DeviceIntPtr dev = NULL; 71 int rc = Success; 72 int i = 0, len = 0; 73 char *info, *ptr; 74 Bool *skip = NULL; 75 76 REQUEST(xXIQueryDeviceReq); 77 REQUEST_SIZE_MATCH(xXIQueryDeviceReq); 78 79 if (stuff->deviceid != XIAllDevices && stuff->deviceid != XIAllMasterDevices) 80 { 81 rc = dixLookupDevice(&dev, stuff->deviceid, client, DixGetAttrAccess); 82 if (rc != Success) 83 { 84 client->errorValue = stuff->deviceid; 85 return rc; 86 } 87 len += SizeDeviceInfo(dev); 88 } 89 else 90 { 91 skip = calloc(sizeof(Bool), inputInfo.numDevices); 92 if (!skip) 93 return BadAlloc; 94 95 for (dev = inputInfo.devices; dev; dev = dev->next, i++) 96 { 97 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); 98 if (!skip[i]) 99 len += SizeDeviceInfo(dev); 100 } 101 102 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) 103 { 104 skip[i] = ShouldSkipDevice(client, stuff->deviceid, dev); 105 if (!skip[i]) 106 len += SizeDeviceInfo(dev); 107 } 108 } 109 110 info = calloc(1, len); 111 if (!info) { 112 free(skip); 113 return BadAlloc; 114 } 115 116 memset(&rep, 0, sizeof(xXIQueryDeviceReply)); 117 rep.repType = X_Reply; 118 rep.RepType = X_XIQueryDevice; 119 rep.sequenceNumber = client->sequence; 120 rep.length = len/4; 121 rep.num_devices = 0; 122 123 ptr = info; 124 if (dev) 125 { 126 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 127 if (client->swapped) 128 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 129 info += len; 130 rep.num_devices = 1; 131 } else 132 { 133 i = 0; 134 for (dev = inputInfo.devices; dev; dev = dev->next, i++) 135 { 136 if (!skip[i]) 137 { 138 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 139 if (client->swapped) 140 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 141 info += len; 142 rep.num_devices++; 143 } 144 } 145 146 for (dev = inputInfo.off_devices; dev; dev = dev->next, i++) 147 { 148 if (!skip[i]) 149 { 150 len = ListDeviceInfo(client, dev, (xXIDeviceInfo*)info); 151 if (client->swapped) 152 SwapDeviceInfo(dev, (xXIDeviceInfo*)info); 153 info += len; 154 rep.num_devices++; 155 } 156 } 157 } 158 159 len = rep.length * 4; 160 WriteReplyToClient(client, sizeof(xXIQueryDeviceReply), &rep); 161 WriteToClient(client, len, ptr); 162 free(ptr); 163 free(skip); 164 return rc; 165} 166 167void 168SRepXIQueryDevice(ClientPtr client, int size, xXIQueryDeviceReply *rep) 169{ 170 char n; 171 172 swaps(&rep->sequenceNumber, n); 173 swapl(&rep->length, n); 174 swaps(&rep->num_devices, n); 175 176 /* Device info is already swapped, see ProcXIQueryDevice */ 177 178 WriteToClient(client, size, (char *)rep); 179} 180 181 182/** 183 * @return Whether the device should be included in the returned list. 184 */ 185static Bool 186ShouldSkipDevice(ClientPtr client, int deviceid, DeviceIntPtr dev) 187{ 188 /* if all devices are not being queried, only master devices are */ 189 if (deviceid == XIAllDevices || IsMaster(dev)) 190 { 191 int rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixGetAttrAccess); 192 if (rc == Success) 193 return FALSE; 194 } 195 return TRUE; 196} 197 198/** 199 * @return The number of bytes needed to store this device's xXIDeviceInfo 200 * (and its classes). 201 */ 202static int 203SizeDeviceInfo(DeviceIntPtr dev) 204{ 205 int len = sizeof(xXIDeviceInfo); 206 207 /* 4-padded name */ 208 len += pad_to_int32(strlen(dev->name)); 209 210 return len + SizeDeviceClasses(dev); 211 212} 213 214/* 215 * @return The number of bytes needed to store this device's classes. 216 */ 217int 218SizeDeviceClasses(DeviceIntPtr dev) 219{ 220 int len = 0; 221 222 if (dev->button) 223 { 224 len += sizeof(xXIButtonInfo); 225 len += dev->button->numButtons * sizeof(Atom); 226 len += pad_to_int32(bits_to_bytes(dev->button->numButtons)); 227 } 228 229 if (dev->key) 230 { 231 XkbDescPtr xkb = dev->key->xkbInfo->desc; 232 len += sizeof(xXIKeyInfo); 233 len += (xkb->max_key_code - xkb->min_key_code + 1) * sizeof(uint32_t); 234 } 235 236 if (dev->valuator) 237 len += sizeof(xXIValuatorInfo) * dev->valuator->numAxes; 238 239 return len; 240} 241 242 243/** 244 * Write button information into info. 245 * @return Number of bytes written into info. 246 */ 247int 248ListButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info, Bool reportState) 249{ 250 unsigned char *bits; 251 int mask_len; 252 int i; 253 254 if (!dev || !dev->button) 255 return 0; 256 257 mask_len = bytes_to_int32(bits_to_bytes(dev->button->numButtons)); 258 259 info->type = ButtonClass; 260 info->num_buttons = dev->button->numButtons; 261 info->length = bytes_to_int32(sizeof(xXIButtonInfo)) + 262 info->num_buttons + mask_len; 263 info->sourceid = dev->button->sourceid; 264 265 bits = (unsigned char*)&info[1]; 266 memset(bits, 0, mask_len * 4); 267 268 if (reportState) 269 for (i = 0; i < dev->button->numButtons; i++) 270 if (BitIsOn(dev->button->down, i)) 271 SetBit(bits, i); 272 273 bits += mask_len * 4; 274 memcpy(bits, dev->button->labels, dev->button->numButtons * sizeof(Atom)); 275 276 return info->length * 4; 277} 278 279static void 280SwapButtonInfo(DeviceIntPtr dev, xXIButtonInfo* info) 281{ 282 char n; 283 Atom *btn; 284 int i; 285 swaps(&info->type, n); 286 swaps(&info->length, n); 287 swaps(&info->sourceid, n); 288 289 for (i = 0, btn = (Atom*)&info[1]; i < info->num_buttons; i++, btn++) 290 swaps(btn, n); 291 292 swaps(&info->num_buttons, n); 293} 294 295/** 296 * Write key information into info. 297 * @return Number of bytes written into info. 298 */ 299int 300ListKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) 301{ 302 int i; 303 XkbDescPtr xkb = dev->key->xkbInfo->desc; 304 uint32_t *kc; 305 306 info->type = KeyClass; 307 info->num_keycodes = xkb->max_key_code - xkb->min_key_code + 1; 308 info->length = sizeof(xXIKeyInfo)/4 + info->num_keycodes; 309 info->sourceid = dev->key->sourceid; 310 311 kc = (uint32_t*)&info[1]; 312 for (i = xkb->min_key_code; i <= xkb->max_key_code; i++, kc++) 313 *kc = i; 314 315 return info->length * 4; 316} 317 318static void 319SwapKeyInfo(DeviceIntPtr dev, xXIKeyInfo* info) 320{ 321 char n; 322 uint32_t *key; 323 int i; 324 swaps(&info->type, n); 325 swaps(&info->length, n); 326 swaps(&info->sourceid, n); 327 328 for (i = 0, key = (uint32_t*)&info[1]; i < info->num_keycodes; i++, key++) 329 swapl(key, n); 330 331 swaps(&info->num_keycodes, n); 332} 333 334/** 335 * List axis information for the given axis. 336 * 337 * @return The number of bytes written into info. 338 */ 339int 340ListValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info, int axisnumber, 341 Bool reportState) 342{ 343 ValuatorClassPtr v = dev->valuator; 344 345 info->type = ValuatorClass; 346 info->length = sizeof(xXIValuatorInfo)/4; 347 info->label = v->axes[axisnumber].label; 348 info->min.integral = v->axes[axisnumber].min_value; 349 info->min.frac = 0; 350 info->max.integral = v->axes[axisnumber].max_value; 351 info->max.frac = 0; 352 info->value.integral = (int)v->axisVal[axisnumber]; 353 info->value.frac = (int)(v->axisVal[axisnumber] * (1 << 16) * (1 << 16)); 354 info->resolution = v->axes[axisnumber].resolution; 355 info->number = axisnumber; 356 info->mode = valuator_get_mode(dev, axisnumber); 357 info->sourceid = v->sourceid; 358 359 if (!reportState) 360 info->value = info->min; 361 362 return info->length * 4; 363} 364 365static void 366SwapValuatorInfo(DeviceIntPtr dev, xXIValuatorInfo* info) 367{ 368 char n; 369 swaps(&info->type, n); 370 swaps(&info->length, n); 371 swapl(&info->label, n); 372 swapl(&info->min.integral, n); 373 swapl(&info->min.frac, n); 374 swapl(&info->max.integral, n); 375 swapl(&info->max.frac, n); 376 swaps(&info->number, n); 377 swaps(&info->sourceid, n); 378} 379 380int GetDeviceUse(DeviceIntPtr dev, uint16_t *attachment) 381{ 382 DeviceIntPtr master = dev->u.master; 383 int use; 384 385 if (IsMaster(dev)) 386 { 387 DeviceIntPtr paired = GetPairedDevice(dev); 388 use = IsPointerDevice(dev) ? XIMasterPointer : XIMasterKeyboard; 389 *attachment = (paired ? paired->id : 0); 390 } else if (master) 391 { 392 use = IsPointerDevice(master) ? XISlavePointer : XISlaveKeyboard; 393 *attachment = master->id; 394 } else 395 use = XIFloatingSlave; 396 397 return use; 398} 399 400/** 401 * Write the info for device dev into the buffer pointed to by info. 402 * 403 * @return The number of bytes used. 404 */ 405static int 406ListDeviceInfo(ClientPtr client, DeviceIntPtr dev, xXIDeviceInfo* info) 407{ 408 char *any = (char*)&info[1]; 409 int len = 0, total_len = 0; 410 411 info->deviceid = dev->id; 412 info->use = GetDeviceUse(dev, &info->attachment); 413 info->num_classes = 0; 414 info->name_len = strlen(dev->name); 415 info->enabled = dev->enabled; 416 total_len = sizeof(xXIDeviceInfo); 417 418 len = pad_to_int32(info->name_len); 419 memset(any, 0, len); 420 strncpy(any, dev->name, info->name_len); 421 any += len; 422 total_len += len; 423 424 total_len += ListDeviceClasses(client, dev, any, &info->num_classes); 425 return total_len; 426} 427 428/** 429 * Write the class info of the device into the memory pointed to by any, set 430 * nclasses to the number of classes in total and return the number of bytes 431 * written. 432 */ 433int 434ListDeviceClasses(ClientPtr client, DeviceIntPtr dev, 435 char *any, uint16_t *nclasses) 436{ 437 int total_len = 0; 438 int len; 439 int i; 440 int rc; 441 442 /* Check if the current device state should be suppressed */ 443 rc = XaceHook(XACE_DEVICE_ACCESS, client, dev, DixReadAccess); 444 445 if (dev->button) 446 { 447 (*nclasses)++; 448 len = ListButtonInfo(dev, (xXIButtonInfo*)any, rc == Success); 449 any += len; 450 total_len += len; 451 } 452 453 if (dev->key) 454 { 455 (*nclasses)++; 456 len = ListKeyInfo(dev, (xXIKeyInfo*)any); 457 any += len; 458 total_len += len; 459 } 460 461 for (i = 0; dev->valuator && i < dev->valuator->numAxes; i++) 462 { 463 (*nclasses)++; 464 len = ListValuatorInfo(dev, (xXIValuatorInfo*)any, i, rc == Success); 465 any += len; 466 total_len += len; 467 } 468 469 return total_len; 470} 471 472static void 473SwapDeviceInfo(DeviceIntPtr dev, xXIDeviceInfo* info) 474{ 475 char n; 476 char *any = (char*)&info[1]; 477 int i; 478 479 /* Skip over name */ 480 any += pad_to_int32(info->name_len); 481 482 for (i = 0; i < info->num_classes; i++) 483 { 484 int len = ((xXIAnyInfo*)any)->length; 485 switch(((xXIAnyInfo*)any)->type) 486 { 487 case XIButtonClass: 488 SwapButtonInfo(dev, (xXIButtonInfo*)any); 489 break; 490 case XIKeyClass: 491 SwapKeyInfo(dev, (xXIKeyInfo*)any); 492 break; 493 case XIValuatorClass: 494 SwapValuatorInfo(dev, (xXIValuatorInfo*)any); 495 break; 496 } 497 498 any += len * 4; 499 } 500 501 swaps(&info->deviceid, n); 502 swaps(&info->use, n); 503 swaps(&info->attachment, n); 504 swaps(&info->num_classes, n); 505 swaps(&info->name_len, n); 506 507} 508