msi: Use BS_GROUPBOX for group boxes.
[wine] / dlls / winex11.drv / wintab.c
1 /*
2  * X11 tablet driver
3  *
4  * Copyright 2003 CodeWeavers (Aric Stewart)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "x11drv.h"
31 #include "wine/library.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34 #include "wintab.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
37
38 #define WT_MAX_NAME_LEN 256
39
40 typedef struct tagWTI_CURSORS_INFO
41 {
42     WCHAR   NAME[WT_MAX_NAME_LEN];
43         /* a displayable zero-terminated string containing the name of the
44          * cursor.
45          */
46     BOOL    ACTIVE;
47         /* whether the cursor is currently connected. */
48     WTPKT   PKTDATA;
49         /* a bit mask indicating the packet data items supported when this
50          * cursor is connected.
51          */
52     BYTE    BUTTONS;
53         /* the number of buttons on this cursor. */
54     BYTE    BUTTONBITS;
55         /* the number of bits of raw button data returned by the hardware.*/
56     DWORD   cchBTNNAMES;
57     WCHAR   *BTNNAMES;
58         /* a list of zero-terminated strings containing the names of the
59          * cursor's buttons. The number of names in the list is the same as the
60          * number of buttons on the cursor. The names are separated by a single
61          * zero character; the list is terminated by two zero characters.
62          */
63     BYTE    BUTTONMAP[32];
64         /* a 32 byte array of logical button numbers, one for each physical
65          * button.
66          */
67     BYTE    SYSBTNMAP[32];
68         /* a 32 byte array of button action codes, one for each logical
69          * button.
70          */
71     BYTE    NPBUTTON;
72         /* the physical button number of the button that is controlled by normal
73          * pressure.
74          */
75     UINT    NPBTNMARKS[2];
76         /* an array of two UINTs, specifying the button marks for the normal
77          * pressure button. The first UINT contains the release mark; the second
78          * contains the press mark.
79          */
80     UINT    *NPRESPONSE;
81         /* an array of UINTs describing the pressure response curve for normal
82          * pressure.
83          */
84     BYTE    TPBUTTON;
85         /* the physical button number of the button that is controlled by
86          * tangential pressure.
87          */
88     UINT    TPBTNMARKS[2];
89         /* an array of two UINTs, specifying the button marks for the tangential
90          * pressure button. The first UINT contains the release mark; the second
91          * contains the press mark.
92          */
93     UINT    *TPRESPONSE;
94         /* an array of UINTs describing the pressure response curve for
95          * tangential pressure.
96          */
97     DWORD   PHYSID;
98          /* a manufacturer-specific physical identifier for the cursor. This
99           * value will distinguish the physical cursor from others on the same
100           * device. This physical identifier allows applications to bind
101           * functions to specific physical cursors, even if category numbers
102           * change and multiple, otherwise identical, physical cursors are
103           * present.
104           */
105     UINT    MODE;
106         /* the cursor mode number of this cursor type, if this cursor type has
107          * the CRC_MULTIMODE capability.
108          */
109     UINT    MINPKTDATA;
110         /* the minimum set of data available from a physical cursor in this
111          * cursor type, if this cursor type has the CRC_AGGREGATE capability.
112          */
113     UINT    MINBUTTONS;
114         /* the minimum number of buttons of physical cursors in the cursor type,
115          * if this cursor type has the CRC_AGGREGATE capability.
116          */
117     UINT    CAPABILITIES;
118         /* flags indicating cursor capabilities, as defined below:
119             CRC_MULTIMODE
120                 Indicates this cursor type describes one of several modes of a
121                 single physical cursor. Consecutive cursor type categories
122                 describe the modes; the CSR_MODE data item gives the mode number
123                 of each cursor type.
124             CRC_AGGREGATE
125                 Indicates this cursor type describes several physical cursors
126                 that cannot be distinguished by software.
127             CRC_INVERT
128                 Indicates this cursor type describes the physical cursor in its
129                 inverted orientation; the previous consecutive cursor type
130                 category describes the normal orientation.
131          */
132     UINT    TYPE;
133         /* Manufacturer Unique id for the item type */
134 } WTI_CURSORS_INFO, *LPWTI_CURSORS_INFO;
135
136
137 typedef struct tagWTI_DEVICES_INFO
138 {
139     WCHAR   NAME[WT_MAX_NAME_LEN];
140         /* a displayable null- terminated string describing the device,
141          * manufacturer, and revision level.
142          */
143     UINT    HARDWARE;
144         /* flags indicating hardware and driver capabilities, as defined
145          * below:
146             HWC_INTEGRATED:
147                 Indicates that the display and digitizer share the same surface.
148             HWC_TOUCH
149                 Indicates that the cursor must be in physical contact with the
150                 device to report position.
151             HWC_HARDPROX
152                 Indicates that device can generate events when the cursor is
153                 entering and leaving the physical detection range.
154             HWC_PHYSID_CURSORS
155                 Indicates that device can uniquely identify the active cursor in
156                 hardware.
157          */
158     UINT    NCSRTYPES;
159         /* the number of supported cursor types.*/
160     UINT    FIRSTCSR;
161         /* the first cursor type number for the device. */
162     UINT    PKTRATE;
163         /* the maximum packet report rate in Hertz. */
164     WTPKT   PKTDATA;
165         /* a bit mask indicating which packet data items are always available.*/
166     WTPKT   PKTMODE;
167         /* a bit mask indicating which packet data items are physically
168          * relative, i.e., items for which the hardware can only report change,
169          * not absolute measurement.
170          */
171     WTPKT   CSRDATA;
172         /* a bit mask indicating which packet data items are only available when
173          * certain cursors are connected. The individual cursor descriptions
174          * must be consulted to determine which cursors return which data.
175          */
176     INT     XMARGIN;
177     INT     YMARGIN;
178     INT     ZMARGIN;
179         /* the size of tablet context margins in tablet native coordinates, in
180          * the x, y, and z directions, respectively.
181          */
182     AXIS    X;
183     AXIS    Y;
184     AXIS    Z;
185         /* the tablet's range and resolution capabilities, in the x, y, and z
186          * axes, respectively.
187          */
188     AXIS    NPRESSURE;
189     AXIS    TPRESSURE;
190         /* the tablet's range and resolution capabilities, for the normal and
191          * tangential pressure inputs, respectively.
192          */
193     AXIS    ORIENTATION[3];
194         /* a 3-element array describing the tablet's orientation range and
195          * resolution capabilities.
196          */
197     AXIS    ROTATION[3];
198         /* a 3-element array describing the tablet's rotation range and
199          * resolution capabilities.
200          */
201     WCHAR   PNPID[WT_MAX_NAME_LEN];
202         /* a null-terminated string containing the devices Plug and Play ID.*/
203 }   WTI_DEVICES_INFO, *LPWTI_DEVICES_INFO;
204
205 typedef struct tagWTPACKET {
206         HCTX pkContext;
207         UINT pkStatus;
208         LONG pkTime;
209         WTPKT pkChanged;
210         UINT pkSerialNumber;
211         UINT pkCursor;
212         DWORD pkButtons;
213         DWORD pkX;
214         DWORD pkY;
215         DWORD pkZ;
216         UINT pkNormalPressure;
217         UINT pkTangentPressure;
218         ORIENTATION pkOrientation;
219         ROTATION pkRotation; /* 1.1 */
220 } WTPACKET, *LPWTPACKET;
221
222
223 #ifdef SONAME_LIBXI
224
225 #include <X11/Xlib.h>
226 #include <X11/extensions/XInput.h>
227
228 static int           motion_type;
229 static int           button_press_type;
230 static int           button_release_type;
231 static int           key_press_type;
232 static int           key_release_type;
233 static int           proximity_in_type;
234 static int           proximity_out_type;
235
236 static HWND          hwndTabletDefault;
237 static WTPACKET      gMsgPacket;
238 static DWORD         gSerial;
239 static INT           button_state[10];
240
241 #define             CURSORMAX 10
242
243 static LOGCONTEXTW      gSysContext;
244 static WTI_DEVICES_INFO gSysDevice;
245 static WTI_CURSORS_INFO gSysCursor[CURSORMAX];
246 static INT              gNumCursors;
247
248
249 /* XInput stuff */
250 static void *xinput_handle;
251
252 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
253 MAKE_FUNCPTR(XListInputDevices)
254 MAKE_FUNCPTR(XFreeDeviceList)
255 MAKE_FUNCPTR(XOpenDevice)
256 MAKE_FUNCPTR(XQueryDeviceState)
257 MAKE_FUNCPTR(XGetDeviceButtonMapping)
258 MAKE_FUNCPTR(XCloseDevice)
259 MAKE_FUNCPTR(XSelectExtensionEvent)
260 MAKE_FUNCPTR(XFreeDeviceState)
261 #undef MAKE_FUNCPTR
262
263 static INT X11DRV_XInput_Init(void)
264 {
265     xinput_handle = wine_dlopen(SONAME_LIBXI, RTLD_NOW, NULL, 0);
266     if (xinput_handle)
267     {
268 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xinput_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
269         LOAD_FUNCPTR(XListInputDevices)
270         LOAD_FUNCPTR(XFreeDeviceList)
271         LOAD_FUNCPTR(XOpenDevice)
272         LOAD_FUNCPTR(XGetDeviceButtonMapping)
273         LOAD_FUNCPTR(XCloseDevice)
274         LOAD_FUNCPTR(XSelectExtensionEvent)
275         LOAD_FUNCPTR(XQueryDeviceState)
276         LOAD_FUNCPTR(XFreeDeviceState)
277 #undef LOAD_FUNCPTR
278         return 1;
279     }
280 sym_not_found:
281     return 0;
282 }
283
284 static int Tablet_ErrorHandler(Display *dpy, XErrorEvent *event, void* arg)
285 {
286     return 1;
287 }
288
289 void X11DRV_LoadTabletInfo(HWND hwnddefault)
290 {
291     const WCHAR SZ_CONTEXT_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
292     const WCHAR SZ_DEVICE_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
293     const WCHAR SZ_NON_PLUGINPLAY[] = {'n','o','n','-','p','l','u','g','i','n','p','l','a','y',0};
294
295     struct x11drv_thread_data *data = x11drv_thread_data();
296     int num_devices;
297     int loop;
298     int cursor_target;
299     XDeviceInfo *devices;
300     XDeviceInfo *target = NULL;
301     BOOL    axis_read_complete= FALSE;
302
303     XAnyClassPtr        any;
304     XButtonInfoPtr      Button;
305     XValuatorInfoPtr    Val;
306     XAxisInfoPtr        Axis;
307
308     XDevice *opendevice;
309
310     if (!X11DRV_XInput_Init())
311     {
312         ERR("Unable to initialized the XInput library.\n");
313         return;
314     }
315
316     hwndTabletDefault = hwnddefault;
317
318     /* Do base initializaion */
319     strcpyW(gSysContext.lcName, SZ_CONTEXT_NAME);
320     strcpyW(gSysDevice.NAME, SZ_DEVICE_NAME);
321
322     gSysContext.lcOptions = CXO_SYSTEM;
323     gSysContext.lcLocks = CXL_INSIZE | CXL_INASPECT | CXL_MARGIN |
324                                CXL_SENSITIVITY | CXL_SYSOUT;
325
326     gSysContext.lcMsgBase= WT_DEFBASE;
327     gSysContext.lcDevice = 0;
328     gSysContext.lcPktData =
329         PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR |
330         PK_BUTTONS |  PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
331     gSysContext.lcMoveMask=
332         PK_BUTTONS |  PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
333     gSysContext.lcStatus = CXS_ONTOP;
334     gSysContext.lcPktRate = 100;
335     gSysContext.lcBtnDnMask = 0xffffffff;
336     gSysContext.lcBtnUpMask = 0xffffffff;
337     gSysContext.lcSensX = 65536;
338     gSysContext.lcSensY = 65536;
339     gSysContext.lcSensX = 65536;
340     gSysContext.lcSensZ = 65536;
341     gSysContext.lcSysSensX= 65536;
342     gSysContext.lcSysSensY= 65536;
343
344     /* Device Defaults */
345     gSysDevice.HARDWARE = HWC_HARDPROX|HWC_PHYSID_CURSORS;
346     gSysDevice.FIRSTCSR= 0;
347     gSysDevice.PKTRATE = 100;
348     gSysDevice.PKTDATA =
349         PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR |
350         PK_BUTTONS |  PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
351     strcpyW(gSysDevice.PNPID, SZ_NON_PLUGINPLAY);
352
353     wine_tsx11_lock();
354
355     cursor_target = -1;
356     devices = pXListInputDevices(data->display, &num_devices);
357     if (!devices)
358     {
359         WARN("XInput Extenstions reported as not avalable\n");
360         wine_tsx11_unlock();
361         return;
362     }
363     for (loop=0; loop < num_devices; loop++)
364     {
365         int class_loop;
366
367         TRACE("Trying device %i(%s)\n",loop,devices[loop].name);
368         if (devices[loop].use == IsXExtensionDevice)
369         {
370             LPWTI_CURSORS_INFO cursor;
371
372             TRACE("Is Extension Device\n");
373             cursor_target++;
374             target = &devices[loop];
375             cursor = &gSysCursor[cursor_target];
376
377             if (strlen(target->name) >= WT_MAX_NAME_LEN)
378             {
379                 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target->name));
380                 cursor_target--;
381                 continue;
382             }
383
384             X11DRV_expect_error(data->display, Tablet_ErrorHandler, NULL);
385             opendevice = pXOpenDevice(data->display,target->id);
386             if (!X11DRV_check_error() && opendevice)
387             {
388                 unsigned char map[32];
389                 int i;
390                 int shft = 0;
391
392                 X11DRV_expect_error(data->display,Tablet_ErrorHandler,NULL);
393                 pXGetDeviceButtonMapping(data->display, opendevice, map, 32);
394                 if (X11DRV_check_error())
395                 {
396                     TRACE("No buttons, Non Tablet Device\n");
397                     pXCloseDevice(data->display, opendevice);
398                     cursor_target --;
399                     continue;
400                 }
401
402                 for (i=0; i< cursor->BUTTONS; i++,shft++)
403                 {
404                     cursor->BUTTONMAP[i] = map[i];
405                     cursor->SYSBTNMAP[i] = (1<<shft);
406                 }
407                 pXCloseDevice(data->display, opendevice);
408             }
409             else
410             {
411                 WARN("Unable to open device %s\n",target->name);
412                 cursor_target --;
413                 continue;
414             }
415             MultiByteToWideChar(CP_UNIXCP, 0, target->name, -1, cursor->NAME, WT_MAX_NAME_LEN);
416
417             cursor->ACTIVE = 1;
418             cursor->PKTDATA = PK_TIME | PK_CURSOR | PK_BUTTONS |  PK_X | PK_Y |
419                               PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE |
420                               PK_ORIENTATION;
421
422             cursor->PHYSID = cursor_target;
423             cursor->NPBUTTON = 1;
424             cursor->NPBTNMARKS[0] = 0 ;
425             cursor->NPBTNMARKS[1] = 1 ;
426             cursor->CAPABILITIES = CRC_MULTIMODE;
427             if (strcasecmp(target->name,"stylus")==0)
428                 cursor->TYPE = 0x4825;
429             if (strcasecmp(target->name,"eraser")==0)
430                 cursor->TYPE = 0xc85a;
431
432
433             any = (XAnyClassPtr) (target->inputclassinfo);
434
435             for (class_loop = 0; class_loop < target->num_classes; class_loop++)
436             {
437                 switch (any->class)
438                 {
439                     case ValuatorClass:
440                         if (!axis_read_complete)
441                         {
442                             Val = (XValuatorInfoPtr) any;
443                             Axis = (XAxisInfoPtr) ((char *) Val + sizeof
444                                 (XValuatorInfo));
445
446                             if (Val->num_axes>=1)
447                             {
448                                 /* Axis 1 is X */
449                                 gSysDevice.X.axMin = Axis->min_value;
450                                 gSysDevice.X.axMax= Axis->max_value;
451                                 gSysDevice.X.axUnits = TU_INCHES;
452                                 gSysDevice.X.axResolution = Axis->resolution;
453                                 gSysContext.lcInOrgX = Axis->min_value;
454                                 gSysContext.lcSysOrgX = Axis->min_value;
455                                 gSysContext.lcInExtX = Axis->max_value;
456                                 gSysContext.lcSysExtX = Axis->max_value;
457                                 Axis++;
458                             }
459                             if (Val->num_axes>=2)
460                             {
461                                 /* Axis 2 is Y */
462                                 gSysDevice.Y.axMin = Axis->min_value;
463                                 gSysDevice.Y.axMax= Axis->max_value;
464                                 gSysDevice.Y.axUnits = TU_INCHES;
465                                 gSysDevice.Y.axResolution = Axis->resolution;
466                                 gSysContext.lcInOrgY = Axis->min_value;
467                                 gSysContext.lcSysOrgY = Axis->min_value;
468                                 gSysContext.lcInExtY = Axis->max_value;
469                                 gSysContext.lcSysExtY = Axis->max_value;
470                                 Axis++;
471                             }
472                             if (Val->num_axes>=3)
473                             {
474                                 /* Axis 3 is Normal Pressure */
475                                 gSysDevice.NPRESSURE.axMin = Axis->min_value;
476                                 gSysDevice.NPRESSURE.axMax= Axis->max_value;
477                                 gSysDevice.NPRESSURE.axUnits = TU_INCHES;
478                                 gSysDevice.NPRESSURE.axResolution =
479                                                         Axis->resolution;
480                                 Axis++;
481                             }
482                             if (Val->num_axes >= 5)
483                             {
484                                 /* Axis 4 and 5 are X and Y tilt */
485                                 XAxisInfoPtr        XAxis = Axis;
486                                 Axis++;
487                                 if (max (abs(Axis->max_value),
488                                          abs(XAxis->max_value)))
489                                 {
490                                     gSysDevice.ORIENTATION[0].axMin = 0;
491                                     gSysDevice.ORIENTATION[0].axMax = 3600;
492                                     gSysDevice.ORIENTATION[0].axUnits = TU_CIRCLE;
493                                     gSysDevice.ORIENTATION[0].axResolution
494                                                                 = CASTFIX32(3600);
495                                     gSysDevice.ORIENTATION[1].axMin = -1000;
496                                     gSysDevice.ORIENTATION[1].axMax = 1000;
497                                     gSysDevice.ORIENTATION[1].axUnits = TU_CIRCLE;
498                                     gSysDevice.ORIENTATION[1].axResolution
499                                                                 = CASTFIX32(3600);
500                                     Axis++;
501                                 }
502                             }
503                             axis_read_complete = TRUE;
504                         }
505                         break;
506                     case ButtonClass:
507                     {
508                         int cchBuf = 512;
509                         int cchPos = 0;
510                         int i;
511
512                         Button = (XButtonInfoPtr) any;
513                         cursor->BUTTONS = Button->num_buttons;
514                         cursor->BTNNAMES = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*cchBuf);
515                         for (i = 0; i < cursor->BUTTONS; i++)
516                         {
517                             /* FIXME - these names are probably incorrect */
518                             int cch = strlenW(cursor->NAME) + 1;
519                             while (cch > cchBuf - cchPos - 1) /* we want one extra byte for the last NUL */
520                             {
521                                 cchBuf *= 2;
522                                 cursor->BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor->BTNNAMES, sizeof(WCHAR)*cchBuf);
523                             }
524
525                             strcpyW(cursor->BTNNAMES + cchPos, cursor->NAME);
526                             cchPos += cch;
527                         }
528                         cursor->BTNNAMES[cchPos++] = 0;
529                         cursor->BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor->BTNNAMES, sizeof(WCHAR)*cchPos);
530                         cursor->cchBTNNAMES = cchPos;
531                     }
532                     break;
533                 }
534                 any = (XAnyClassPtr) ((char*) any + any->length);
535             }
536         }
537     }
538     pXFreeDeviceList(devices);
539     wine_tsx11_unlock();
540     gSysDevice.NCSRTYPES = cursor_target+1;
541     gNumCursors = cursor_target+1;
542 }
543
544 static int figure_deg(int x, int y)
545 {
546     int rc;
547
548     if (y != 0)
549     {
550         rc = (int) 10 * (atan( (FLOAT)abs(y) / (FLOAT)abs(x)) / (3.1415 / 180));
551         if (y>0)
552         {
553             if (x>0)
554                 rc += 900;
555             else
556                 rc = 2700 - rc;
557         }
558         else
559         {
560             if (x>0)
561                 rc = 900 - rc;
562             else
563                 rc += 2700;
564         }
565     }
566     else
567     {
568         if (x >= 0)
569             rc = 900;
570         else
571             rc = 2700;
572     }
573
574     return rc;
575 }
576
577 static int get_button_state(int deviceid)
578 {
579     return button_state[deviceid];
580 }
581
582 static void set_button_state(XID deviceid)
583 {
584     struct x11drv_thread_data *data = x11drv_thread_data();
585     XDevice *device;
586     XDeviceState *state;
587     XInputClass  *class;
588     int loop;
589     int rc = 0;
590
591     wine_tsx11_lock();
592     device = pXOpenDevice(data->display,deviceid);
593     state = pXQueryDeviceState(data->display,device);
594
595     if (state)
596     {
597         class = state->data;
598         for (loop = 0; loop < state->num_classes; loop++)
599         {
600             if (class->class == ButtonClass)
601             {
602                 int loop2;
603                 XButtonState *button_state =  (XButtonState*)class;
604                 for (loop2 = 0; loop2 < button_state->num_buttons; loop2++)
605                 {
606                     if (button_state->buttons[loop2 / 8] & (1 << (loop2 % 8)))
607                     {
608                         rc |= (1<<loop2);
609                     }
610                 }
611             }
612             class = (XInputClass *) ((char *) class + class->length);
613         }
614     }
615     pXFreeDeviceState(state);
616     wine_tsx11_unlock();
617     button_state[deviceid] = rc;
618 }
619
620 static void motion_event( HWND hwnd, XEvent *event )
621 {
622     XDeviceMotionEvent *motion = (XDeviceMotionEvent *)event;
623     LPWTI_CURSORS_INFO cursor = &gSysCursor[motion->deviceid];
624
625     memset(&gMsgPacket,0,sizeof(WTPACKET));
626
627     TRACE("Received tablet motion event (%p)\n",hwnd);
628
629     /* Set cursor to inverted if cursor is the eraser */
630     gMsgPacket.pkStatus = (cursor->TYPE == 0xc85a ?TPS_INVERT:0);
631     gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(motion->time);
632     gMsgPacket.pkSerialNumber = gSerial++;
633     gMsgPacket.pkCursor = motion->deviceid;
634     gMsgPacket.pkX = motion->axis_data[0];
635     gMsgPacket.pkY = motion->axis_data[1];
636     gMsgPacket.pkOrientation.orAzimuth = figure_deg(motion->axis_data[3],motion->axis_data[4]);
637     gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max
638                                             (abs(motion->axis_data[3]),
639                                              abs(motion->axis_data[4])))
640                                            * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
641     gMsgPacket.pkNormalPressure = motion->axis_data[2];
642     gMsgPacket.pkButtons = get_button_state(motion->deviceid);
643     SendMessageW(hwndTabletDefault,WT_PACKET,0,(LPARAM)hwnd);
644 }
645
646 static void button_event( HWND hwnd, XEvent *event )
647 {
648     XDeviceButtonEvent *button = (XDeviceButtonEvent *) event;
649     LPWTI_CURSORS_INFO cursor = &gSysCursor[button->deviceid];
650
651     memset(&gMsgPacket,0,sizeof(WTPACKET));
652
653     TRACE("Received tablet button %s event\n", (event->type == button_press_type)?"press":"release");
654
655     /* Set cursor to inverted if cursor is the eraser */
656     gMsgPacket.pkStatus = (cursor->TYPE == 0xc85a ?TPS_INVERT:0);
657     set_button_state(button->deviceid);
658     gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(button->time);
659     gMsgPacket.pkSerialNumber = gSerial++;
660     gMsgPacket.pkCursor = button->deviceid;
661     gMsgPacket.pkX = button->axis_data[0];
662     gMsgPacket.pkY = button->axis_data[1];
663     gMsgPacket.pkOrientation.orAzimuth = figure_deg(button->axis_data[3],button->axis_data[4]);
664     gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(button->axis_data[3]),
665                                                             abs(button->axis_data[4])))
666                                            * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
667     gMsgPacket.pkNormalPressure = button->axis_data[2];
668     gMsgPacket.pkButtons = get_button_state(button->deviceid);
669     SendMessageW(hwndTabletDefault,WT_PACKET,0,(LPARAM)hwnd);
670 }
671
672 static void key_event( HWND hwnd, XEvent *event )
673 {
674     if (event->type == key_press_type)
675         FIXME("Received tablet key press event\n");
676     else
677         FIXME("Received tablet key release event\n");
678 }
679
680 static void proximity_event( HWND hwnd, XEvent *event )
681 {
682     XProximityNotifyEvent *proximity = (XProximityNotifyEvent *) event;
683     LPWTI_CURSORS_INFO cursor = &gSysCursor[proximity->deviceid];
684
685     memset(&gMsgPacket,0,sizeof(WTPACKET));
686
687     TRACE("Received tablet proximity event\n");
688     /* Set cursor to inverted if cursor is the eraser */
689     gMsgPacket.pkStatus = (cursor->TYPE == 0xc85a ?TPS_INVERT:0);
690     gMsgPacket.pkStatus |= (event->type==proximity_out_type)?TPS_PROXIMITY:0;
691     gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(proximity->time);
692     gMsgPacket.pkSerialNumber = gSerial++;
693     gMsgPacket.pkCursor = proximity->deviceid;
694     gMsgPacket.pkX = proximity->axis_data[0];
695     gMsgPacket.pkY = proximity->axis_data[1];
696     gMsgPacket.pkOrientation.orAzimuth = figure_deg(proximity->axis_data[3],proximity->axis_data[4]);
697     gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(proximity->axis_data[3]),
698                                                             abs(proximity->axis_data[4])))
699                                            * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
700     gMsgPacket.pkNormalPressure = proximity->axis_data[2];
701     gMsgPacket.pkButtons = get_button_state(proximity->deviceid);
702
703     SendMessageW(hwndTabletDefault, WT_PROXIMITY, (event->type == proximity_in_type), (LPARAM)hwnd);
704 }
705
706 int X11DRV_AttachEventQueueToTablet(HWND hOwner)
707 {
708     struct x11drv_thread_data *data = x11drv_thread_data();
709     int             num_devices;
710     int             loop;
711     int             cur_loop;
712     XDeviceInfo     *devices;
713     XDeviceInfo     *target = NULL;
714     XDevice         *the_device;
715     XEventClass     event_list[7];
716     Window          win = X11DRV_get_whole_window( hOwner );
717
718     if (!win) return 0;
719
720     TRACE("Creating context for window %p (%lx)  %i cursors\n", hOwner, win, gNumCursors);
721
722     wine_tsx11_lock();
723     devices = pXListInputDevices(data->display, &num_devices);
724
725     X11DRV_expect_error(data->display,Tablet_ErrorHandler,NULL);
726     for (cur_loop=0; cur_loop < gNumCursors; cur_loop++)
727     {
728         char   cursorNameA[WT_MAX_NAME_LEN];
729         int    event_number=0;
730
731         /* the cursor name fits in the buffer because too long names are skipped */
732         WideCharToMultiByte(CP_UNIXCP, 0, gSysCursor[cur_loop].NAME, -1, cursorNameA, WT_MAX_NAME_LEN, NULL, NULL);
733         for (loop=0; loop < num_devices; loop ++)
734             if (strcmp(devices[loop].name, cursorNameA) == 0)
735                 target = &devices[loop];
736
737         TRACE("Opening cursor %i id %i\n",cur_loop,(INT)target->id);
738
739         the_device = pXOpenDevice(data->display, target->id);
740
741         if (!the_device)
742         {
743             WARN("Unable to Open device\n");
744             continue;
745         }
746
747         if (the_device->num_classes > 0)
748         {
749             DeviceKeyPress(the_device, key_press_type, event_list[event_number]);
750             if (event_list[event_number]) event_number++;
751             DeviceKeyRelease(the_device, key_release_type, event_list[event_number]);
752             if (event_list[event_number]) event_number++;
753             DeviceButtonPress(the_device, button_press_type, event_list[event_number]);
754             if (event_list[event_number]) event_number++;
755             DeviceButtonRelease(the_device, button_release_type, event_list[event_number]);
756             if (event_list[event_number]) event_number++;
757             DeviceMotionNotify(the_device, motion_type, event_list[event_number]);
758             if (event_list[event_number]) event_number++;
759             ProximityIn(the_device, proximity_in_type, event_list[event_number]);
760             if (event_list[event_number]) event_number++;
761             ProximityOut(the_device, proximity_out_type, event_list[event_number]);
762             if (event_list[event_number]) event_number++;
763
764             if (key_press_type) X11DRV_register_event_handler( key_press_type, key_event );
765             if (key_release_type) X11DRV_register_event_handler( key_release_type, key_event );
766             if (button_press_type) X11DRV_register_event_handler( button_press_type, button_event );
767             if (button_release_type) X11DRV_register_event_handler( button_release_type, button_event );
768             if (motion_type) X11DRV_register_event_handler( motion_type, motion_event );
769             if (proximity_in_type) X11DRV_register_event_handler( proximity_in_type, proximity_event );
770             if (proximity_out_type) X11DRV_register_event_handler( proximity_out_type, proximity_event );
771
772             pXSelectExtensionEvent(data->display, win, event_list, event_number);
773         }
774     }
775     XSync(data->display, False);
776     X11DRV_check_error();
777
778     if (NULL != devices) pXFreeDeviceList(devices);
779     wine_tsx11_unlock();
780     return 0;
781 }
782
783 int X11DRV_GetCurrentPacket(LPWTPACKET *packet)
784 {
785     memcpy(packet,&gMsgPacket,sizeof(WTPACKET));
786     return 1;
787 }
788
789
790 static inline int CopyTabletData(LPVOID target, LPCVOID src, INT size)
791 {
792     /*
793      * It is valid to call CopyTabletData with NULL.
794      * This handles the WTInfo() case where lpOutput is null.
795      */
796     if(target != NULL)
797         memcpy(target,src,size);
798     return(size);
799 }
800
801 /***********************************************************************
802  *              X11DRV_WTInfoW (X11DRV.@)
803  */
804 UINT X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
805 {
806     /*
807      * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
808      * lpOutput == NULL signifies the user only wishes
809      * to find the size of the data.
810      * NOTE:
811      * From now on use CopyTabletData to fill lpOutput. memcpy will break
812      * the code.
813      */
814     int rc = 0;
815     LPWTI_CURSORS_INFO  tgtcursor;
816     TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput);
817
818     switch(wCategory)
819     {
820         case 0:
821             /* return largest necessary buffer */
822             TRACE("%i cursors\n",gNumCursors);
823             if (gNumCursors>0)
824             {
825                 FIXME("Return proper size\n");
826                 rc = 200;
827             }
828             break;
829         case WTI_INTERFACE:
830             switch (nIndex)
831             {
832                 WORD version;
833                 case IFC_WINTABID:
834                 {
835                     static const WCHAR driver[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
836                     rc = CopyTabletData(lpOutput, driver, (strlenW(driver) + 1) * sizeof(WCHAR));
837                     break;
838                 }
839                 case IFC_SPECVERSION:
840                     version = (0x01) | (0x01 << 8);
841                     rc = CopyTabletData(lpOutput, &version,sizeof(WORD));
842                     break;
843                 case IFC_IMPLVERSION:
844                     version = (0x00) | (0x01 << 8);
845                     rc = CopyTabletData(lpOutput, &version,sizeof(WORD));
846                     break;
847                 default:
848                     FIXME("WTI_INTERFACE unhandled index %i\n",nIndex);
849                     rc = 0;
850             }
851             break;
852         case WTI_DEFSYSCTX:
853         case WTI_DDCTXS:
854         case WTI_DEFCONTEXT:
855             switch (nIndex)
856             {
857                 case 0:
858                     rc = CopyTabletData(lpOutput, &gSysContext,
859                             sizeof(LOGCONTEXTW));
860                     break;
861                 case CTX_NAME:
862                     rc = CopyTabletData(lpOutput, &gSysContext.lcName,
863                          (strlenW(gSysContext.lcName)+1) * sizeof(WCHAR));
864                     break;
865                 case CTX_OPTIONS:
866                     rc = CopyTabletData(lpOutput, &gSysContext.lcOptions,
867                                         sizeof(UINT));
868                     break;
869                 case CTX_STATUS:
870                     rc = CopyTabletData(lpOutput, &gSysContext.lcStatus,
871                                         sizeof(UINT));
872                     break;
873                 case CTX_LOCKS:
874                     rc= CopyTabletData (lpOutput, &gSysContext.lcLocks,
875                                         sizeof(UINT));
876                     break;
877                 case CTX_MSGBASE:
878                     rc = CopyTabletData(lpOutput, &gSysContext.lcMsgBase,
879                                         sizeof(UINT));
880                     break;
881                 case CTX_DEVICE:
882                     rc = CopyTabletData(lpOutput, &gSysContext.lcDevice,
883                                         sizeof(UINT));
884                     break;
885                 case CTX_PKTRATE:
886                     rc = CopyTabletData(lpOutput, &gSysContext.lcPktRate,
887                                         sizeof(UINT));
888                     break;
889                 case CTX_PKTDATA:
890                     rc = CopyTabletData(lpOutput, &gSysContext.lcPktData,
891                                         sizeof(WTPKT));
892                     break;
893                 case CTX_PKTMODE:
894                     rc = CopyTabletData(lpOutput, &gSysContext.lcPktMode,
895                                         sizeof(WTPKT));
896                     break;
897                 case CTX_MOVEMASK:
898                     rc = CopyTabletData(lpOutput, &gSysContext.lcMoveMask,
899                                         sizeof(WTPKT));
900                     break;
901                 case CTX_BTNDNMASK:
902                     rc = CopyTabletData(lpOutput, &gSysContext.lcBtnDnMask,
903                                         sizeof(DWORD));
904                     break;
905                 case CTX_BTNUPMASK:
906                     rc = CopyTabletData(lpOutput, &gSysContext.lcBtnUpMask,
907                                         sizeof(DWORD));
908                     break;
909                 case CTX_INORGX:
910                     rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgX,
911                                         sizeof(LONG));
912                     break;
913                 case CTX_INORGY:
914                     rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgY,
915                                         sizeof(LONG));
916                     break;
917                 case CTX_INORGZ:
918                     rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgZ,
919                                         sizeof(LONG));
920                     break;
921                 case CTX_INEXTX:
922                     rc = CopyTabletData(lpOutput, &gSysContext.lcInExtX,
923                                         sizeof(LONG));
924                     break;
925                 case CTX_INEXTY:
926                      rc = CopyTabletData(lpOutput, &gSysContext.lcInExtY,
927                                         sizeof(LONG));
928                     break;
929                 case CTX_INEXTZ:
930                      rc = CopyTabletData(lpOutput, &gSysContext.lcInExtZ,
931                                         sizeof(LONG));
932                     break;
933                 case CTX_OUTORGX:
934                      rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgX,
935                                         sizeof(LONG));
936                     break;
937                 case CTX_OUTORGY:
938                       rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgY,
939                                         sizeof(LONG));
940                     break;
941                 case CTX_OUTORGZ:
942                        rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgZ,
943                                         sizeof(LONG));
944                     break;
945                case CTX_OUTEXTX:
946                       rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtX,
947                                         sizeof(LONG));
948                     break;
949                 case CTX_OUTEXTY:
950                        rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtY,
951                                         sizeof(LONG));
952                     break;
953                 case CTX_OUTEXTZ:
954                        rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtZ,
955                                         sizeof(LONG));
956                     break;
957                 case CTX_SENSX:
958                         rc = CopyTabletData(lpOutput, &gSysContext.lcSensX,
959                                         sizeof(LONG));
960                     break;
961                 case CTX_SENSY:
962                         rc = CopyTabletData(lpOutput, &gSysContext.lcSensY,
963                                         sizeof(LONG));
964                     break;
965                 case CTX_SENSZ:
966                         rc = CopyTabletData(lpOutput, &gSysContext.lcSensZ,
967                                         sizeof(LONG));
968                     break;
969                 case CTX_SYSMODE:
970                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysMode,
971                                         sizeof(LONG));
972                     break;
973                 case CTX_SYSORGX:
974                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgX,
975                                         sizeof(LONG));
976                     break;
977                 case CTX_SYSORGY:
978                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgY,
979                                         sizeof(LONG));
980                     break;
981                 case CTX_SYSEXTX:
982                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtX,
983                                         sizeof(LONG));
984                     break;
985                 case CTX_SYSEXTY:
986                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtY,
987                                         sizeof(LONG));
988                     break;
989                 case CTX_SYSSENSX:
990                         rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensX,
991                                         sizeof(LONG));
992                     break;
993                 case CTX_SYSSENSY:
994                        rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensY,
995                                         sizeof(LONG));
996                     break;
997                 default:
998                     FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex);
999                     rc = 0;
1000             }
1001             break;
1002         case WTI_CURSORS:
1003         case WTI_CURSORS+1:
1004         case WTI_CURSORS+2:
1005         case WTI_CURSORS+3:
1006         case WTI_CURSORS+4:
1007         case WTI_CURSORS+5:
1008         case WTI_CURSORS+6:
1009         case WTI_CURSORS+7:
1010         case WTI_CURSORS+8:
1011         case WTI_CURSORS+9:
1012             tgtcursor = &gSysCursor[wCategory - WTI_CURSORS];
1013             switch (nIndex)
1014             {
1015                 case CSR_NAME:
1016                     rc = CopyTabletData(lpOutput, &tgtcursor->NAME,
1017                                         (strlenW(tgtcursor->NAME)+1) * sizeof(WCHAR));
1018                     break;
1019                 case CSR_ACTIVE:
1020                     rc = CopyTabletData(lpOutput,&tgtcursor->ACTIVE,
1021                                         sizeof(BOOL));
1022                     break;
1023                 case CSR_PKTDATA:
1024                     rc = CopyTabletData(lpOutput,&tgtcursor->PKTDATA,
1025                                         sizeof(WTPKT));
1026                     break;
1027                 case CSR_BUTTONS:
1028                     rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONS,
1029                                         sizeof(BYTE));
1030                     break;
1031                 case CSR_BUTTONBITS:
1032                     rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONBITS,
1033                                         sizeof(BYTE));
1034                     break;
1035                 case CSR_BTNNAMES:
1036                     FIXME("Button Names not returned correctly\n");
1037                     rc = CopyTabletData(lpOutput,&tgtcursor->BTNNAMES,
1038                                         tgtcursor->cchBTNNAMES*sizeof(WCHAR));
1039                     break;
1040                 case CSR_BUTTONMAP:
1041                     rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONMAP,
1042                                         sizeof(BYTE)*32);
1043                     break;
1044                 case CSR_SYSBTNMAP:
1045                     rc = CopyTabletData(lpOutput,&tgtcursor->SYSBTNMAP,
1046                                         sizeof(BYTE)*32);
1047                     break;
1048                 case CSR_NPBTNMARKS:
1049                     rc = CopyTabletData(lpOutput,&tgtcursor->NPBTNMARKS,
1050                                         sizeof(UINT)*2);
1051                     break;
1052                 case CSR_NPBUTTON:
1053                     rc = CopyTabletData(lpOutput,&tgtcursor->NPBUTTON,
1054                                         sizeof(BYTE));
1055                     break;
1056                 case CSR_NPRESPONSE:
1057                     FIXME("Not returning CSR_NPRESPONSE correctly\n");
1058                     rc = 0;
1059                     break;
1060                 case CSR_TPBUTTON:
1061                     rc = CopyTabletData(lpOutput,&tgtcursor->TPBUTTON,
1062                                         sizeof(BYTE));
1063                     break;
1064                 case CSR_TPBTNMARKS:
1065                     rc = CopyTabletData(lpOutput,&tgtcursor->TPBTNMARKS,
1066                                         sizeof(UINT)*2);
1067                     break;
1068                 case CSR_TPRESPONSE:
1069                     FIXME("Not returning CSR_TPRESPONSE correctly\n");
1070                     rc = 0;
1071                     break;
1072                 case CSR_PHYSID:
1073                 {
1074                     DWORD id;
1075                     id = tgtcursor->PHYSID;
1076                     id += (wCategory - WTI_CURSORS);
1077                     rc = CopyTabletData(lpOutput,&id,sizeof(DWORD));
1078                 }
1079                     break;
1080                 case CSR_MODE:
1081                     rc = CopyTabletData(lpOutput,&tgtcursor->MODE,sizeof(UINT));
1082                     break;
1083                 case CSR_MINPKTDATA:
1084                     rc = CopyTabletData(lpOutput,&tgtcursor->MINPKTDATA,
1085                         sizeof(UINT));
1086                     break;
1087                 case CSR_MINBUTTONS:
1088                     rc = CopyTabletData(lpOutput,&tgtcursor->MINBUTTONS,
1089                         sizeof(UINT));
1090                     break;
1091                 case CSR_CAPABILITIES:
1092                     rc = CopyTabletData(lpOutput,&tgtcursor->CAPABILITIES,
1093                         sizeof(UINT));
1094                     break;
1095                 case CSR_TYPE:
1096                     rc = CopyTabletData(lpOutput,&tgtcursor->TYPE,
1097                         sizeof(UINT));
1098                     break;
1099                 default:
1100                     FIXME("WTI_CURSORS unhandled index %i\n",nIndex);
1101                     rc = 0;
1102             }
1103             break;
1104         case WTI_DEVICES:
1105             switch (nIndex)
1106             {
1107                 case DVC_NAME:
1108                     rc = CopyTabletData(lpOutput,gSysDevice.NAME,
1109                                         (strlenW(gSysDevice.NAME)+1) * sizeof(WCHAR));
1110                     break;
1111                 case DVC_HARDWARE:
1112                     rc = CopyTabletData(lpOutput,&gSysDevice.HARDWARE,
1113                                         sizeof(UINT));
1114                     break;
1115                 case DVC_NCSRTYPES:
1116                     rc = CopyTabletData(lpOutput,&gSysDevice.NCSRTYPES,
1117                                         sizeof(UINT));
1118                     break;
1119                 case DVC_FIRSTCSR:
1120                     rc = CopyTabletData(lpOutput,&gSysDevice.FIRSTCSR,
1121                                         sizeof(UINT));
1122                     break;
1123                 case DVC_PKTRATE:
1124                     rc = CopyTabletData(lpOutput,&gSysDevice.PKTRATE,
1125                                         sizeof(UINT));
1126                     break;
1127                 case DVC_PKTDATA:
1128                     rc = CopyTabletData(lpOutput,&gSysDevice.PKTDATA,
1129                                         sizeof(WTPKT));
1130                     break;
1131                 case DVC_PKTMODE:
1132                     rc = CopyTabletData(lpOutput,&gSysDevice.PKTMODE,
1133                                         sizeof(WTPKT));
1134                     break;
1135                 case DVC_CSRDATA:
1136                     rc = CopyTabletData(lpOutput,&gSysDevice.CSRDATA,
1137                                         sizeof(WTPKT));
1138                     break;
1139                 case DVC_XMARGIN:
1140                     rc = CopyTabletData(lpOutput,&gSysDevice.XMARGIN,
1141                                         sizeof(INT));
1142                     break;
1143                 case DVC_YMARGIN:
1144                     rc = CopyTabletData(lpOutput,&gSysDevice.YMARGIN,
1145                                         sizeof(INT));
1146                     break;
1147                 case DVC_ZMARGIN:
1148                     rc = 0; /* unsupported */
1149                     /*
1150                     rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1151                                         sizeof(INT));
1152                     */
1153                     break;
1154                 case DVC_X:
1155                     rc = CopyTabletData(lpOutput,&gSysDevice.X,
1156                                         sizeof(AXIS));
1157                     break;
1158                 case DVC_Y:
1159                     rc = CopyTabletData(lpOutput,&gSysDevice.Y,
1160                                         sizeof(AXIS));
1161                     break;
1162                 case DVC_Z:
1163                     rc = 0; /* unsupported */
1164                     /*
1165                     rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1166                                         sizeof(AXIS));
1167                     */
1168                     break;
1169                 case DVC_NPRESSURE:
1170                     rc = CopyTabletData(lpOutput,&gSysDevice.NPRESSURE,
1171                                         sizeof(AXIS));
1172                     break;
1173                 case DVC_TPRESSURE:
1174                     rc = 0; /* unsupported */
1175                     /*
1176                     rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1177                                         sizeof(AXIS));
1178                     */
1179                     break;
1180                 case DVC_ORIENTATION:
1181                     rc = CopyTabletData(lpOutput,&gSysDevice.ORIENTATION,
1182                                         sizeof(AXIS)*3);
1183                     break;
1184                 case DVC_ROTATION:
1185                     rc = 0; /* unsupported */
1186                     /*
1187                     rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1188                                         sizeof(AXIS)*3);
1189                     */
1190                     break;
1191                 case DVC_PNPID:
1192                     rc = CopyTabletData(lpOutput,gSysDevice.PNPID,
1193                                         (strlenW(gSysDevice.PNPID)+1)*sizeof(WCHAR));
1194                     break;
1195                 default:
1196                     FIXME("WTI_DEVICES unhandled index %i\n",nIndex);
1197                     rc = 0;
1198             }
1199             break;
1200         default:
1201             FIXME("Unhandled Category %i\n",wCategory);
1202     }
1203     return rc;
1204 }
1205
1206 #else /* SONAME_LIBXI */
1207
1208 /***********************************************************************
1209  *              AttachEventQueueToTablet (X11DRV.@)
1210  */
1211 int X11DRV_AttachEventQueueToTablet(HWND hOwner)
1212 {
1213     return 0;
1214 }
1215
1216 /***********************************************************************
1217  *              GetCurrentPacket (X11DRV.@)
1218  */
1219 int X11DRV_GetCurrentPacket(LPWTPACKET *packet)
1220 {
1221     return 0;
1222 }
1223
1224 /***********************************************************************
1225  *              LoadTabletInfo (X11DRV.@)
1226  */
1227 void X11DRV_LoadTabletInfo(HWND hwnddefault)
1228 {
1229 }
1230
1231 /***********************************************************************
1232  *              WTInfoW (X11DRV.@)
1233  */
1234 UINT X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
1235 {
1236     return 0;
1237 }
1238
1239 #endif /* SONAME_LIBXI */