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