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