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
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
;
270 static WTPACKET last_packet
;
272 /* Reference: http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
274 * Cursors come in sets of 3 normally
275 * Cursor #0 = puck device 1
276 * Cursor #1 = stylus device 1
277 * Cursor #2 = eraser device 1
278 * Cursor #3 = puck device 2
279 * Cursor #4 = stylus device 2
280 * Cursor #5 = eraser device 2
283 * A dual tracking/multimode tablet is one
284 * that supports 2 independent cursors of the same or
285 * different types simultaneously on a single tablet.
286 * This makes our cursor layout potentially like this
287 * Cursor #0 = puck 1 device 1
288 * Cursor #1 = stylus 1 device 1
289 * Cursor #2 = eraser 1 device 1
290 * Cursor #3 = puck 2 device 1
291 * Cursor #4 = stylus 2 device 1
292 * Cursor #5 = eraser 2 device 1
293 * Cursor #6 = puck 1 device 2
296 * So with multimode tablets we could potentially need
297 * 2 slots of the same type per tablet i.e.
298 * you are using 2 styluses at once so they would
299 * get placed in Cursors #1 and Cursor #4
301 * Now say someone has 2 multimode tablets with 2 erasers each
302 * now we would need Cursor #2, #5, #8, #11
303 * So to support that we need CURSORMAX of 12 (0 to 11)
304 * FIXME: we don't support more than 4 regular tablets or 2 multimode tablets */
306 static INT button_state
[CURSORMAX
];
308 static LOGCONTEXTW gSysContext
;
309 static WTI_DEVICES_INFO gSysDevice
;
310 static WTI_CURSORS_INFO gSysCursor
[CURSORMAX
];
311 static INT gNumCursors
; /* do NOT use this to iterate through gSysCursor slots */
315 static void *xinput_handle
;
317 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
318 MAKE_FUNCPTR(XListInputDevices
)
319 MAKE_FUNCPTR(XFreeDeviceList
)
320 MAKE_FUNCPTR(XOpenDevice
)
321 MAKE_FUNCPTR(XQueryDeviceState
)
322 MAKE_FUNCPTR(XGetDeviceButtonMapping
)
323 MAKE_FUNCPTR(XCloseDevice
)
324 MAKE_FUNCPTR(XSelectExtensionEvent
)
325 MAKE_FUNCPTR(XFreeDeviceState
)
328 static INT
X11DRV_XInput_Init(void)
330 xinput_handle
= dlopen(SONAME_LIBXI
, RTLD_NOW
);
333 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xinput_handle, #f)) == NULL) goto sym_not_found
334 LOAD_FUNCPTR(XListInputDevices
);
335 LOAD_FUNCPTR(XFreeDeviceList
);
336 LOAD_FUNCPTR(XOpenDevice
);
337 LOAD_FUNCPTR(XGetDeviceButtonMapping
);
338 LOAD_FUNCPTR(XCloseDevice
);
339 LOAD_FUNCPTR(XSelectExtensionEvent
);
340 LOAD_FUNCPTR(XQueryDeviceState
);
341 LOAD_FUNCPTR(XFreeDeviceState
);
349 static int Tablet_ErrorHandler(Display
*dpy
, XErrorEvent
*event
, void* arg
)
354 static void trace_axes(XValuatorInfoPtr val
)
359 for (i
= 0, axis
= val
->axes
; i
< val
->num_axes
; i
++, axis
++)
360 TRACE(" Axis %d: [resolution %d|min_value %d|max_value %d]\n", i
, axis
->resolution
, axis
->min_value
, axis
->max_value
);
363 static BOOL
match_token(const char *haystack
, const char *needle
)
366 for (p
= haystack
; *p
; )
368 while (*p
&& isspace(*p
))
373 for (q
= needle
; *q
&& *p
&& tolower(*p
) == tolower(*q
); q
++)
375 if (! *q
&& (isspace(*p
) || !*p
))
378 while (*p
&& ! isspace(*p
))
384 /* Determining if an X device is a Tablet style device is an imperfect science.
385 ** We rely on common conventions around device names as well as the type reported
386 ** by Wacom tablets. This code will likely need to be expanded for alternate tablet types
388 ** Wintab refers to any device that interacts with the tablet as a cursor,
389 ** (stylus, eraser, tablet mouse, airbrush, etc)
390 ** this is not to be confused with wacom x11 configuration "cursor" device.
391 ** Wacoms x11 config "cursor" refers to its device slot (which we mirror with
392 ** our gSysCursors) for puck like devices (tablet mice essentially).
395 static BOOL
is_tablet_cursor(const char *name
, const char *type
)
398 static const char *tablet_cursor_allowlist
[] = {
410 for (i
=0; tablet_cursor_allowlist
[i
] != NULL
; i
++) {
411 if (name
&& match_token(name
, tablet_cursor_allowlist
[i
]))
413 if (type
&& match_token(type
, tablet_cursor_allowlist
[i
]))
419 static UINT
get_cursor_type(const char *name
, const char *type
)
422 static const char* tablet_stylus_allowlist
[] = {
430 /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
431 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
432 if (type
&& match_token(type
, tablet_stylus_allowlist
[i
]))
435 if (type
&& match_token(type
, "eraser"))
436 return CSR_TYPE_ERASER
;
437 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
438 if (name
&& match_token(name
, tablet_stylus_allowlist
[i
]))
441 if (name
&& match_token(name
, "eraser"))
442 return CSR_TYPE_ERASER
;
444 return CSR_TYPE_OTHER
;
447 /* cursors are placed in gSysCursor rows depending on their type
448 * see CURSORMAX comments for more detail */
449 static BOOL
add_system_cursor(LPWTI_CURSORS_INFO cursor
)
453 if (cursor
->TYPE
== CSR_TYPE_PEN
)
455 else if (cursor
->TYPE
== CSR_TYPE_ERASER
)
458 for (; offset
< CURSORMAX
; offset
+= 3)
460 if (!gSysCursor
[offset
].ACTIVE
)
462 gSysCursor
[offset
] = *cursor
;
471 static void disable_system_cursors(void)
475 for (i
= 0; i
< CURSORMAX
; ++i
)
477 gSysCursor
[i
].ACTIVE
= 0;
484 /***********************************************************************
485 * X11DRV_LoadTabletInfo (X11DRV.@)
487 BOOL CDECL
X11DRV_LoadTabletInfo(HWND hwnddefault
)
489 static const WCHAR SZ_CONTEXT_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
490 static const WCHAR SZ_DEVICE_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
491 static const WCHAR SZ_NON_PLUG_N_PLAY
[] = {'n','o','n','-','p','l','u','g','-','n','-','p','l','a','y',0};
493 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
496 XDeviceInfo
*devices
;
497 XDeviceInfo
*target
= NULL
;
498 BOOL axis_read_complete
= FALSE
;
501 XButtonInfoPtr Button
;
502 XValuatorInfoPtr Val
;
507 if (!X11DRV_XInput_Init())
509 ERR("Unable to initialize the XInput library.\n");
513 hwndTabletDefault
= hwnddefault
;
515 /* Do base initialization */
516 strcpyW(gSysContext
.lcName
, SZ_CONTEXT_NAME
);
517 strcpyW(gSysDevice
.NAME
, SZ_DEVICE_NAME
);
519 gSysContext
.lcOptions
= CXO_SYSTEM
;
520 gSysContext
.lcLocks
= CXL_INSIZE
| CXL_INASPECT
| CXL_MARGIN
|
521 CXL_SENSITIVITY
| CXL_SYSOUT
;
523 gSysContext
.lcMsgBase
= WT_DEFBASE
;
524 gSysContext
.lcDevice
= 0;
525 gSysContext
.lcPktData
=
526 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
527 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
528 gSysContext
.lcMoveMask
=
529 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
530 gSysContext
.lcStatus
= CXS_ONTOP
;
531 gSysContext
.lcPktRate
= 100;
532 gSysContext
.lcBtnDnMask
= 0xffffffff;
533 gSysContext
.lcBtnUpMask
= 0xffffffff;
534 gSysContext
.lcSensX
= 65536;
535 gSysContext
.lcSensY
= 65536;
536 gSysContext
.lcSensX
= 65536;
537 gSysContext
.lcSensZ
= 65536;
538 gSysContext
.lcSysSensX
= 65536;
539 gSysContext
.lcSysSensY
= 65536;
540 gSysContext
.lcSysExtX
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
541 gSysContext
.lcSysExtY
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
543 /* initialize cursors */
544 disable_system_cursors();
546 /* Device Defaults */
547 gSysDevice
.HARDWARE
= HWC_HARDPROX
|HWC_PHYSID_CURSORS
;
548 gSysDevice
.FIRSTCSR
= 0;
549 gSysDevice
.PKTRATE
= 100;
551 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
552 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
553 strcpyW(gSysDevice
.PNPID
, SZ_NON_PLUG_N_PLAY
);
555 devices
= pXListInputDevices(data
->display
, &num_devices
);
558 WARN("XInput Extensions reported as not available\n");
561 TRACE("XListInputDevices reports %d devices\n", num_devices
);
562 for (loop
=0; loop
< num_devices
; loop
++)
565 char *device_type
= devices
[loop
].type
? XGetAtomName(data
->display
, devices
[loop
].type
) : NULL
;
566 WTI_CURSORS_INFO cursor
;
568 TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %d]\n",
569 loop
, (int) devices
[loop
].id
, devices
[loop
].name
, debugstr_a(device_type
),
570 devices
[loop
].num_classes
, devices
[loop
].use
);
572 switch (devices
[loop
].use
)
574 case IsXExtensionDevice
:
575 #ifdef IsXExtensionPointer
576 case IsXExtensionPointer
:
578 #ifdef IsXExtensionKeyboard
579 case IsXExtensionKeyboard
:
581 TRACE("Is XExtension: Device, Keyboard, or Pointer\n");
582 target
= &devices
[loop
];
584 if (strlen(target
->name
) >= WT_MAX_NAME_LEN
)
586 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target
->name
));
590 X11DRV_expect_error(data
->display
, Tablet_ErrorHandler
, NULL
);
591 opendevice
= pXOpenDevice(data
->display
,target
->id
);
592 if (!X11DRV_check_error() && opendevice
)
594 unsigned char map
[32];
598 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
599 cursor
.BUTTONS
= pXGetDeviceButtonMapping(data
->display
, opendevice
, map
, 32);
600 if (X11DRV_check_error() || cursor
.BUTTONS
<= 0)
602 TRACE("No buttons, Non Tablet Device\n");
603 pXCloseDevice(data
->display
, opendevice
);
607 for (i
=0; i
< cursor
.BUTTONS
; i
++,shft
++)
609 cursor
.BUTTONMAP
[i
] = map
[i
];
610 cursor
.SYSBTNMAP
[i
] = (1<<shft
);
612 pXCloseDevice(data
->display
, opendevice
);
616 WARN("Unable to open device %s\n",target
->name
);
619 MultiByteToWideChar(CP_UNIXCP
, 0, target
->name
, -1, cursor
.NAME
, WT_MAX_NAME_LEN
);
621 if (! is_tablet_cursor(target
->name
, device_type
))
623 WARN("Skipping device %d [name %s|type %s]; not apparently a tablet cursor type device\n",
624 loop
, devices
[loop
].name
, debugstr_a(device_type
));
629 cursor
.PKTDATA
= PK_TIME
| PK_CURSOR
| PK_BUTTONS
| PK_X
| PK_Y
|
630 PK_NORMAL_PRESSURE
| PK_TANGENT_PRESSURE
|
633 cursor
.PHYSID
= target
->id
;
635 cursor
.NPBTNMARKS
[0] = 0 ;
636 cursor
.NPBTNMARKS
[1] = 1 ;
637 cursor
.CAPABILITIES
= CRC_MULTIMODE
;
639 cursor
.TYPE
= get_cursor_type(target
->name
, device_type
);
641 any
= target
->inputclassinfo
;
643 for (class_loop
= 0; class_loop
< target
->num_classes
; class_loop
++)
649 Val
= (XValuatorInfoPtr
) any
;
650 TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n",
651 class_loop
, (int) Val
->class, Val
->length
, Val
->num_axes
, Val
->mode
, Val
->motion_buffer
);
652 if (TRACE_ON(wintab32
))
655 /* FIXME: This is imperfect; we compute our devices capabilities based upon the
656 ** first pen type device we find. However, a more correct implementation
657 ** would require acquiring a wide variety of tablets and running through
658 ** the various inputs to see what the values are. Odds are that a
659 ** more 'correct' algorithm would condense to this one anyway.
661 if (!axis_read_complete
&& cursor
.TYPE
== CSR_TYPE_PEN
)
663 Axis
= (XAxisInfoPtr
) ((char *) Val
+ sizeof
666 if (Val
->num_axes
>=1)
669 gSysDevice
.X
.axMin
= Axis
->min_value
;
670 gSysDevice
.X
.axMax
= Axis
->max_value
;
671 gSysDevice
.X
.axUnits
= TU_INCHES
;
672 gSysDevice
.X
.axResolution
= Axis
->resolution
;
673 gSysContext
.lcInOrgX
= Axis
->min_value
;
674 gSysContext
.lcOutOrgX
= Axis
->min_value
;
675 gSysContext
.lcInExtX
= Axis
->max_value
;
676 gSysContext
.lcOutExtX
= Axis
->max_value
;
679 if (Val
->num_axes
>=2)
682 gSysDevice
.Y
.axMin
= Axis
->min_value
;
683 gSysDevice
.Y
.axMax
= Axis
->max_value
;
684 gSysDevice
.Y
.axUnits
= TU_INCHES
;
685 gSysDevice
.Y
.axResolution
= Axis
->resolution
;
686 gSysContext
.lcInOrgY
= Axis
->min_value
;
687 gSysContext
.lcOutOrgY
= Axis
->min_value
;
688 gSysContext
.lcInExtY
= Axis
->max_value
;
689 gSysContext
.lcOutExtY
= Axis
->max_value
;
692 if (Val
->num_axes
>=3)
694 /* Axis 3 is Normal Pressure */
695 gSysDevice
.NPRESSURE
.axMin
= Axis
->min_value
;
696 gSysDevice
.NPRESSURE
.axMax
= Axis
->max_value
;
697 gSysDevice
.NPRESSURE
.axUnits
= TU_INCHES
;
698 gSysDevice
.NPRESSURE
.axResolution
=
702 if (Val
->num_axes
>= 5)
704 /* Axis 4 and 5 are X and Y tilt */
705 XAxisInfoPtr XAxis
= Axis
;
707 if (max (abs(Axis
->max_value
),
708 abs(XAxis
->max_value
)))
710 gSysDevice
.ORIENTATION
[0].axMin
= 0;
711 gSysDevice
.ORIENTATION
[0].axMax
= 3600;
712 gSysDevice
.ORIENTATION
[0].axUnits
= TU_CIRCLE
;
713 gSysDevice
.ORIENTATION
[0].axResolution
715 gSysDevice
.ORIENTATION
[1].axMin
= -1000;
716 gSysDevice
.ORIENTATION
[1].axMax
= 1000;
717 gSysDevice
.ORIENTATION
[1].axUnits
= TU_CIRCLE
;
718 gSysDevice
.ORIENTATION
[1].axResolution
720 gSysDevice
.ORIENTATION
[2].axMin
= 0;
721 gSysDevice
.ORIENTATION
[2].axMax
= 3600;
722 gSysDevice
.ORIENTATION
[2].axUnits
= TU_CIRCLE
;
723 gSysDevice
.ORIENTATION
[2].axResolution
728 axis_read_complete
= TRUE
;
737 Button
= (XButtonInfoPtr
) any
;
738 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
739 class_loop
, (int) Button
->class, Button
->length
, Button
->num_buttons
);
740 cursor
.BTNNAMES
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*cchBuf
);
741 for (i
= 0; i
< cursor
.BUTTONS
; i
++)
743 /* FIXME - these names are probably incorrect */
744 int cch
= strlenW(cursor
.NAME
) + 1;
745 while (cch
> cchBuf
- cchPos
- 1) /* we want one extra byte for the last NUL */
748 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchBuf
);
751 strcpyW(cursor
.BTNNAMES
+ cchPos
, cursor
.NAME
);
754 cursor
.BTNNAMES
[cchPos
++] = 0;
755 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchPos
);
756 cursor
.cchBTNNAMES
= cchPos
;
759 } /* switch any->class */
760 any
= (XAnyClassPtr
) ((char*) any
+ any
->length
);
761 } /* for class_loop */
762 if (!add_system_cursor(&cursor
))
763 FIXME("Skipping this cursor due to lack of system cursor slots.\n");
765 } /* switch devices.use */
767 } /* for XListInputDevices */
768 pXFreeDeviceList(devices
);
770 if (!axis_read_complete
)
772 disable_system_cursors();
773 WARN("Did not find a valid stylus, unable to determine system context parameters. Wintab is disabled.\n");
777 gSysDevice
.NCSRTYPES
= gNumCursors
;
781 static int figure_deg(int x
, int y
)
785 angle
= atan2((float)y
, (float)x
);
790 return (0.5 + (angle
* 1800.0 / M_PI
));
793 static int get_button_state(int curnum
)
795 return button_state
[curnum
];
798 static void set_button_state(int curnum
, XID deviceid
)
800 struct x11drv_thread_data
*data
= x11drv_thread_data();
807 device
= pXOpenDevice(data
->display
,deviceid
);
808 state
= pXQueryDeviceState(data
->display
,device
);
813 for (loop
= 0; loop
< state
->num_classes
; loop
++)
815 if (class->class == ButtonClass
)
818 XButtonState
*button_state
= (XButtonState
*)class;
819 for (loop2
= 0; loop2
< button_state
->num_buttons
; loop2
++)
821 if (button_state
->buttons
[loop2
/ 8] & (1 << (loop2
% 8)))
827 class = (XInputClass
*) ((char *) class + class->length
);
830 pXFreeDeviceState(state
);
831 button_state
[curnum
] = rc
;
834 static int cursor_from_device(DWORD deviceid
, LPWTI_CURSORS_INFO
*cursorp
)
837 for (i
= 0; i
< CURSORMAX
; i
++)
838 if (gSysCursor
[i
].ACTIVE
&& gSysCursor
[i
].PHYSID
== deviceid
)
840 *cursorp
= &gSysCursor
[i
];
844 ERR("Could not map device id %d to a cursor\n", (int) deviceid
);
848 static DWORD
get_changed_state( WTPACKET
*pkt
)
852 if (pkt
->pkX
!= last_packet
.pkX
)
854 if (pkt
->pkY
!= last_packet
.pkY
)
856 if (pkt
->pkZ
!= last_packet
.pkZ
)
858 if (pkt
->pkSerialNumber
!= last_packet
.pkSerialNumber
)
859 change
|= PK_SERIAL_NUMBER
;
860 if (pkt
->pkTime
!= last_packet
.pkTime
)
862 if (pkt
->pkNormalPressure
!= last_packet
.pkNormalPressure
)
863 change
|= PK_NORMAL_PRESSURE
;
864 if (pkt
->pkTangentPressure
!= last_packet
.pkTangentPressure
)
865 change
|= PK_TANGENT_PRESSURE
;
866 if (pkt
->pkCursor
!= last_packet
.pkCursor
)
868 if (pkt
->pkButtons
!= last_packet
.pkButtons
)
869 change
|= PK_BUTTONS
;
870 if (pkt
->pkOrientation
.orAzimuth
!= last_packet
.pkOrientation
.orAzimuth
||
871 pkt
->pkOrientation
.orAltitude
!= last_packet
.pkOrientation
.orAltitude
||
872 pkt
->pkOrientation
.orTwist
!= last_packet
.pkOrientation
.orTwist
)
873 change
|= PK_ORIENTATION
;
874 if (pkt
->pkRotation
.roPitch
!= last_packet
.pkRotation
.roPitch
||
875 pkt
->pkRotation
.roRoll
!= last_packet
.pkRotation
.roRoll
||
876 pkt
->pkRotation
.roYaw
!= last_packet
.pkRotation
.roYaw
)
877 change
|= PK_ROTATION
;
882 static BOOL
motion_event( HWND hwnd
, XEvent
*event
)
884 XDeviceMotionEvent
*motion
= (XDeviceMotionEvent
*)event
;
885 LPWTI_CURSORS_INFO cursor
;
886 int curnum
= cursor_from_device(motion
->deviceid
, &cursor
);
890 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
892 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd
, (int) motion
->deviceid
, curnum
);
894 /* Set cursor to inverted if cursor is the eraser */
895 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
896 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(motion
->time
);
897 gMsgPacket
.pkSerialNumber
= gSerial
++;
898 gMsgPacket
.pkCursor
= curnum
;
899 gMsgPacket
.pkX
= motion
->axis_data
[0];
900 gMsgPacket
.pkY
= motion
->axis_data
[1];
901 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(motion
->axis_data
[3],motion
->axis_data
[4]);
902 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max
903 (abs(motion
->axis_data
[3]),
904 abs(motion
->axis_data
[4])))
905 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
906 gMsgPacket
.pkNormalPressure
= motion
->axis_data
[2];
907 gMsgPacket
.pkButtons
= get_button_state(curnum
);
908 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
909 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
910 last_packet
= gMsgPacket
;
914 static BOOL
button_event( HWND hwnd
, XEvent
*event
)
916 XDeviceButtonEvent
*button
= (XDeviceButtonEvent
*) event
;
917 LPWTI_CURSORS_INFO cursor
;
918 int curnum
= cursor_from_device(button
->deviceid
, &cursor
);
922 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
924 TRACE("Received tablet button %s event\n", (event
->type
== button_press_type
)?"press":"release");
926 /* Set cursor to inverted if cursor is the eraser */
927 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
928 set_button_state(curnum
, button
->deviceid
);
929 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(button
->time
);
930 gMsgPacket
.pkSerialNumber
= gSerial
++;
931 gMsgPacket
.pkCursor
= curnum
;
932 if (button
->axes_count
> 0) {
933 gMsgPacket
.pkX
= button
->axis_data
[0];
934 gMsgPacket
.pkY
= button
->axis_data
[1];
935 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(button
->axis_data
[3],button
->axis_data
[4]);
936 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(button
->axis_data
[3]),
937 abs(button
->axis_data
[4])))
938 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
939 gMsgPacket
.pkNormalPressure
= button
->axis_data
[2];
941 gMsgPacket
.pkX
= last_packet
.pkX
;
942 gMsgPacket
.pkY
= last_packet
.pkY
;
943 gMsgPacket
.pkOrientation
= last_packet
.pkOrientation
;
944 gMsgPacket
.pkNormalPressure
= last_packet
.pkNormalPressure
;
946 gMsgPacket
.pkButtons
= get_button_state(curnum
);
947 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
948 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
949 last_packet
= gMsgPacket
;
953 static BOOL
key_event( HWND hwnd
, XEvent
*event
)
955 if (event
->type
== key_press_type
)
956 FIXME("Received tablet key press event\n");
958 FIXME("Received tablet key release event\n");
962 static BOOL
proximity_event( HWND hwnd
, XEvent
*event
)
964 XProximityNotifyEvent
*proximity
= (XProximityNotifyEvent
*) event
;
965 LPWTI_CURSORS_INFO cursor
;
966 int curnum
= cursor_from_device(proximity
->deviceid
, &cursor
);
967 LPARAM proximity_info
;
969 TRACE("hwnd=%p\n", hwnd
);
974 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
976 /* Set cursor to inverted if cursor is the eraser */
977 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
978 gMsgPacket
.pkStatus
|= (event
->type
==proximity_out_type
)?TPS_PROXIMITY
:0;
979 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(proximity
->time
);
980 gMsgPacket
.pkSerialNumber
= gSerial
++;
981 gMsgPacket
.pkCursor
= curnum
;
982 gMsgPacket
.pkX
= proximity
->axis_data
[0];
983 gMsgPacket
.pkY
= proximity
->axis_data
[1];
984 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(proximity
->axis_data
[3],proximity
->axis_data
[4]);
985 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(proximity
->axis_data
[3]),
986 abs(proximity
->axis_data
[4])))
987 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
988 gMsgPacket
.pkNormalPressure
= proximity
->axis_data
[2];
989 gMsgPacket
.pkButtons
= get_button_state(curnum
);
991 /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context
992 * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct
994 * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity"
995 * WPARAM contains context handle.
996 * HWND to HCTX is handled by wintab32.
998 proximity_info
= MAKELPARAM((event
->type
== proximity_in_type
),
999 (event
->type
== proximity_in_type
) || (event
->type
== proximity_out_type
));
1000 SendMessageW(hwndTabletDefault
, WT_PROXIMITY
, (WPARAM
)hwnd
, proximity_info
);
1004 /***********************************************************************
1005 * X11DRV_AttachEventQueueToTablet (X11DRV.@)
1007 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1009 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
1013 XDeviceInfo
*devices
;
1014 XDeviceInfo
*target
= NULL
;
1015 XDevice
*the_device
;
1016 XEventClass event_list
[7];
1017 Window win
= X11DRV_get_whole_window( hOwner
);
1019 if (!win
|| !xinput_handle
) return 0;
1021 TRACE("Creating context for window %p (%lx) %i cursors\n", hOwner
, win
, gNumCursors
);
1023 devices
= pXListInputDevices(data
->display
, &num_devices
);
1025 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
1026 for (cur_loop
=0; cur_loop
< CURSORMAX
; cur_loop
++)
1028 char cursorNameA
[WT_MAX_NAME_LEN
];
1031 if (!gSysCursor
[cur_loop
].ACTIVE
) continue;
1033 /* the cursor name fits in the buffer because too long names are skipped */
1034 WideCharToMultiByte(CP_UNIXCP
, 0, gSysCursor
[cur_loop
].NAME
, -1, cursorNameA
, WT_MAX_NAME_LEN
, NULL
, NULL
);
1035 for (loop
=0; loop
< num_devices
; loop
++)
1036 if (strcmp(devices
[loop
].name
, cursorNameA
) == 0)
1037 target
= &devices
[loop
];
1039 WARN("Cursor Name %s not found in list of targets.\n", cursorNameA
);
1043 TRACE("Opening cursor %i id %i\n",cur_loop
,(INT
)target
->id
);
1045 the_device
= pXOpenDevice(data
->display
, target
->id
);
1049 WARN("Unable to Open device\n");
1053 if (the_device
->num_classes
> 0)
1055 DeviceKeyPress(the_device
, key_press_type
, event_list
[event_number
]);
1056 if (key_press_type
) event_number
++;
1057 DeviceKeyRelease(the_device
, key_release_type
, event_list
[event_number
]);
1058 if (key_release_type
) event_number
++;
1059 DeviceButtonPress(the_device
, button_press_type
, event_list
[event_number
]);
1060 if (button_press_type
) event_number
++;
1061 DeviceButtonRelease(the_device
, button_release_type
, event_list
[event_number
]);
1062 if (button_release_type
) event_number
++;
1063 DeviceMotionNotify(the_device
, motion_type
, event_list
[event_number
]);
1064 if (motion_type
) event_number
++;
1065 ProximityIn(the_device
, proximity_in_type
, event_list
[event_number
]);
1066 if (proximity_in_type
) event_number
++;
1067 ProximityOut(the_device
, proximity_out_type
, event_list
[event_number
]);
1068 if (proximity_out_type
) event_number
++;
1071 X11DRV_register_event_handler( key_press_type
, key_event
, "XInput KeyPress" );
1072 if (key_release_type
)
1073 X11DRV_register_event_handler( key_release_type
, key_event
, "XInput KeyRelease" );
1074 if (button_press_type
)
1075 X11DRV_register_event_handler( button_press_type
, button_event
, "XInput ButtonPress" );
1076 if (button_release_type
)
1077 X11DRV_register_event_handler( button_release_type
, button_event
, "XInput ButtonRelease" );
1079 X11DRV_register_event_handler( motion_type
, motion_event
, "XInput MotionNotify" );
1080 if (proximity_in_type
)
1081 X11DRV_register_event_handler( proximity_in_type
, proximity_event
, "XInput ProximityIn" );
1082 if (proximity_out_type
)
1083 X11DRV_register_event_handler( proximity_out_type
, proximity_event
, "XInput ProximityOut" );
1085 pXSelectExtensionEvent(data
->display
, win
, event_list
, event_number
);
1088 XSync(data
->display
, False
);
1089 X11DRV_check_error();
1091 if (NULL
!= devices
) pXFreeDeviceList(devices
);
1095 /***********************************************************************
1096 * X11DRV_GetCurrentPacket (X11DRV.@)
1098 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1100 *packet
= gMsgPacket
;
1105 static inline int CopyTabletData(LPVOID target
, LPCVOID src
, INT size
)
1108 * It is valid to call CopyTabletData with NULL.
1109 * This handles the WTInfo() case where lpOutput is null.
1112 memcpy(target
,src
,size
);
1116 /***********************************************************************
1117 * X11DRV_WTInfoW (X11DRV.@)
1119 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1122 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1123 * lpOutput == NULL signifies the user only wishes
1124 * to find the size of the data.
1126 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1130 LPWTI_CURSORS_INFO tgtcursor
;
1131 TRACE("(%u, %u, %p)\n", wCategory
, nIndex
, lpOutput
);
1133 if (!xinput_handle
) return 0;
1138 /* return largest necessary buffer */
1139 TRACE("%i cursors\n",gNumCursors
);
1142 FIXME("Return proper size\n");
1153 static const WCHAR driver
[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1154 rc
= CopyTabletData(lpOutput
, driver
, (strlenW(driver
) + 1) * sizeof(WCHAR
));
1157 case IFC_SPECVERSION
:
1158 version
= (0x01) | (0x01 << 8);
1159 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1161 case IFC_IMPLVERSION
:
1162 version
= (0x00) | (0x01 << 8);
1163 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1167 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1171 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1174 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex
);
1180 case WTI_DEFCONTEXT
:
1184 /* report 0 if wintab is disabled */
1185 if (0 == gNumCursors
)
1188 rc
= CopyTabletData(lpOutput
, &gSysContext
,
1189 sizeof(LOGCONTEXTW
));
1192 rc
= CopyTabletData(lpOutput
, gSysContext
.lcName
,
1193 (strlenW(gSysContext
.lcName
)+1) * sizeof(WCHAR
));
1196 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOptions
,
1200 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcStatus
,
1204 rc
= CopyTabletData (lpOutput
, &gSysContext
.lcLocks
,
1208 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMsgBase
,
1212 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcDevice
,
1216 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktRate
,
1220 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktData
,
1224 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktMode
,
1228 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMoveMask
,
1232 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnDnMask
,
1236 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnUpMask
,
1240 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgX
,
1244 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgY
,
1248 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgZ
,
1252 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtX
,
1256 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtY
,
1260 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtZ
,
1264 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgX
,
1268 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgY
,
1272 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgZ
,
1276 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtX
,
1280 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtY
,
1284 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtZ
,
1288 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensX
,
1292 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensY
,
1296 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensZ
,
1300 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysMode
,
1304 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgX
,
1308 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgY
,
1312 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtX
,
1316 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtY
,
1320 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensX
,
1324 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensY
,
1328 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex
);
1342 case WTI_CURSORS
+10:
1343 case WTI_CURSORS
+11:
1344 /* CURSORMAX == 12 */
1345 /* FIXME: dynamic cursor support */
1346 /* Apps will poll different slots to detect what cursors are available
1347 * if there isn't a cursor for this slot return 0 */
1348 if (!gSysCursor
[wCategory
- WTI_CURSORS
].ACTIVE
)
1352 tgtcursor
= &gSysCursor
[wCategory
- WTI_CURSORS
];
1356 rc
= CopyTabletData(lpOutput
, tgtcursor
->NAME
,
1357 (strlenW(tgtcursor
->NAME
)+1) * sizeof(WCHAR
));
1360 rc
= CopyTabletData(lpOutput
,&tgtcursor
->ACTIVE
,
1364 rc
= CopyTabletData(lpOutput
,&tgtcursor
->PKTDATA
,
1368 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONS
,
1371 case CSR_BUTTONBITS
:
1372 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONBITS
,
1376 FIXME("Button Names not returned correctly\n");
1377 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BTNNAMES
,
1378 tgtcursor
->cchBTNNAMES
*sizeof(WCHAR
));
1381 rc
= CopyTabletData(lpOutput
,tgtcursor
->BUTTONMAP
,
1385 rc
= CopyTabletData(lpOutput
,tgtcursor
->SYSBTNMAP
,
1388 case CSR_NPBTNMARKS
:
1389 rc
= CopyTabletData(lpOutput
,tgtcursor
->NPBTNMARKS
,
1393 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBUTTON
,
1396 case CSR_NPRESPONSE
:
1397 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1401 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBUTTON
,
1404 case CSR_TPBTNMARKS
:
1405 rc
= CopyTabletData(lpOutput
,tgtcursor
->TPBTNMARKS
,
1408 case CSR_TPRESPONSE
:
1409 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1415 id
= tgtcursor
->PHYSID
;
1416 rc
= CopyTabletData(lpOutput
,&id
,sizeof(DWORD
));
1420 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MODE
,sizeof(UINT
));
1422 case CSR_MINPKTDATA
:
1423 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINPKTDATA
,
1426 case CSR_MINBUTTONS
:
1427 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINBUTTONS
,
1430 case CSR_CAPABILITIES
:
1431 rc
= CopyTabletData(lpOutput
,&tgtcursor
->CAPABILITIES
,
1435 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TYPE
,
1439 FIXME("WTI_CURSORS unhandled index %i\n",nIndex
);
1448 rc
= CopyTabletData(lpOutput
,gSysDevice
.NAME
,
1449 (strlenW(gSysDevice
.NAME
)+1) * sizeof(WCHAR
));
1452 rc
= CopyTabletData(lpOutput
,&gSysDevice
.HARDWARE
,
1456 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NCSRTYPES
,
1460 rc
= CopyTabletData(lpOutput
,&gSysDevice
.FIRSTCSR
,
1464 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTRATE
,
1468 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTDATA
,
1472 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTMODE
,
1476 rc
= CopyTabletData(lpOutput
,&gSysDevice
.CSRDATA
,
1480 rc
= CopyTabletData(lpOutput
,&gSysDevice
.XMARGIN
,
1484 rc
= CopyTabletData(lpOutput
,&gSysDevice
.YMARGIN
,
1488 rc
= 0; /* unsupported */
1490 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1495 rc
= CopyTabletData(lpOutput
,&gSysDevice
.X
,
1499 rc
= CopyTabletData(lpOutput
,&gSysDevice
.Y
,
1503 rc
= 0; /* unsupported */
1505 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1510 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NPRESSURE
,
1514 rc
= 0; /* unsupported */
1516 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1520 case DVC_ORIENTATION
:
1521 rc
= CopyTabletData(lpOutput
,gSysDevice
.ORIENTATION
,
1525 rc
= 0; /* unsupported */
1527 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1532 rc
= CopyTabletData(lpOutput
,gSysDevice
.PNPID
,
1533 (strlenW(gSysDevice
.PNPID
)+1)*sizeof(WCHAR
));
1536 FIXME("WTI_DEVICES unhandled index %i\n",nIndex
);
1541 FIXME("Unhandled Category %i\n",wCategory
);
1546 #else /* SONAME_LIBXI */
1548 /***********************************************************************
1549 * AttachEventQueueToTablet (X11DRV.@)
1551 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1556 /***********************************************************************
1557 * GetCurrentPacket (X11DRV.@)
1559 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1564 /***********************************************************************
1565 * LoadTabletInfo (X11DRV.@)
1567 BOOL CDECL
X11DRV_LoadTabletInfo(HWND hwnddefault
)
1572 /***********************************************************************
1573 * WTInfoW (X11DRV.@)
1575 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1580 #endif /* SONAME_LIBXI */