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