4 * Copyright 2003 CodeWeavers (Aric Stewart)
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.
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.
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
22 #include "wine/port.h"
31 #include "wine/library.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wintab32
);
38 #define WT_MAX_NAME_LEN 256
40 typedef struct tagWTI_CURSORS_INFO
42 WCHAR NAME
[WT_MAX_NAME_LEN
];
43 /* a displayable zero-terminated string containing the name of the
47 /* whether the cursor is currently connected. */
49 /* a bit mask indicating the packet data items supported when this
50 * cursor is connected.
53 /* the number of buttons on this cursor. */
55 /* the number of bits of raw button data returned by the hardware.*/
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.
64 /* a 32 byte array of logical button numbers, one for each physical
68 /* a 32 byte array of button action codes, one for each logical
72 /* the physical button number of the button that is controlled by normal
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.
81 /* an array of UINTs describing the pressure response curve for normal
85 /* the physical button number of the button that is controlled by
86 * tangential pressure.
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.
94 /* an array of UINTs describing the pressure response curve for
95 * tangential pressure.
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
106 /* the cursor mode number of this cursor type, if this cursor type has
107 * the CRC_MULTIMODE capability.
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.
114 /* the minimum number of buttons of physical cursors in the cursor type,
115 * if this cursor type has the CRC_AGGREGATE capability.
118 /* flags indicating cursor capabilities, as defined below:
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
125 Indicates this cursor type describes several physical cursors
126 that cannot be distinguished by software.
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.
133 /* Manufacturer Unique id for the item type */
134 } WTI_CURSORS_INFO
, *LPWTI_CURSORS_INFO
;
137 typedef struct tagWTI_DEVICES_INFO
139 WCHAR NAME
[WT_MAX_NAME_LEN
];
140 /* a displayable null- terminated string describing the device,
141 * manufacturer, and revision level.
144 /* flags indicating hardware and driver capabilities, as defined
147 Indicates that the display and digitizer share the same surface.
149 Indicates that the cursor must be in physical contact with the
150 device to report position.
152 Indicates that device can generate events when the cursor is
153 entering and leaving the physical detection range.
155 Indicates that device can uniquely identify the active cursor in
159 /* the number of supported cursor types.*/
161 /* the first cursor type number for the device. */
163 /* the maximum packet report rate in Hertz. */
165 /* a bit mask indicating which packet data items are always available.*/
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.
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.
179 /* the size of tablet context margins in tablet native coordinates, in
180 * the x, y, and z directions, respectively.
185 /* the tablet's range and resolution capabilities, in the x, y, and z
186 * axes, respectively.
190 /* the tablet's range and resolution capabilities, for the normal and
191 * tangential pressure inputs, respectively.
194 /* a 3-element array describing the tablet's orientation range and
195 * resolution capabilities.
198 /* a 3-element array describing the tablet's rotation range and
199 * resolution capabilities.
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
;
206 /***********************************************************************
207 * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE
208 * In Wintab 1.2, a CSR_TYPE feature was added. This adds the
209 * ability to return a type of cursor on a tablet.
210 * Unfortunately, we cannot get the cursor type directly from X,
211 * and it is not specified directly anywhere. So we virtualize
212 * the type here. (This is unfortunate, the kernel module has
213 * the exact type, but we have no way of getting that module to
214 * pass us that type).
216 * Reference linuxwacom driver project wcmCommon.c function
217 * idtotype for a much larger list of CSR_TYPE.
219 * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wcmCommon.c?view=markup
221 * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this:
222 * (cursor.TYPE & 0x0F06) == target_cursor_type
223 * Reference: Section Unique ID
224 * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
226 #define CSR_TYPE_PEN 0x822
227 #define CSR_TYPE_ERASER 0x82a
228 #define CSR_TYPE_MOUSE_2D 0x007
229 #define CSR_TYPE_MOUSE_4D 0x094
230 /* CSR_TYPE_OTHER is a special value! assumed no real world significance
231 * if a stylus type or eraser type eventually have this value
232 * it'll be a bug. As of 2008 05 21 we can be sure because
233 * linux wacom lists all the known values and this isn't one of them */
234 #define CSR_TYPE_OTHER 0x000
236 typedef struct tagWTPACKET
{
247 UINT pkNormalPressure
;
248 UINT pkTangentPressure
;
249 ORIENTATION pkOrientation
;
250 ROTATION pkRotation
; /* 1.1 */
251 } WTPACKET
, *LPWTPACKET
;
256 #include <X11/Xlib.h>
257 #include <X11/extensions/XInput.h>
259 static int motion_type
;
260 static int button_press_type
;
261 static int button_release_type
;
262 static int key_press_type
;
263 static int key_release_type
;
264 static int proximity_in_type
;
265 static int proximity_out_type
;
267 static HWND hwndTabletDefault
;
268 static WTPACKET gMsgPacket
;
269 static DWORD gSerial
;
271 /* Reference: http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
273 * Cursors come in sets of 3 normally
274 * Cursor #0 = puck device 1
275 * Cursor #1 = stylus device 1
276 * Cursor #2 = eraser device 1
277 * Cursor #3 = puck device 2
278 * Cursor #4 = stylus device 2
279 * Cursor #5 = eraser device 2
282 * A dual tracking/multimode tablet is one
283 * that supports 2 independent cursors of the same or
284 * different types simultaneously on a single tablet.
285 * This makes our cursor layout potentially like this
286 * Cursor #0 = puck 1 device 1
287 * Cursor #1 = stylus 1 device 1
288 * Cursor #2 = eraser 1 device 1
289 * Cursor #3 = puck 2 device 1
290 * Cursor #4 = stylus 2 device 1
291 * Cursor #5 = eraser 2 device 1
292 * Cursor #6 = puck 1 device 2
295 * So with multimode tablets we could potentially need
296 * 2 slots of the same type per tablet i.e.
297 * you are using 2 styluses at once so they would
298 * get placed in Cursors #1 and Cursor #4
300 * Now say someone has 2 multimode tablets with 2 erasers each
301 * now we would need Cursor #2, #5, #8, #11
302 * So to support that we need CURSORMAX of 12 (0 to 11)
303 * FIXME: we don't support more than 4 regular tablets or 2 multimode tablets */
305 static INT button_state
[CURSORMAX
];
307 static LOGCONTEXTW gSysContext
;
308 static WTI_DEVICES_INFO gSysDevice
;
309 static WTI_CURSORS_INFO gSysCursor
[CURSORMAX
];
310 static INT gNumCursors
; /* do NOT use this to iterate through gSysCursor slots */
314 static void *xinput_handle
;
316 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
317 MAKE_FUNCPTR(XListInputDevices
)
318 MAKE_FUNCPTR(XFreeDeviceList
)
319 MAKE_FUNCPTR(XOpenDevice
)
320 MAKE_FUNCPTR(XQueryDeviceState
)
321 MAKE_FUNCPTR(XGetDeviceButtonMapping
)
322 MAKE_FUNCPTR(XCloseDevice
)
323 MAKE_FUNCPTR(XSelectExtensionEvent
)
324 MAKE_FUNCPTR(XFreeDeviceState
)
327 static INT
X11DRV_XInput_Init(void)
329 xinput_handle
= wine_dlopen(SONAME_LIBXI
, RTLD_NOW
, NULL
, 0);
332 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xinput_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
333 LOAD_FUNCPTR(XListInputDevices
)
334 LOAD_FUNCPTR(XFreeDeviceList
)
335 LOAD_FUNCPTR(XOpenDevice
)
336 LOAD_FUNCPTR(XGetDeviceButtonMapping
)
337 LOAD_FUNCPTR(XCloseDevice
)
338 LOAD_FUNCPTR(XSelectExtensionEvent
)
339 LOAD_FUNCPTR(XQueryDeviceState
)
340 LOAD_FUNCPTR(XFreeDeviceState
)
348 static int Tablet_ErrorHandler(Display
*dpy
, XErrorEvent
*event
, void* arg
)
353 static void trace_axes(XValuatorInfoPtr val
)
358 for (i
= 0, axis
= val
->axes
; i
< val
->num_axes
; i
++, axis
++)
359 TRACE(" Axis %d: [resolution %d|min_value %d|max_value %d]\n", i
, axis
->resolution
, axis
->min_value
, axis
->max_value
);
362 static BOOL
match_token(const char *haystack
, const char *needle
)
365 for (p
= haystack
; *p
; )
367 while (*p
&& isspace(*p
))
372 for (q
= needle
; *q
&& *p
&& tolower(*p
) == tolower(*q
); q
++)
374 if (! *q
&& (isspace(*p
) || !*p
))
377 while (*p
&& ! isspace(*p
))
383 /* Determining if an X device is a Tablet style device is an imperfect science.
384 ** We rely on common conventions around device names as well as the type reported
385 ** by Wacom tablets. This code will likely need to be expanded for alternate tablet types
387 ** Wintab refers to any device that interacts with the tablet as a cursor,
388 ** (stylus, eraser, tablet mouse, airbrush, etc)
389 ** this is not to be confused with wacom x11 configuration "cursor" device.
390 ** Wacoms x11 config "cursor" refers to its device slot (which we mirror with
391 ** our gSysCursors) for puck like devices (tablet mice essentially).
394 static BOOL
is_tablet_cursor(const char *name
, const char *type
)
397 static const char *tablet_cursor_whitelist
[] = {
409 for (i
=0; tablet_cursor_whitelist
[i
] != NULL
; i
++) {
410 if (name
&& match_token(name
, tablet_cursor_whitelist
[i
]))
412 if (type
&& match_token(type
, tablet_cursor_whitelist
[i
]))
418 static UINT
get_cursor_type(const char *name
, const char *type
)
421 static const char* tablet_stylus_whitelist
[] = {
429 /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
430 for (i
=0; tablet_stylus_whitelist
[i
] != NULL
; i
++) {
431 if (type
&& match_token(type
, tablet_stylus_whitelist
[i
]))
434 if (type
&& match_token(type
, "eraser"))
435 return CSR_TYPE_ERASER
;
436 for (i
=0; tablet_stylus_whitelist
[i
] != NULL
; i
++) {
437 if (name
&& match_token(name
, tablet_stylus_whitelist
[i
]))
440 if (name
&& match_token(name
, "eraser"))
441 return CSR_TYPE_ERASER
;
443 return CSR_TYPE_OTHER
;
446 /* cursors are placed in gSysCursor rows depending on their type
447 * see CURSORMAX comments for more detail */
448 static BOOL
add_system_cursor(LPWTI_CURSORS_INFO cursor
)
452 if (cursor
->TYPE
== CSR_TYPE_PEN
)
454 else if (cursor
->TYPE
== CSR_TYPE_ERASER
)
457 for (; offset
< CURSORMAX
; offset
+= 3)
459 if (!gSysCursor
[offset
].ACTIVE
)
461 gSysCursor
[offset
] = *cursor
;
470 static void disable_system_cursors(void)
474 for (i
= 0; i
< CURSORMAX
; ++i
)
476 gSysCursor
[i
].ACTIVE
= 0;
483 /***********************************************************************
484 * X11DRV_LoadTabletInfo (X11DRV.@)
486 BOOL CDECL
X11DRV_LoadTabletInfo(HWND hwnddefault
)
488 const WCHAR SZ_CONTEXT_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
489 const WCHAR SZ_DEVICE_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
490 const WCHAR SZ_NON_PLUGINPLAY
[] = {'n','o','n','-','p','l','u','g','i','n','p','l','a','y',0};
492 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
495 XDeviceInfo
*devices
;
496 XDeviceInfo
*target
= NULL
;
497 BOOL axis_read_complete
= FALSE
;
500 XButtonInfoPtr Button
;
501 XValuatorInfoPtr Val
;
506 if (!X11DRV_XInput_Init())
508 ERR("Unable to initialize the XInput library.\n");
512 hwndTabletDefault
= hwnddefault
;
514 /* Do base initialization */
515 strcpyW(gSysContext
.lcName
, SZ_CONTEXT_NAME
);
516 strcpyW(gSysDevice
.NAME
, SZ_DEVICE_NAME
);
518 gSysContext
.lcOptions
= CXO_SYSTEM
;
519 gSysContext
.lcLocks
= CXL_INSIZE
| CXL_INASPECT
| CXL_MARGIN
|
520 CXL_SENSITIVITY
| CXL_SYSOUT
;
522 gSysContext
.lcMsgBase
= WT_DEFBASE
;
523 gSysContext
.lcDevice
= 0;
524 gSysContext
.lcPktData
=
525 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
526 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
527 gSysContext
.lcMoveMask
=
528 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
529 gSysContext
.lcStatus
= CXS_ONTOP
;
530 gSysContext
.lcPktRate
= 100;
531 gSysContext
.lcBtnDnMask
= 0xffffffff;
532 gSysContext
.lcBtnUpMask
= 0xffffffff;
533 gSysContext
.lcSensX
= 65536;
534 gSysContext
.lcSensY
= 65536;
535 gSysContext
.lcSensX
= 65536;
536 gSysContext
.lcSensZ
= 65536;
537 gSysContext
.lcSysSensX
= 65536;
538 gSysContext
.lcSysSensY
= 65536;
539 gSysContext
.lcOutExtX
= GetSystemMetrics(SM_CXSCREEN
);
540 gSysContext
.lcOutExtY
= GetSystemMetrics(SM_CYSCREEN
);
542 /* initialize cursors */
543 disable_system_cursors();
545 /* Device Defaults */
546 gSysDevice
.HARDWARE
= HWC_HARDPROX
|HWC_PHYSID_CURSORS
;
547 gSysDevice
.FIRSTCSR
= 0;
548 gSysDevice
.PKTRATE
= 100;
550 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
551 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
552 strcpyW(gSysDevice
.PNPID
, SZ_NON_PLUGINPLAY
);
554 devices
= pXListInputDevices(data
->display
, &num_devices
);
557 WARN("XInput Extensions reported as not available\n");
560 TRACE("XListInputDevices reports %d devices\n", num_devices
);
561 for (loop
=0; loop
< num_devices
; loop
++)
564 char *device_type
= devices
[loop
].type
? XGetAtomName(data
->display
, devices
[loop
].type
) : NULL
;
565 WTI_CURSORS_INFO cursor
;
567 TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %d]\n",
568 loop
, (int) devices
[loop
].id
, devices
[loop
].name
, device_type
? device_type
: "",
569 devices
[loop
].num_classes
, devices
[loop
].use
);
571 switch (devices
[loop
].use
)
573 case IsXExtensionDevice
:
574 #ifdef IsXExtensionPointer
575 case IsXExtensionPointer
:
577 #ifdef IsXExtensionKeyboard
578 case IsXExtensionKeyboard
:
580 TRACE("Is XExtension: Device, Keyboard, or Pointer\n");
581 target
= &devices
[loop
];
583 if (strlen(target
->name
) >= WT_MAX_NAME_LEN
)
585 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target
->name
));
589 X11DRV_expect_error(data
->display
, Tablet_ErrorHandler
, NULL
);
590 opendevice
= pXOpenDevice(data
->display
,target
->id
);
591 if (!X11DRV_check_error() && opendevice
)
593 unsigned char map
[32];
597 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
598 cursor
.BUTTONS
= pXGetDeviceButtonMapping(data
->display
, opendevice
, map
, 32);
599 if (X11DRV_check_error() || cursor
.BUTTONS
<= 0)
601 TRACE("No buttons, Non Tablet Device\n");
602 pXCloseDevice(data
->display
, opendevice
);
606 for (i
=0; i
< cursor
.BUTTONS
; i
++,shft
++)
608 cursor
.BUTTONMAP
[i
] = map
[i
];
609 cursor
.SYSBTNMAP
[i
] = (1<<shft
);
611 pXCloseDevice(data
->display
, opendevice
);
615 WARN("Unable to open device %s\n",target
->name
);
618 MultiByteToWideChar(CP_UNIXCP
, 0, target
->name
, -1, cursor
.NAME
, WT_MAX_NAME_LEN
);
620 if (! is_tablet_cursor(target
->name
, device_type
))
622 WARN("Skipping device %d [name %s|type %s]; not apparently a tablet cursor type device. If this is wrong, please report it to wine-devel@winehq.org\n",
623 loop
, devices
[loop
].name
, device_type
? device_type
: "");
628 cursor
.PKTDATA
= PK_TIME
| PK_CURSOR
| PK_BUTTONS
| PK_X
| PK_Y
|
629 PK_NORMAL_PRESSURE
| PK_TANGENT_PRESSURE
|
632 cursor
.PHYSID
= target
->id
;
634 cursor
.NPBTNMARKS
[0] = 0 ;
635 cursor
.NPBTNMARKS
[1] = 1 ;
636 cursor
.CAPABILITIES
= CRC_MULTIMODE
;
638 cursor
.TYPE
= get_cursor_type(target
->name
, device_type
);
640 any
= target
->inputclassinfo
;
642 for (class_loop
= 0; class_loop
< target
->num_classes
; class_loop
++)
648 Val
= (XValuatorInfoPtr
) any
;
649 TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n",
650 class_loop
, (int) Val
->class, Val
->length
, Val
->num_axes
, Val
->mode
, Val
->motion_buffer
);
651 if (TRACE_ON(wintab32
))
654 /* FIXME: This is imperfect; we compute our devices capabilities based upon the
655 ** first pen type device we find. However, a more correct implementation
656 ** would require acquiring a wide variety of tablets and running through
657 ** the various inputs to see what the values are. Odds are that a
658 ** more 'correct' algorithm would condense to this one anyway.
660 if (!axis_read_complete
&& cursor
.TYPE
== CSR_TYPE_PEN
)
662 Axis
= (XAxisInfoPtr
) ((char *) Val
+ sizeof
665 if (Val
->num_axes
>=1)
668 gSysDevice
.X
.axMin
= Axis
->min_value
;
669 gSysDevice
.X
.axMax
= Axis
->max_value
;
670 gSysDevice
.X
.axUnits
= TU_INCHES
;
671 gSysDevice
.X
.axResolution
= Axis
->resolution
;
672 gSysContext
.lcInOrgX
= Axis
->min_value
;
673 gSysContext
.lcSysOrgX
= Axis
->min_value
;
674 gSysContext
.lcInExtX
= Axis
->max_value
;
675 gSysContext
.lcSysExtX
= Axis
->max_value
;
678 if (Val
->num_axes
>=2)
681 gSysDevice
.Y
.axMin
= Axis
->min_value
;
682 gSysDevice
.Y
.axMax
= Axis
->max_value
;
683 gSysDevice
.Y
.axUnits
= TU_INCHES
;
684 gSysDevice
.Y
.axResolution
= Axis
->resolution
;
685 gSysContext
.lcInOrgY
= Axis
->min_value
;
686 gSysContext
.lcSysOrgY
= Axis
->min_value
;
687 gSysContext
.lcInExtY
= Axis
->max_value
;
688 gSysContext
.lcSysExtY
= Axis
->max_value
;
691 if (Val
->num_axes
>=3)
693 /* Axis 3 is Normal Pressure */
694 gSysDevice
.NPRESSURE
.axMin
= Axis
->min_value
;
695 gSysDevice
.NPRESSURE
.axMax
= Axis
->max_value
;
696 gSysDevice
.NPRESSURE
.axUnits
= TU_INCHES
;
697 gSysDevice
.NPRESSURE
.axResolution
=
701 if (Val
->num_axes
>= 5)
703 /* Axis 4 and 5 are X and Y tilt */
704 XAxisInfoPtr XAxis
= Axis
;
706 if (max (abs(Axis
->max_value
),
707 abs(XAxis
->max_value
)))
709 gSysDevice
.ORIENTATION
[0].axMin
= 0;
710 gSysDevice
.ORIENTATION
[0].axMax
= 3600;
711 gSysDevice
.ORIENTATION
[0].axUnits
= TU_CIRCLE
;
712 gSysDevice
.ORIENTATION
[0].axResolution
714 gSysDevice
.ORIENTATION
[1].axMin
= -1000;
715 gSysDevice
.ORIENTATION
[1].axMax
= 1000;
716 gSysDevice
.ORIENTATION
[1].axUnits
= TU_CIRCLE
;
717 gSysDevice
.ORIENTATION
[1].axResolution
722 axis_read_complete
= TRUE
;
731 Button
= (XButtonInfoPtr
) any
;
732 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
733 class_loop
, (int) Button
->class, Button
->length
, Button
->num_buttons
);
734 cursor
.BTNNAMES
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*cchBuf
);
735 for (i
= 0; i
< cursor
.BUTTONS
; i
++)
737 /* FIXME - these names are probably incorrect */
738 int cch
= strlenW(cursor
.NAME
) + 1;
739 while (cch
> cchBuf
- cchPos
- 1) /* we want one extra byte for the last NUL */
742 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchBuf
);
745 strcpyW(cursor
.BTNNAMES
+ cchPos
, cursor
.NAME
);
748 cursor
.BTNNAMES
[cchPos
++] = 0;
749 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchPos
);
750 cursor
.cchBTNNAMES
= cchPos
;
753 } /* switch any->class */
754 any
= (XAnyClassPtr
) ((char*) any
+ any
->length
);
755 } /* for class_loop */
756 if (!add_system_cursor(&cursor
))
757 FIXME("Skipping this cursor due to lack of system cursor slots.\n");
759 } /* switch devices.use */
761 } /* for XListInputDevices */
762 pXFreeDeviceList(devices
);
764 if (axis_read_complete
)
765 gSysDevice
.NCSRTYPES
= gNumCursors
;
768 disable_system_cursors();
769 WARN("Did not find a valid stylus, unable to determine system context parameters. Wintab is disabled.\n");
775 static int figure_deg(int x
, int y
)
779 angle
= atan2((float)y
, (float)x
);
784 return (0.5 + (angle
* 1800.0 / M_PI
));
787 static int get_button_state(int curnum
)
789 return button_state
[curnum
];
792 static void set_button_state(int curnum
, XID deviceid
)
794 struct x11drv_thread_data
*data
= x11drv_thread_data();
801 device
= pXOpenDevice(data
->display
,deviceid
);
802 state
= pXQueryDeviceState(data
->display
,device
);
807 for (loop
= 0; loop
< state
->num_classes
; loop
++)
809 if (class->class == ButtonClass
)
812 XButtonState
*button_state
= (XButtonState
*)class;
813 for (loop2
= 0; loop2
< button_state
->num_buttons
; loop2
++)
815 if (button_state
->buttons
[loop2
/ 8] & (1 << (loop2
% 8)))
821 class = (XInputClass
*) ((char *) class + class->length
);
824 pXFreeDeviceState(state
);
825 button_state
[curnum
] = rc
;
828 static int cursor_from_device(DWORD deviceid
, LPWTI_CURSORS_INFO
*cursorp
)
831 for (i
= 0; i
< CURSORMAX
; i
++)
832 if (gSysCursor
[i
].ACTIVE
&& gSysCursor
[i
].PHYSID
== deviceid
)
834 *cursorp
= &gSysCursor
[i
];
838 ERR("Could not map device id %d to a cursor\n", (int) deviceid
);
842 static void motion_event( HWND hwnd
, XEvent
*event
)
844 XDeviceMotionEvent
*motion
= (XDeviceMotionEvent
*)event
;
845 LPWTI_CURSORS_INFO cursor
;
846 int curnum
= cursor_from_device(motion
->deviceid
, &cursor
);
850 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
852 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd
, (int) motion
->deviceid
, curnum
);
854 /* Set cursor to inverted if cursor is the eraser */
855 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
856 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(motion
->time
);
857 gMsgPacket
.pkSerialNumber
= gSerial
++;
858 gMsgPacket
.pkCursor
= curnum
;
859 gMsgPacket
.pkX
= motion
->axis_data
[0];
860 gMsgPacket
.pkY
= motion
->axis_data
[1];
861 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(motion
->axis_data
[3],motion
->axis_data
[4]);
862 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max
863 (abs(motion
->axis_data
[3]),
864 abs(motion
->axis_data
[4])))
865 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
866 gMsgPacket
.pkNormalPressure
= motion
->axis_data
[2];
867 gMsgPacket
.pkButtons
= get_button_state(curnum
);
868 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
871 static void button_event( HWND hwnd
, XEvent
*event
)
873 XDeviceButtonEvent
*button
= (XDeviceButtonEvent
*) event
;
874 LPWTI_CURSORS_INFO cursor
;
875 int curnum
= cursor_from_device(button
->deviceid
, &cursor
);
879 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
881 TRACE("Received tablet button %s event\n", (event
->type
== button_press_type
)?"press":"release");
883 /* Set cursor to inverted if cursor is the eraser */
884 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
885 set_button_state(curnum
, button
->deviceid
);
886 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(button
->time
);
887 gMsgPacket
.pkSerialNumber
= gSerial
++;
888 gMsgPacket
.pkCursor
= curnum
;
889 gMsgPacket
.pkX
= button
->axis_data
[0];
890 gMsgPacket
.pkY
= button
->axis_data
[1];
891 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(button
->axis_data
[3],button
->axis_data
[4]);
892 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(button
->axis_data
[3]),
893 abs(button
->axis_data
[4])))
894 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
895 gMsgPacket
.pkNormalPressure
= button
->axis_data
[2];
896 gMsgPacket
.pkButtons
= get_button_state(curnum
);
897 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
900 static void key_event( HWND hwnd
, XEvent
*event
)
902 if (event
->type
== key_press_type
)
903 FIXME("Received tablet key press event\n");
905 FIXME("Received tablet key release event\n");
908 static void proximity_event( HWND hwnd
, XEvent
*event
)
910 XProximityNotifyEvent
*proximity
= (XProximityNotifyEvent
*) event
;
911 LPWTI_CURSORS_INFO cursor
;
912 int curnum
= cursor_from_device(proximity
->deviceid
, &cursor
);
913 LPARAM proximity_info
;
915 TRACE("hwnd=%p\n", hwnd
);
920 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
922 /* Set cursor to inverted if cursor is the eraser */
923 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
924 gMsgPacket
.pkStatus
|= (event
->type
==proximity_out_type
)?TPS_PROXIMITY
:0;
925 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(proximity
->time
);
926 gMsgPacket
.pkSerialNumber
= gSerial
++;
927 gMsgPacket
.pkCursor
= curnum
;
928 gMsgPacket
.pkX
= proximity
->axis_data
[0];
929 gMsgPacket
.pkY
= proximity
->axis_data
[1];
930 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(proximity
->axis_data
[3],proximity
->axis_data
[4]);
931 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(proximity
->axis_data
[3]),
932 abs(proximity
->axis_data
[4])))
933 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
934 gMsgPacket
.pkNormalPressure
= proximity
->axis_data
[2];
935 gMsgPacket
.pkButtons
= get_button_state(curnum
);
937 /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context
938 * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct
940 * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity"
941 * WPARAM contains context handle.
942 * HWND to HCTX is handled by wintab32.
944 proximity_info
= MAKELPARAM((event
->type
== proximity_in_type
),
945 (event
->type
== proximity_in_type
) || (event
->type
== proximity_out_type
));
946 SendMessageW(hwndTabletDefault
, WT_PROXIMITY
, (WPARAM
)hwnd
, proximity_info
);
949 /***********************************************************************
950 * X11DRV_AttachEventQueueToTablet (X11DRV.@)
952 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
954 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
958 XDeviceInfo
*devices
;
959 XDeviceInfo
*target
= NULL
;
961 XEventClass event_list
[7];
962 Window win
= X11DRV_get_whole_window( hOwner
);
964 if (!win
|| !xinput_handle
) return 0;
966 TRACE("Creating context for window %p (%lx) %i cursors\n", hOwner
, win
, gNumCursors
);
968 devices
= pXListInputDevices(data
->display
, &num_devices
);
970 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
971 for (cur_loop
=0; cur_loop
< CURSORMAX
; cur_loop
++)
973 char cursorNameA
[WT_MAX_NAME_LEN
];
976 if (!gSysCursor
[cur_loop
].ACTIVE
) continue;
978 /* the cursor name fits in the buffer because too long names are skipped */
979 WideCharToMultiByte(CP_UNIXCP
, 0, gSysCursor
[cur_loop
].NAME
, -1, cursorNameA
, WT_MAX_NAME_LEN
, NULL
, NULL
);
980 for (loop
=0; loop
< num_devices
; loop
++)
981 if (strcmp(devices
[loop
].name
, cursorNameA
) == 0)
982 target
= &devices
[loop
];
984 WARN("Cursor Name %s not found in list of targets.\n", cursorNameA
);
988 TRACE("Opening cursor %i id %i\n",cur_loop
,(INT
)target
->id
);
990 the_device
= pXOpenDevice(data
->display
, target
->id
);
994 WARN("Unable to Open device\n");
998 if (the_device
->num_classes
> 0)
1000 DeviceKeyPress(the_device
, key_press_type
, event_list
[event_number
]);
1001 if (key_press_type
) event_number
++;
1002 DeviceKeyRelease(the_device
, key_release_type
, event_list
[event_number
]);
1003 if (key_release_type
) event_number
++;
1004 DeviceButtonPress(the_device
, button_press_type
, event_list
[event_number
]);
1005 if (button_press_type
) event_number
++;
1006 DeviceButtonRelease(the_device
, button_release_type
, event_list
[event_number
]);
1007 if (button_release_type
) event_number
++;
1008 DeviceMotionNotify(the_device
, motion_type
, event_list
[event_number
]);
1009 if (motion_type
) event_number
++;
1010 ProximityIn(the_device
, proximity_in_type
, event_list
[event_number
]);
1011 if (proximity_in_type
) event_number
++;
1012 ProximityOut(the_device
, proximity_out_type
, event_list
[event_number
]);
1013 if (proximity_out_type
) event_number
++;
1016 X11DRV_register_event_handler( key_press_type
, key_event
, "XInput KeyPress" );
1017 if (key_release_type
)
1018 X11DRV_register_event_handler( key_release_type
, key_event
, "XInput KeyRelease" );
1019 if (button_press_type
)
1020 X11DRV_register_event_handler( button_press_type
, button_event
, "XInput ButtonPress" );
1021 if (button_release_type
)
1022 X11DRV_register_event_handler( button_release_type
, button_event
, "XInput ButtonRelease" );
1024 X11DRV_register_event_handler( motion_type
, motion_event
, "XInput MotionNotify" );
1025 if (proximity_in_type
)
1026 X11DRV_register_event_handler( proximity_in_type
, proximity_event
, "XInput ProximityIn" );
1027 if (proximity_out_type
)
1028 X11DRV_register_event_handler( proximity_out_type
, proximity_event
, "XInput ProximityOut" );
1030 pXSelectExtensionEvent(data
->display
, win
, event_list
, event_number
);
1033 XSync(data
->display
, False
);
1034 X11DRV_check_error();
1036 if (NULL
!= devices
) pXFreeDeviceList(devices
);
1040 /***********************************************************************
1041 * X11DRV_GetCurrentPacket (X11DRV.@)
1043 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1045 *packet
= gMsgPacket
;
1050 static inline int CopyTabletData(LPVOID target
, LPCVOID src
, INT size
)
1053 * It is valid to call CopyTabletData with NULL.
1054 * This handles the WTInfo() case where lpOutput is null.
1057 memcpy(target
,src
,size
);
1061 /***********************************************************************
1062 * X11DRV_WTInfoW (X11DRV.@)
1064 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1067 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1068 * lpOutput == NULL signifies the user only wishes
1069 * to find the size of the data.
1071 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1075 LPWTI_CURSORS_INFO tgtcursor
;
1076 TRACE("(%u, %u, %p)\n", wCategory
, nIndex
, lpOutput
);
1078 if (!xinput_handle
) return 0;
1083 /* return largest necessary buffer */
1084 TRACE("%i cursors\n",gNumCursors
);
1087 FIXME("Return proper size\n");
1098 static const WCHAR driver
[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1099 rc
= CopyTabletData(lpOutput
, driver
, (strlenW(driver
) + 1) * sizeof(WCHAR
));
1102 case IFC_SPECVERSION
:
1103 version
= (0x01) | (0x01 << 8);
1104 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1106 case IFC_IMPLVERSION
:
1107 version
= (0x00) | (0x01 << 8);
1108 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1112 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1116 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1119 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex
);
1125 case WTI_DEFCONTEXT
:
1129 /* report 0 if wintab is disabled */
1130 if (0 == gNumCursors
)
1133 rc
= CopyTabletData(lpOutput
, &gSysContext
,
1134 sizeof(LOGCONTEXTW
));
1137 rc
= CopyTabletData(lpOutput
, gSysContext
.lcName
,
1138 (strlenW(gSysContext
.lcName
)+1) * sizeof(WCHAR
));
1141 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOptions
,
1145 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcStatus
,
1149 rc
= CopyTabletData (lpOutput
, &gSysContext
.lcLocks
,
1153 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMsgBase
,
1157 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcDevice
,
1161 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktRate
,
1165 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktData
,
1169 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktMode
,
1173 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMoveMask
,
1177 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnDnMask
,
1181 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnUpMask
,
1185 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgX
,
1189 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgY
,
1193 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgZ
,
1197 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtX
,
1201 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtY
,
1205 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtZ
,
1209 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgX
,
1213 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgY
,
1217 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgZ
,
1221 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtX
,
1225 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtY
,
1229 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtZ
,
1233 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensX
,
1237 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensY
,
1241 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensZ
,
1245 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysMode
,
1249 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgX
,
1253 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgY
,
1257 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtX
,
1261 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtY
,
1265 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensX
,
1269 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensY
,
1273 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex
);
1287 case WTI_CURSORS
+10:
1288 case WTI_CURSORS
+11:
1289 /* CURSORMAX == 12 */
1290 /* FIXME: dynamic cursor support */
1291 /* Apps will poll different slots to detect what cursors are available
1292 * if there isn't a cursor for this slot return 0 */
1293 if (!gSysCursor
[wCategory
- WTI_CURSORS
].ACTIVE
)
1297 tgtcursor
= &gSysCursor
[wCategory
- WTI_CURSORS
];
1301 rc
= CopyTabletData(lpOutput
, tgtcursor
->NAME
,
1302 (strlenW(tgtcursor
->NAME
)+1) * sizeof(WCHAR
));
1305 rc
= CopyTabletData(lpOutput
,&tgtcursor
->ACTIVE
,
1309 rc
= CopyTabletData(lpOutput
,&tgtcursor
->PKTDATA
,
1313 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONS
,
1316 case CSR_BUTTONBITS
:
1317 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONBITS
,
1321 FIXME("Button Names not returned correctly\n");
1322 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BTNNAMES
,
1323 tgtcursor
->cchBTNNAMES
*sizeof(WCHAR
));
1326 rc
= CopyTabletData(lpOutput
,tgtcursor
->BUTTONMAP
,
1330 rc
= CopyTabletData(lpOutput
,tgtcursor
->SYSBTNMAP
,
1333 case CSR_NPBTNMARKS
:
1334 rc
= CopyTabletData(lpOutput
,tgtcursor
->NPBTNMARKS
,
1338 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBUTTON
,
1341 case CSR_NPRESPONSE
:
1342 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1346 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBUTTON
,
1349 case CSR_TPBTNMARKS
:
1350 rc
= CopyTabletData(lpOutput
,tgtcursor
->TPBTNMARKS
,
1353 case CSR_TPRESPONSE
:
1354 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1360 id
= tgtcursor
->PHYSID
;
1361 rc
= CopyTabletData(lpOutput
,&id
,sizeof(DWORD
));
1365 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MODE
,sizeof(UINT
));
1367 case CSR_MINPKTDATA
:
1368 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINPKTDATA
,
1371 case CSR_MINBUTTONS
:
1372 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINBUTTONS
,
1375 case CSR_CAPABILITIES
:
1376 rc
= CopyTabletData(lpOutput
,&tgtcursor
->CAPABILITIES
,
1380 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TYPE
,
1384 FIXME("WTI_CURSORS unhandled index %i\n",nIndex
);
1393 rc
= CopyTabletData(lpOutput
,gSysDevice
.NAME
,
1394 (strlenW(gSysDevice
.NAME
)+1) * sizeof(WCHAR
));
1397 rc
= CopyTabletData(lpOutput
,&gSysDevice
.HARDWARE
,
1401 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NCSRTYPES
,
1405 rc
= CopyTabletData(lpOutput
,&gSysDevice
.FIRSTCSR
,
1409 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTRATE
,
1413 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTDATA
,
1417 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTMODE
,
1421 rc
= CopyTabletData(lpOutput
,&gSysDevice
.CSRDATA
,
1425 rc
= CopyTabletData(lpOutput
,&gSysDevice
.XMARGIN
,
1429 rc
= CopyTabletData(lpOutput
,&gSysDevice
.YMARGIN
,
1433 rc
= 0; /* unsupported */
1435 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1440 rc
= CopyTabletData(lpOutput
,&gSysDevice
.X
,
1444 rc
= CopyTabletData(lpOutput
,&gSysDevice
.Y
,
1448 rc
= 0; /* unsupported */
1450 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1455 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NPRESSURE
,
1459 rc
= 0; /* unsupported */
1461 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1465 case DVC_ORIENTATION
:
1466 rc
= CopyTabletData(lpOutput
,gSysDevice
.ORIENTATION
,
1470 rc
= 0; /* unsupported */
1472 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1477 rc
= CopyTabletData(lpOutput
,gSysDevice
.PNPID
,
1478 (strlenW(gSysDevice
.PNPID
)+1)*sizeof(WCHAR
));
1481 FIXME("WTI_DEVICES unhandled index %i\n",nIndex
);
1486 FIXME("Unhandled Category %i\n",wCategory
);
1491 #else /* SONAME_LIBXI */
1493 /***********************************************************************
1494 * AttachEventQueueToTablet (X11DRV.@)
1496 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1501 /***********************************************************************
1502 * GetCurrentPacket (X11DRV.@)
1504 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1509 /***********************************************************************
1510 * LoadTabletInfo (X11DRV.@)
1512 BOOL CDECL
X11DRV_LoadTabletInfo(HWND hwnddefault
)
1517 /***********************************************************************
1518 * WTInfoW (X11DRV.@)
1520 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1525 #endif /* SONAME_LIBXI */