Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | } |