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
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 #include <stdint.h>
29 #include <X11/X.h>
30 #include <X11/Xproto.h>
31 #include <X11/extensions/XI2proto.h>
32 #include <X11/Xatom.h>
33 #include "inputstr.h"
34 #include "extinit.h"
35 #include "exglobals.h"
36 #include "scrnintstr.h"
37 #include "xkbsrv.h"
38
39 #include "xiquerydevice.h"
40
41 #include "protocol-common.h"
42 /*
43 * Protocol testing for XIQueryDevice request and reply.
44 *
45 * Test approach:
46 * Wrap WriteToClient to intercept server's reply. ProcXIQueryDevice returns
47 * data in two batches, once for the request, once for the trailing data
48 * with the device information.
49 * Repeatedly test with varying deviceids and check against data in reply.
50 */
51
52 struct test_data {
53 int which_device;
54 int num_devices_in_reply;
55 };
56
57 extern ClientRec client_window;
58
59 static void reply_XIQueryDevice_data(ClientPtr client, int len, char *data,
60 void *closure);
61 static void reply_XIQueryDevice(ClientPtr client, int len, char *data,
62 void *closure);
63
64 /* reply handling for the first bytes that constitute the reply */
65 static void
reply_XIQueryDevice(ClientPtr client,int len,char * data,void * userdata)66 reply_XIQueryDevice(ClientPtr client, int len, char *data, void *userdata)
67 {
68 xXIQueryDeviceReply *rep = (xXIQueryDeviceReply *) data;
69 struct test_data *querydata = (struct test_data *) userdata;
70
71 if (client->swapped) {
72 swapl(&rep->length);
73 swaps(&rep->sequenceNumber);
74 swaps(&rep->num_devices);
75 }
76
77 reply_check_defaults(rep, len, XIQueryDevice);
78
79 if (querydata->which_device == XIAllDevices)
80 assert(rep->num_devices == devices.num_devices);
81 else if (querydata->which_device == XIAllMasterDevices)
82 assert(rep->num_devices == devices.num_master_devices);
83 else
84 assert(rep->num_devices == 1);
85
86 querydata->num_devices_in_reply = rep->num_devices;
87 reply_handler = reply_XIQueryDevice_data;
88 }
89
90 /* reply handling for the trailing bytes that constitute the device info */
91 static void
reply_XIQueryDevice_data(ClientPtr client,int len,char * data,void * closure)92 reply_XIQueryDevice_data(ClientPtr client, int len, char *data, void *closure)
93 {
94 int i, j;
95 struct test_data *querydata = (struct test_data *) closure;
96
97 DeviceIntPtr dev;
98 xXIDeviceInfo *info = (xXIDeviceInfo *) data;
99 xXIAnyInfo *any;
100
101 for (i = 0; i < querydata->num_devices_in_reply; i++) {
102 if (client->swapped) {
103 swaps(&info->deviceid);
104 swaps(&info->attachment);
105 swaps(&info->use);
106 swaps(&info->num_classes);
107 swaps(&info->name_len);
108 }
109
110 if (querydata->which_device > XIAllMasterDevices)
111 assert(info->deviceid == querydata->which_device);
112
113 assert(info->deviceid >= 2); /* 0 and 1 is reserved */
114
115 switch (info->deviceid) {
116 case 2: /* VCP */
117 dev = devices.vcp;
118 assert(info->use == XIMasterPointer);
119 assert(info->attachment == devices.vck->id);
120 assert(info->num_classes == 3); /* 2 axes + button */
121 break;
122 case 3: /* VCK */
123 dev = devices.vck;
124 assert(info->use == XIMasterKeyboard);
125 assert(info->attachment == devices.vcp->id);
126 assert(info->num_classes == 1);
127 break;
128 case 4: /* mouse */
129 dev = devices.mouse;
130 assert(info->use == XISlavePointer);
131 assert(info->attachment == devices.vcp->id);
132 assert(info->num_classes == 7); /* 4 axes + button + 2 scroll */
133 break;
134 case 5: /* keyboard */
135 dev = devices.kbd;
136 assert(info->use == XISlaveKeyboard);
137 assert(info->attachment == devices.vck->id);
138 assert(info->num_classes == 1);
139 break;
140
141 default:
142 /* We shouldn't get here */
143 assert(0);
144 break;
145 }
146 assert(info->enabled == dev->enabled);
147 assert(info->name_len == strlen(dev->name));
148 assert(strncmp((char *) &info[1], dev->name, info->name_len) == 0);
149
150 any =
151 (xXIAnyInfo *) ((char *) &info[1] + ((info->name_len + 3) / 4) * 4);
152 for (j = 0; j < info->num_classes; j++) {
153 if (client->swapped) {
154 swaps(&any->type);
155 swaps(&any->length);
156 swaps(&any->sourceid);
157 }
158
159 switch (info->deviceid) {
160 case 3: /* VCK and kbd have the same properties */
161 case 5:
162 {
163 int k;
164 xXIKeyInfo *ki = (xXIKeyInfo *) any;
165 XkbDescPtr xkb = devices.vck->key->xkbInfo->desc;
166 uint32_t *kc;
167
168 if (client->swapped)
169 swaps(&ki->num_keycodes);
170
171 assert(any->type == XIKeyClass);
172 assert(ki->num_keycodes ==
173 (xkb->max_key_code - xkb->min_key_code + 1));
174 assert(any->length == (2 + ki->num_keycodes));
175
176 kc = (uint32_t *) &ki[1];
177 for (k = 0; k < ki->num_keycodes; k++, kc++) {
178 if (client->swapped)
179 swapl(kc);
180
181 assert(*kc >= xkb->min_key_code);
182 assert(*kc <= xkb->max_key_code);
183 }
184 break;
185 }
186 case 4:
187 {
188 assert(any->type == XIButtonClass ||
189 any->type == XIValuatorClass ||
190 any->type == XIScrollClass);
191
192 if (any->type == XIScrollClass) {
193 xXIScrollInfo *si = (xXIScrollInfo *) any;
194
195 if (client->swapped) {
196 swaps(&si->number);
197 swaps(&si->scroll_type);
198 swapl(&si->increment.integral);
199 swapl(&si->increment.frac);
200 }
201 assert(si->length == 6);
202 assert(si->number == 2 || si->number == 3);
203 if (si->number == 2) {
204 assert(si->scroll_type == XIScrollTypeVertical);
205 assert(!si->flags);
206 }
207 if (si->number == 3) {
208 assert(si->scroll_type == XIScrollTypeHorizontal);
209 assert(si->flags & XIScrollFlagPreferred);
210 assert(!(si->flags & ~XIScrollFlagPreferred));
211 }
212
213 assert(si->increment.integral == si->number);
214 /* protocol-common.c sets up increments of 2.4 and 3.5 */
215 assert(si->increment.frac > 0.3 * (1ULL << 32));
216 assert(si->increment.frac < 0.6 * (1ULL << 32));
217 }
218
219 }
220 /* fall through */
221 case 2: /* VCP and mouse have the same properties except for scroll */
222 {
223 if (info->deviceid == 2) /* VCP */
224 assert(any->type == XIButtonClass ||
225 any->type == XIValuatorClass);
226
227 if (any->type == XIButtonClass) {
228 int l;
229 xXIButtonInfo *bi = (xXIButtonInfo *) any;
230
231 if (client->swapped)
232 swaps(&bi->num_buttons);
233
234 assert(bi->num_buttons == devices.vcp->button->numButtons);
235
236 l = 2 + bi->num_buttons +
237 bytes_to_int32(bits_to_bytes(bi->num_buttons));
238 assert(bi->length == l);
239 }
240 else if (any->type == XIValuatorClass) {
241 xXIValuatorInfo *vi = (xXIValuatorInfo *) any;
242
243 if (client->swapped) {
244 swaps(&vi->number);
245 swapl(&vi->label);
246 swapl(&vi->min.integral);
247 swapl(&vi->min.frac);
248 swapl(&vi->max.integral);
249 swapl(&vi->max.frac);
250 swapl(&vi->resolution);
251 }
252
253 assert(vi->length == 11);
254 assert(vi->number >= 0 && vi->number < 4);
255 if (info->deviceid == 2) /* VCP */
256 assert(vi->number < 2);
257
258 assert(vi->mode == XIModeRelative);
259 /* device was set up as relative, so standard
260 * values here. */
261 assert(vi->min.integral == -1);
262 assert(vi->min.frac == 0);
263 assert(vi->max.integral == -1);
264 assert(vi->max.frac == 0);
265 assert(vi->resolution == 0);
266 }
267 }
268 break;
269 }
270 any = (xXIAnyInfo *) (((char *) any) + any->length * 4);
271 }
272
273 info = (xXIDeviceInfo *) any;
274 }
275 }
276
277 static void
request_XIQueryDevice(struct test_data * querydata,int deviceid,int error)278 request_XIQueryDevice(struct test_data *querydata, int deviceid, int error)
279 {
280 int rc;
281 ClientRec client;
282 xXIQueryDeviceReq request;
283
284 request_init(&request, XIQueryDevice);
285 client = init_client(request.length, &request);
286 reply_handler = reply_XIQueryDevice;
287
288 querydata->which_device = deviceid;
289
290 request.deviceid = deviceid;
291 rc = ProcXIQueryDevice(&client);
292 assert(rc == error);
293
294 if (rc != Success)
295 assert(client.errorValue == deviceid);
296
297 reply_handler = reply_XIQueryDevice;
298
299 client.swapped = TRUE;
300 swaps(&request.length);
301 swaps(&request.deviceid);
302 rc = SProcXIQueryDevice(&client);
303 assert(rc == error);
304
305 if (rc != Success)
306 assert(client.errorValue == deviceid);
307 }
308
309 static void
test_XIQueryDevice(void)310 test_XIQueryDevice(void)
311 {
312 int i;
313 xXIQueryDeviceReq request;
314 struct test_data data;
315
316 reply_handler = reply_XIQueryDevice;
317 global_userdata = &data;
318 request_init(&request, XIQueryDevice);
319
320 printf("Testing XIAllDevices.\n");
321 request_XIQueryDevice(&data, XIAllDevices, Success);
322 printf("Testing XIAllMasterDevices.\n");
323 request_XIQueryDevice(&data, XIAllMasterDevices, Success);
324
325 printf("Testing existing device ids.\n");
326 for (i = 2; i < 6; i++)
327 request_XIQueryDevice(&data, i, Success);
328
329 printf("Testing non-existing device ids.\n");
330 for (i = 6; i <= 0xFFFF; i++)
331 request_XIQueryDevice(&data, i, BadDevice);
332
333 reply_handler = NULL;
334
335 }
336
337 int
protocol_xiquerydevice_test(void)338 protocol_xiquerydevice_test(void)
339 {
340 init_simple();
341
342 test_XIQueryDevice();
343
344 return 0;
345 }
346