1/************************************************************ 2 3Copyright 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 25Copyright 1989 by Hewlett-Packard Company, Palo Alto, California. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Hewlett-Packard not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37HEWLETT-PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39HEWLETT-PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 44 45********************************************************/ 46 47/*********************************************************************** 48 * 49 * Extension function to list the available input devices. 50 * 51 */ 52 53#ifdef HAVE_DIX_CONFIG_H 54#include <dix-config.h> 55#endif 56 57#include <X11/X.h> /* for inputstr.h */ 58#include <X11/Xproto.h> /* Request macro */ 59#include "inputstr.h" /* DeviceIntPtr */ 60#include <X11/extensions/XI.h> 61#include <X11/extensions/XIproto.h> 62#include "XIstubs.h" 63#include "extnsionst.h" 64#include "exevents.h" 65#include "xace.h" 66#include "xkbsrv.h" 67#include "xkbstr.h" 68 69#include "listdev.h" 70 71 72/*********************************************************************** 73 * 74 * This procedure lists the input devices available to the server. 75 * 76 */ 77 78int 79SProcXListInputDevices(ClientPtr client) 80{ 81 char n; 82 83 REQUEST(xListInputDevicesReq); 84 swaps(&stuff->length, n); 85 return (ProcXListInputDevices(client)); 86} 87 88/*********************************************************************** 89 * 90 * This procedure calculates the size of the information to be returned 91 * for an input device. 92 * 93 */ 94 95static void 96SizeDeviceInfo(DeviceIntPtr d, int *namesize, int *size) 97{ 98 int chunks; 99 100 *namesize += 1; 101 if (d->name) 102 *namesize += strlen(d->name); 103 if (d->key != NULL) 104 *size += sizeof(xKeyInfo); 105 if (d->button != NULL) 106 *size += sizeof(xButtonInfo); 107 if (d->valuator != NULL) { 108 chunks = ((int)d->valuator->numAxes + 19) / VPC; 109 *size += (chunks * sizeof(xValuatorInfo) + 110 d->valuator->numAxes * sizeof(xAxisInfo)); 111 } 112} 113 114/*********************************************************************** 115 * 116 * This procedure copies data to the DeviceInfo struct, swapping if necessary. 117 * 118 * We need the extra byte in the allocated buffer, because the trailing null 119 * hammers one extra byte, which is overwritten by the next name except for 120 * the last name copied. 121 * 122 */ 123 124static void 125CopyDeviceName(char **namebuf, char *name) 126{ 127 char *nameptr = (char *)*namebuf; 128 129 if (name) { 130 *nameptr++ = strlen(name); 131 strcpy(nameptr, name); 132 *namebuf += (strlen(name) + 1); 133 } else { 134 *nameptr++ = 0; 135 *namebuf += 1; 136 } 137} 138 139/*********************************************************************** 140 * 141 * This procedure copies ButtonClass information, swapping if necessary. 142 * 143 */ 144 145static void 146CopySwapButtonClass(ClientPtr client, ButtonClassPtr b, char **buf) 147{ 148 char n; 149 xButtonInfoPtr b2; 150 151 b2 = (xButtonInfoPtr) * buf; 152 b2->class = ButtonClass; 153 b2->length = sizeof(xButtonInfo); 154 b2->num_buttons = b->numButtons; 155 if (client && client->swapped) { 156 swaps(&b2->num_buttons, n); /* macro - braces are required */ 157 } 158 *buf += sizeof(xButtonInfo); 159} 160 161/*********************************************************************** 162 * 163 * This procedure copies data to the DeviceInfo struct, swapping if necessary. 164 * 165 */ 166 167static void 168CopySwapDevice(ClientPtr client, DeviceIntPtr d, int num_classes, 169 char **buf) 170{ 171 char n; 172 xDeviceInfoPtr dev; 173 174 dev = (xDeviceInfoPtr) * buf; 175 176 dev->id = d->id; 177 dev->type = d->xinput_type; 178 dev->num_classes = num_classes; 179 if (IsMaster(d) && IsKeyboardDevice(d)) 180 dev->use = IsXKeyboard; 181 else if (IsMaster(d) && IsPointerDevice(d)) 182 dev->use = IsXPointer; 183 else if (d->valuator && d->button) 184 dev->use = IsXExtensionPointer; 185 else if (d->key && d->kbdfeed) 186 dev->use = IsXExtensionKeyboard; 187 else 188 dev->use = IsXExtensionDevice; 189 190 if (client->swapped) { 191 swapl(&dev->type, n); /* macro - braces are required */ 192 } 193 *buf += sizeof(xDeviceInfo); 194} 195 196/*********************************************************************** 197 * 198 * This procedure copies KeyClass information, swapping if necessary. 199 * 200 */ 201 202static void 203CopySwapKeyClass(ClientPtr client, KeyClassPtr k, char **buf) 204{ 205 char n; 206 xKeyInfoPtr k2; 207 208 k2 = (xKeyInfoPtr) * buf; 209 k2->class = KeyClass; 210 k2->length = sizeof(xKeyInfo); 211 k2->min_keycode = k->xkbInfo->desc->min_key_code; 212 k2->max_keycode = k->xkbInfo->desc->max_key_code; 213 k2->num_keys = k2->max_keycode - k2->min_keycode + 1; 214 if (client && client->swapped) { 215 swaps(&k2->num_keys, n); 216 } 217 *buf += sizeof(xKeyInfo); 218} 219 220/*********************************************************************** 221 * 222 * This procedure copies ValuatorClass information, swapping if necessary. 223 * 224 * Devices may have up to 255 valuators. The length of a ValuatorClass is 225 * defined to be sizeof(ValuatorClassInfo) + num_axes * sizeof (xAxisInfo). 226 * The maximum length is therefore (8 + 255 * 12) = 3068. However, the 227 * length field is one byte. If a device has more than 20 valuators, we 228 * must therefore return multiple valuator classes to the client. 229 * 230 */ 231 232static int 233CopySwapValuatorClass(ClientPtr client, DeviceIntPtr dev, char **buf) 234{ 235 int i, j, axes, t_axes; 236 char n; 237 ValuatorClassPtr v = dev->valuator; 238 xValuatorInfoPtr v2; 239 AxisInfo *a; 240 xAxisInfoPtr a2; 241 242 for (i = 0, axes = v->numAxes; i < ((v->numAxes + 19) / VPC); 243 i++, axes -= VPC) { 244 t_axes = axes < VPC ? axes : VPC; 245 if (t_axes < 0) 246 t_axes = v->numAxes % VPC; 247 v2 = (xValuatorInfoPtr) * buf; 248 v2->class = ValuatorClass; 249 v2->length = sizeof(xValuatorInfo) + t_axes * sizeof(xAxisInfo); 250 v2->num_axes = t_axes; 251 v2->mode = valuator_get_mode(dev, 0); 252 v2->motion_buffer_size = v->numMotionEvents; 253 if (client && client->swapped) { 254 swapl(&v2->motion_buffer_size, n); 255 } 256 *buf += sizeof(xValuatorInfo); 257 a = v->axes + (VPC * i); 258 a2 = (xAxisInfoPtr) * buf; 259 for (j = 0; j < t_axes; j++) { 260 a2->min_value = a->min_value; 261 a2->max_value = a->max_value; 262 a2->resolution = a->resolution; 263 if (client && client->swapped) { 264 swapl(&a2->min_value, n); 265 swapl(&a2->max_value, n); 266 swapl(&a2->resolution, n); 267 } 268 a2++; 269 a++; 270 *buf += sizeof(xAxisInfo); 271 } 272 } 273 return i; 274} 275 276static void 277CopySwapClasses(ClientPtr client, DeviceIntPtr dev, CARD8 *num_classes, 278 char** classbuf) 279{ 280 if (dev->key != NULL) { 281 CopySwapKeyClass(client, dev->key, classbuf); 282 (*num_classes)++; 283 } 284 if (dev->button != NULL) { 285 CopySwapButtonClass(client, dev->button, classbuf); 286 (*num_classes)++; 287 } 288 if (dev->valuator != NULL) { 289 (*num_classes) += 290 CopySwapValuatorClass(client, dev, classbuf); 291 } 292} 293 294/*********************************************************************** 295 * 296 * This procedure lists information to be returned for an input device. 297 * 298 */ 299 300static void 301ListDeviceInfo(ClientPtr client, DeviceIntPtr d, xDeviceInfoPtr dev, 302 char **devbuf, char **classbuf, char **namebuf) 303{ 304 CopyDeviceName(namebuf, d->name); 305 CopySwapDevice(client, d, 0, devbuf); 306 CopySwapClasses(client, d, &dev->num_classes, classbuf); 307} 308 309/*********************************************************************** 310 * 311 * This procedure checks if a device should be left off the list. 312 * 313 */ 314 315static Bool 316ShouldSkipDevice(ClientPtr client, DeviceIntPtr d) 317{ 318 /* don't send master devices other than VCP/VCK */ 319 if (!IsMaster(d) || d == inputInfo.pointer || d == inputInfo.keyboard) 320 { 321 int rc = XaceHook(XACE_DEVICE_ACCESS, client, d, DixGetAttrAccess); 322 if (rc == Success) 323 return FALSE; 324 } 325 return TRUE; 326} 327 328 329/*********************************************************************** 330 * 331 * This procedure lists the input devices available to the server. 332 * 333 * If this request is called by a client that has not issued a 334 * GetExtensionVersion request with major/minor version set, we don't send the 335 * complete device list. Instead, we only send the VCP, the VCK and floating 336 * SDs. This resembles the setup found on XI 1.x machines. 337 */ 338 339int 340ProcXListInputDevices(ClientPtr client) 341{ 342 xListInputDevicesReply rep; 343 int numdevs = 0; 344 int namesize = 1; /* need 1 extra byte for strcpy */ 345 int i = 0, size = 0; 346 int total_length; 347 char *devbuf, *classbuf, *namebuf, *savbuf; 348 Bool *skip; 349 xDeviceInfo *dev; 350 DeviceIntPtr d; 351 352 REQUEST_SIZE_MATCH(xListInputDevicesReq); 353 354 memset(&rep, 0, sizeof(xListInputDevicesReply)); 355 rep.repType = X_Reply; 356 rep.RepType = X_ListInputDevices; 357 rep.length = 0; 358 rep.sequenceNumber = client->sequence; 359 360 /* allocate space for saving skip value */ 361 skip = calloc(sizeof(Bool), inputInfo.numDevices); 362 if (!skip) 363 return BadAlloc; 364 365 /* figure out which devices to skip */ 366 numdevs = 0; 367 for (d = inputInfo.devices; d; d = d->next, i++) { 368 skip[i] = ShouldSkipDevice(client, d); 369 if (skip[i]) 370 continue; 371 372 SizeDeviceInfo(d, &namesize, &size); 373 numdevs++; 374 } 375 376 for (d = inputInfo.off_devices; d; d = d->next, i++) { 377 skip[i] = ShouldSkipDevice(client, d); 378 if (skip[i]) 379 continue; 380 381 SizeDeviceInfo(d, &namesize, &size); 382 numdevs++; 383 } 384 385 /* allocate space for reply */ 386 total_length = numdevs * sizeof(xDeviceInfo) + size + namesize; 387 devbuf = (char *)calloc(1, total_length); 388 classbuf = devbuf + (numdevs * sizeof(xDeviceInfo)); 389 namebuf = classbuf + size; 390 savbuf = devbuf; 391 392 /* fill in and send reply */ 393 i = 0; 394 dev = (xDeviceInfoPtr) devbuf; 395 for (d = inputInfo.devices; d; d = d->next, i++) { 396 if (skip[i]) 397 continue; 398 399 ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); 400 } 401 402 for (d = inputInfo.off_devices; d; d = d->next, i++) { 403 if (skip[i]) 404 continue; 405 406 ListDeviceInfo(client, d, dev++, &devbuf, &classbuf, &namebuf); 407 } 408 rep.ndevices = numdevs; 409 rep.length = bytes_to_int32(total_length); 410 WriteReplyToClient(client, sizeof(xListInputDevicesReply), &rep); 411 WriteToClient(client, total_length, savbuf); 412 free(savbuf); 413 free(skip); 414 return Success; 415} 416 417/*********************************************************************** 418 * 419 * This procedure writes the reply for the XListInputDevices function, 420 * if the client and server have a different byte ordering. 421 * 422 */ 423 424void 425SRepXListInputDevices(ClientPtr client, int size, xListInputDevicesReply * rep) 426{ 427 char n; 428 429 swaps(&rep->sequenceNumber, n); 430 swapl(&rep->length, n); 431 WriteToClient(client, size, (char *)rep); 432} 433