add support for Cintiq 21UX2
[expresskeys.git] / src-expresskeys / get_device.c
1 /*
2  expresskeys - Support ExpressKeys, Touch Strips, Scroll Wheel on Wacom tablets.
3
4  Copyright (C) 2005-2007 - Mats Johannesson
5
6  register_events() based on test.c 1996 by Frederic Lepied (xinput-1.2)
7
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License along
19  with this program; if not, write to the Free Software Foundation, Inc.,
20  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include <stdio.h> /* NULL, FILE, fgets, popen, pclose, snprintf */
24 #include <string.h> /* strlen, strstr, strcspn, strncmp, strcmp */
25 #include <ctype.h> /* isdigit, tolower */
26 #include <stdlib.h> /* atoi */
27 #include <X11/extensions/XInput.h>
28
29 #include "defines.h"
30
31 /* Globals: */
32
33 /* State flags: */
34 int have_pad;
35 int ok_xsetwacom;
36 int xsetwacom_version;
37
38 /* Numbers we get from registering our interest in certain events: */
39 int button_press_type;
40 int button_release_type;
41 int motion_type;
42 int proximity_in_type;
43 int proximity_out_type;
44
45 /* Used in many situations as identification, for math and for flow control: */
46 const int ux2 = 7;
47 const int bbo = 6;
48 const int bee = 5;
49 const int i3 = 4;
50 const int i3s = 3;
51 const int g4 = 2;
52 const int g4b = 1;
53 const int nop = 0;
54
55 /* The large structure emanating from XListInputDevices: */
56 XDeviceInfo* xdevice_list;
57
58 /* Arrays used as storage before transfer to structures, and for quick loops: */
59 XDevice* pad_xdevice[MAXMODEL][MAXPAD];
60 XDevice* stylus_xdevice[MAXSTYLUS][MAXMODEL * MAXPAD];
61
62 unsigned long int* pad_id[MAXMODEL][MAXPAD];
63 unsigned long int* stylus_id[MAXSTYLUS][MAXMODEL * MAXPAD];
64
65 const char* pad_name[MAXMODEL][MAXPAD];
66 const char* stylus_name[MAXSTYLUS][MAXMODEL * MAXPAD];
67
68 unsigned char* stylus_mode[MAXSTYLUS][MAXMODEL * MAXPAD];
69
70 /* 'Internal' Globals: */
71
72 /* Counting to keep track, and store in the right array element: */
73 static int pad_num;
74 static int stylus_num;
75
76 /* Recycled placeholder: */
77 static XDevice* tmp_device;
78
79 /* Externals: */
80
81 extern int screen;
82 extern Display* display;
83
84 extern const char* our_prog_name;
85
86 extern const char* pad_string;
87 extern const char* stylus_string;
88
89 extern const char* user_pad;
90 extern const char* user_stylus1;
91 extern const char* user_stylus2;
92
93 static int get_xsetwacom_version(void)
94 {
95         FILE* execfp = NULL;
96         int major, minor, release, ret;
97         char read_buffer[MAXBUFFER];
98
99         major = minor = release = 0;
100
101         if ((execfp = popen("xsetwacom -V", "r")) != NULL) {
102                 fgets(read_buffer, MAXBUFFER, execfp);
103                 if (pclose(execfp) != NON_VALID) {
104                         ret = sscanf(read_buffer, "%i.%i.%i", &major, &minor,
105                                      &release);
106                         if (ret == 3)
107                                 return major * 100 + minor * 10 + release;
108                 }
109         }
110
111         return 0;
112 }
113
114 #define setwacom_ignore_result(buffer, buff_size, device, prop, value) \
115                 {\
116                         FILE *pfd; \
117                         snprintf(buffer, buff_size, "xsetwacom set %s "prop " " value, \
118                                                                 device); \
119                         pfd = popen(buffer, "r"); \
120                         if (pclose(pfd) == NON_VALID) \
121                                 fprintf(stderr, "Error setting " prop " as " value "\n"); \
122                 }
123
124
125 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
126  This function uses the "popen" command which creates a pipe, forks and
127  invokes a shell where xsetwacom can be run. First action is to ensure that
128  version 0.0.7 or greater of xsetwacom is present (ie linuxwacom-0.7.5-2
129  where the option GetTabletID was introduced). Thereafter we match the tablet
130  decimal number string against known tablet numbers. A full table can be
131  found in src/xdrv/wcmUSB.c of the linuxwacom sources (Hex numbers).
132  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
133
134 static int identify_device(char* device_name)
135 {
136         const char* cintiq_20wsx = "197"; /* 0xC5 */
137         const char* cintiq_21UX = "63"; /* 0x3F */
138         const char* cintiq_21UX2 = "204"; /* 0xCC */
139         const char* i3_6x8 = "177"; /* 0xB1 */
140         const char* i3_9x12 = "178"; /* 0xB2 */
141         const char* i3_12x12 = "179"; /* 0xB3 */
142         const char* i3_12x19 = "180"; /* 0xB4 */
143         const char* i3_6x11 = "181"; /* 0xB5 */
144         const char* i3s_4x5 = "176"; /* 0xB0 */
145         const char* i3s_4x6 = "183"; /* 0xB7 */
146         const char* g4_4x5 = "21"; /* 0x15 */
147         const char* g4_6x8 = "22"; /* 0x16 */
148         const char* g4b_6x8 = "129"; /* 0x81 */
149         const char* bamboo = "101"; /* 0x65 */
150
151 /* Minimum xsetwacom version we can use is 0.0.7 */
152         const int min_xsetwacom = 7;
153
154         char read_buffer[MAXBUFFER];
155         char write_buffer[MAXBUFFER];
156
157         int len = 0;
158         int ok_value = 0;
159
160         FILE* execfp = NULL;
161         read_buffer[0] = '\0';
162
163         ok_xsetwacom = 0;
164         xsetwacom_version = get_xsetwacom_version();
165         if (xsetwacom_version > min_xsetwacom) {
166                 ok_xsetwacom = 1;
167
168                 /*
169                  * linuxwacom >= 0.8.0 (xsetwacom 0.1.0) handles the
170                  * touchstrips and expresskeys by default. let's make
171                  * sure those settings are cleared.
172                  */
173                 if (xsetwacom_version >= 10) {
174                         printf("Info: linuxwacom 0.8.0 or newer detected, the "
175                                "TouchStrips and ExpressKeys settings will "
176                                "be reset.\n");
177                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "RelWUp", "0");
178                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "RelWDn", "0");
179                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "AbsWUp", "0");
180                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "AbsWDn", "0");
181
182                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "StripRUp", "0");
183                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "StripRDn", "0");
184                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "StripLUp", "0");
185                         setwacom_ignore_result(write_buffer, MAXBUFFER, device_name, "StripLDn", "0");
186                 }
187         }
188
189 /* linuxwacom-0.7.7-3 changed GetTabletID to plain TabletID. Later, support
190  for both strings were introduced. We follow the same pattern here, defaulting
191  to the new way, should the old format disappear in a linuxwacom future: */
192         if (ok_xsetwacom) {
193                 read_buffer[0] = '\0';
194                 snprintf(write_buffer,MAXBUFFER, "xsetwacom get %s TabletID",
195                                                                 device_name);
196                 if ((execfp = popen(write_buffer, "r")) != NULL) {
197                         fgets(read_buffer, MAXBUFFER, execfp);
198                         if (((pclose(execfp)) != NON_VALID)
199                         && (isdigit(read_buffer[0]))) {
200                                 ok_value = 1;
201                         } else {
202                                 read_buffer[0] = '\0';
203                                 snprintf(write_buffer,MAXBUFFER,
204                                 "xsetwacom get %s GetTabletID", device_name);
205                                 if ((execfp = popen(write_buffer, "r"))
206                                                                 != NULL) {
207                                         fgets(read_buffer, MAXBUFFER, execfp);
208                                         if (((pclose(execfp)) != NON_VALID)
209                                         && (isdigit(read_buffer[0]))) {
210                                                 ok_value = 1;
211                                         }
212                                 }
213                         }
214                 }
215
216                 if (ok_value) {
217                         len = strcspn(read_buffer, " \t\n");
218                         if ((strncmp(read_buffer, cintiq_21UX2, len)) == 0) {
219                                 return ux2;
220                         }
221                         if ((strncmp(read_buffer, bamboo, len)) == 0) {
222                                 return bbo;
223                         }
224                         if ((strncmp(read_buffer, cintiq_20wsx, len)) == 0) {
225                                 return bee;
226                         }
227                         if ((strncmp(read_buffer, cintiq_21UX, len)) == 0) {
228                                 return i3;
229                         }
230                         if (((strncmp(read_buffer, i3_6x8, len)) == 0)
231                                 || ((strncmp(read_buffer, i3_9x12, len)) == 0)
232                                 || ((strncmp(read_buffer, i3_12x12, len)) == 0)
233                                 || ((strncmp(read_buffer, i3_12x19, len)) == 0)
234                                 || ((strncmp(read_buffer, i3_6x11, len)) == 0)){
235                                 return i3;
236                         }
237                         if (((strncmp(read_buffer, i3s_4x5, len)) == 0)
238                                 || ((strncmp(read_buffer, i3s_4x6, len)) == 0)){
239                                 return i3s;
240                         }
241                         if (((strncmp(read_buffer, g4_4x5, len)) == 0)
242                                 || ((strncmp(read_buffer, g4_6x8, len)) == 0)) {
243                                 return g4;
244                         }
245                         if ((strncmp(read_buffer, g4b_6x8, len)) == 0) {
246                                 return g4b;
247                         }
248                 }
249         }
250
251 /* We must treat all tablets as 'padless' if xsetwacom is missing or too old: */
252         if (!ok_xsetwacom) {
253                 have_pad = 0;
254         }
255         return nop;
256
257 }
258
259 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
260  Start looking for supported event types. The scope should be the root window
261  (ie everywhere). We're interested in motion events and proximity in/out for
262  the touch strips, and button press/release for the pad buttons. For the
263  styli we ask about button press and proximity in. Having found the info
264  we ask the X server to keep us continuously notified about these events:
265  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
266
267 static int register_events(const char* name)
268 {
269         int i;
270         int count = 0;
271
272         XInputClassInfo* ip;
273         Window root_win;
274
275         root_win = RootWindow(display, screen);
276
277         if (name == pad_string) {
278                 XEventClass event_list[5];
279                 if (tmp_device->num_classes > 0) {
280                         for (ip = tmp_device->classes,
281                                 i = 0; i < tmp_device->num_classes; ip++, i++) {
282                                 switch (ip->input_class) {
283
284                                 case ButtonClass:
285                                 DeviceButtonPress(tmp_device,
286                                         button_press_type, event_list[count]);
287                                 count++;
288                                 DeviceButtonRelease(tmp_device,
289                                         button_release_type, event_list[count]);
290                                 count++;
291                                 break;
292
293                                 case ValuatorClass:
294                                 DeviceMotionNotify(tmp_device,
295                                         motion_type, event_list[count]);
296                                 count++;
297                                 ProximityIn(tmp_device,
298                                         proximity_in_type, event_list[count]);
299                                 count++;
300                                 ProximityOut(tmp_device,
301                                         proximity_out_type, event_list[count]);
302                                 count++;
303                                 break;
304
305                                 default:
306                                 break;
307                                 }
308                         }
309                 }
310                 if (XSelectExtensionEvent(display, root_win,
311                                         event_list, count)) {
312                         return 0;
313                 }
314                 return count;
315         }
316
317         if (name == stylus_string) {
318                 XEventClass event_list[2];
319                 if (tmp_device->num_classes > 0) {
320                         for (ip = tmp_device->classes,
321                                 i = 0; i < tmp_device->num_classes; ip++, i++) {
322                                 switch (ip->input_class) {
323
324                                 case ButtonClass:
325                                 DeviceButtonPress(tmp_device,
326                                         button_press_type, event_list[count]);
327                                 count++;
328                                 break;
329
330                                 case ValuatorClass:
331                                 ProximityIn(tmp_device,
332                                         proximity_in_type, event_list[count]);
333                                 count++;
334                                 break;
335
336                                 default:
337                                 break;
338                                 }
339                         }
340                 }
341                 if (XSelectExtensionEvent(display, root_win,
342                                         event_list, count)) {
343                         return 0;
344                 }
345                 return count;
346         }
347         return 0;
348 }
349
350 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
351  Find next empty element in the pad-array:
352  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
353
354 static int count_pad(int model)
355 {
356         int i;
357         for (i = 0; i < MAXPAD; i++) {
358                 if (!pad_xdevice[model][i]) {
359                         break;
360                 }
361         }
362         return i;
363 }
364
365 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
366  Find next empty element in the stylus-array:
367  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
368
369 static int count_stylus(int model)
370 {
371         int i, j;
372         pad_num = 0;
373
374         for (j = 0; j < MAXPAD && pad_num == 0; j++) {
375                 for (i = 0; i < MAXSTYLUS; i++) {
376                         if (!stylus_xdevice[i][model * MAXPAD + j]) {
377                                 pad_num = 1;
378                                 break;
379                         }
380                 }
381         }
382         pad_num = model * MAXPAD + --j;
383         return i;
384 }
385
386 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
387  Open a pad-device and start collecting data:
388  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
389
390 static void follow_pad(XDeviceInfo* xdevice_list, int number)
391 {
392         int model;
393
394         if ((tmp_device = XOpenDevice(display, xdevice_list[number].id))) {
395                 if (register_events(pad_string)) {
396                         model = identify_device(xdevice_list[number].name);
397                         pad_num = count_pad(model);
398                         if (pad_num < MAXPAD) {
399                                 pad_xdevice[model][pad_num] = tmp_device;
400                                 pad_id[model][pad_num] = &tmp_device->device_id;
401                                 pad_name[model][pad_num] = xdevice_list[number]
402                                                                         .name;
403                                 have_pad = 1;
404                         } else {
405                                 XFree(tmp_device);
406                         }
407                 }
408         }
409
410 }
411
412 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
413  Open a stylus-device and start collecting data:
414  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
415
416 static void follow_stylus(XDeviceInfo* xdevice_list, int number)
417 {
418         int i;
419         int model;
420
421         XValuatorInfoPtr valuator;
422         XAnyClassPtr anyclass;
423
424         if ((tmp_device = XOpenDevice(display, xdevice_list[number].id))) {
425                 if (register_events(stylus_string)) {
426                         model = identify_device(xdevice_list[number].name);
427                         stylus_num = count_stylus(model);
428                         if ((pad_num < model * MAXPAD + MAXPAD)
429                         && (stylus_num < MAXSTYLUS)) {
430                                 stylus_xdevice[stylus_num][pad_num]= tmp_device;
431                                 stylus_id[stylus_num][pad_num] =
432                                                         &tmp_device->device_id;
433                                 stylus_name[stylus_num][pad_num] =
434                                                 xdevice_list[number].name;
435                                 anyclass = (XAnyClassPtr)
436                                         (xdevice_list[number].inputclassinfo);
437                                 for (i = 0; i < xdevice_list[number]
438                                                         .num_classes; i++) {
439                                         if (anyclass->class == ValuatorClass) {
440                                                 valuator =
441                                                 (XValuatorInfoPtr)anyclass;
442                                                 stylus_mode[stylus_num][pad_num]
443                                                         = &valuator->mode;
444                                         }
445                                         anyclass = (XAnyClassPtr)
446                                         ((char*)anyclass + anyclass->length);
447                                 }
448                         } else {
449                                 XFree(tmp_device);
450                         }
451                 }
452         }
453
454 }
455
456 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
457  First processing of an extension-device's name-string:
458  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
459
460 static int check_name(char* read_buffer, char* write_buffer, int len)
461 {
462         int i;
463
464         if (len >= MAXBUFFER) {
465                 len = MAXBUFFER - 1;
466         }
467
468         for (i = 0; i < len; i++) {
469                 write_buffer[i] = tolower(read_buffer[i]);
470         }
471         write_buffer[i] = '\0';
472
473         if ((strstr(write_buffer, pad_string) !=NULL)
474                 || (strstr(write_buffer, stylus_string) !=NULL)) {
475                 return 1;
476         }
477         return 0;
478
479 }
480
481 /* newer Xorg servers changed the "use" field on the list of input devices */
482 #ifdef IsXExtensionKeyboard
483 #define EXTENSION_DEVICE IsXExtensionKeyboard
484 #else
485 #define EXTENSION_DEVICE IsXExtensionDevice
486 #endif
487
488 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
489  Find all extension-devices containing the strings 'pad'/'stylus'. If the
490  user has specified which pad/stylus(es) to use on the command line, we
491  ignore all others:
492  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
493
494 void get_device_info()
495 {
496         int i;
497         int len;
498         int found;
499         int nr_devices;
500
501         char read_buffer[MAXBUFFER];
502         char write_buffer[MAXBUFFER];
503
504         const char* user_dummy = "not_specified";
505         if ((user_pad) || (user_stylus1)) {
506                 if (user_pad) {
507                         pad_string = user_pad;
508                 } else {
509                         pad_string = user_dummy;
510                 }
511                 if (user_stylus1) {
512                         stylus_string = user_stylus1;
513                 } else {
514                         stylus_string = user_dummy;
515                 }
516         }
517
518         xdevice_list = XListInputDevices(display, &nr_devices);
519
520         for(i = 0; i < nr_devices; i++) {
521                 if (xdevice_list[i].use == EXTENSION_DEVICE) {
522                         len = strlen(xdevice_list[i].name);
523                         snprintf(read_buffer, MAXBUFFER, "%s", xdevice_list[i]
524                                                                         .name);
525                         if (check_name(read_buffer, write_buffer, len)) {
526                                 found = 0;
527                                 if (user_pad) {
528                                         if (strcmp(read_buffer, pad_string)
529                                                                         == 0) {
530                                                 found = 1;
531                                         }
532                                 } else if (strstr(write_buffer, pad_string)) {
533                                         found = 1;
534                                 }
535                                 if ((strstr(write_buffer, pad_string))
536                                                                 && (found)) {
537                                         follow_pad(xdevice_list, i);
538                                 }
539                                 if (user_stylus1) {
540                                         if (strcmp(read_buffer, stylus_string)
541                                                                         == 0) {
542                                                 found = 1;
543                                         }
544                                 } else if (strstr(write_buffer,
545                                                         stylus_string)) {
546                                         found = 1;
547                                 }
548                                 if ((strstr(write_buffer, stylus_string))
549                                                                 && (found)) {
550                                         follow_stylus(xdevice_list, i);
551                                         if (user_stylus2) {
552                                                 stylus_string = user_stylus2;
553                                         }
554                                 }
555                         }
556                 }
557         }
558
559 }
560
561 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
562  Compare device names specified on the command line with found devices:
563  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
564
565 void check_user(FILE* errorfp)
566 {
567         int userpad = 0;
568         int userstylus1 = 0;
569         int userstylus2 = 0;
570
571         int i, j;
572
573         if (user_pad) {
574                 for (i = 0; i < MAXMODEL && userpad == 0; i++) {
575                         for (j = 0; j < MAXPAD; j++) {
576                                 if (pad_name[i][j]) {
577                                         if (strcmp(user_pad,
578                                                         pad_name[i][j]) == 0) {
579                                                 userpad = 1;
580                                                 break;
581                                         }
582                                 }
583                         }
584                 }
585                 if (!userpad) {
586                         exit_on_error(errorfp,
587                         "\n%s ERROR: User named device \"%s\" not found!\n",
588                                                 our_prog_name, user_pad);
589                 }
590         }
591
592         if (user_stylus1) {
593                 for (i = 0; i < MAXSTYLUS && userstylus1 == 0; i++) {
594                         for (j = 0; j < MAXMODEL * MAXPAD; j++){
595                                 if (stylus_name[i][j]) {
596                                         if (strcmp(user_stylus1,
597                                                 stylus_name[i][j]) == 0) {
598                                                 userstylus1 = 1;
599                                                 break;
600                                         }
601                                 }
602                         }
603                 }
604                 if (!userstylus1) {
605                         exit_on_error(errorfp,
606                         "\n%s ERROR: User named device \"%s\" not found!\n",
607                                                 our_prog_name, user_stylus1);
608                 }
609         }
610
611         if (user_stylus2) {
612                 for (i = 0; i < MAXSTYLUS && userstylus2 == 0; i++) {
613                         for (j = 0; j < MAXMODEL * MAXPAD; j++){
614                                 if (stylus_name[i][j]) {
615                                         if (strcmp(user_stylus2,
616                                                 stylus_name[i][j]) == 0) {
617                                                 userstylus2 = 1;
618                                                 break;
619                                         }
620                                 }
621                         }
622                 }
623                 if (!userstylus2) {
624                         exit_on_error(errorfp,
625                         "\n%s ERROR: User named device \"%s\" not found!\n",
626                                                 our_prog_name, user_stylus2);
627                 }
628         }
629
630 }
631
632 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
633  XListInputDevices doesn't provide the devices in a predictable order, so the
634  stylus array could be out of 'sync' with reality. For example, one tablet
635  might get two styli, while another tablet of the same model gets none.
636  The crude heuristics used below is: "If the next tablet of this model has
637  an empty 'slot' zero, and the previous tablet more than 'slot' zero occupied,
638  transfer the last stylus from the previous tablet to the next tablet". The
639  user can also list the styli differently in xorg.conf to correct errors:
640  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
641
642 void shuffle_styli()
643 {
644         int i, j;
645
646         for (i = MAXSTYLUS - 1; i < MAXSTYLUS; i++) {
647                 for (j = 0; j < MAXMODEL * MAXPAD; j++){
648                         if (stylus_xdevice[i][j]) {
649                                 if (((j+1)-((j/MAXPAD)*MAXPAD)) < MAXPAD) {
650                                         if ((pad_xdevice[j/MAXPAD][(j+1)-
651                                                         ((j/MAXPAD)*MAXPAD)])
652                                                 && (!stylus_xdevice[0][j+1])) {
653                                                 stylus_xdevice[0][j+1]
654                                                         = stylus_xdevice[i][j];
655                                                 stylus_xdevice[i][j] = NULL;
656                                                 stylus_id[0][j+1]
657                                                         = stylus_id[i][j];
658                                                 stylus_id[i][j] = NULL;
659                                                 stylus_name[0][j+1]
660                                                         = stylus_name[i][j];
661                                                 stylus_name[i][j] = NULL;
662                                                 stylus_mode[0][j+1]
663                                                         = stylus_mode[i][j];
664                                                 stylus_mode[i][j] = NULL;
665                                         }
666                                 }
667                         }
668                 }
669         }
670
671 }
672
673 /* End Code */
674