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
35 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(wintab32
);
40 #define WT_MAX_NAME_LEN 256
42 typedef struct tagWTI_CURSORS_INFO
44 WCHAR NAME
[WT_MAX_NAME_LEN
];
45 /* a displayable zero-terminated string containing the name of the
49 /* whether the cursor is currently connected. */
51 /* a bit mask indicating the packet data items supported when this
52 * cursor is connected.
55 /* the number of buttons on this cursor. */
57 /* the number of bits of raw button data returned by the hardware.*/
60 /* a list of zero-terminated strings containing the names of the
61 * cursor's buttons. The number of names in the list is the same as the
62 * number of buttons on the cursor. The names are separated by a single
63 * zero character; the list is terminated by two zero characters.
66 /* a 32 byte array of logical button numbers, one for each physical
70 /* a 32 byte array of button action codes, one for each logical
74 /* the physical button number of the button that is controlled by normal
78 /* an array of two UINTs, specifying the button marks for the normal
79 * pressure button. The first UINT contains the release mark; the second
80 * contains the press mark.
83 /* an array of UINTs describing the pressure response curve for normal
87 /* the physical button number of the button that is controlled by
88 * tangential pressure.
91 /* an array of two UINTs, specifying the button marks for the tangential
92 * pressure button. The first UINT contains the release mark; the second
93 * contains the press mark.
96 /* an array of UINTs describing the pressure response curve for
97 * tangential pressure.
100 /* a manufacturer-specific physical identifier for the cursor. This
101 * value will distinguish the physical cursor from others on the same
102 * device. This physical identifier allows applications to bind
103 * functions to specific physical cursors, even if category numbers
104 * change and multiple, otherwise identical, physical cursors are
108 /* the cursor mode number of this cursor type, if this cursor type has
109 * the CRC_MULTIMODE capability.
112 /* the minimum set of data available from a physical cursor in this
113 * cursor type, if this cursor type has the CRC_AGGREGATE capability.
116 /* the minimum number of buttons of physical cursors in the cursor type,
117 * if this cursor type has the CRC_AGGREGATE capability.
120 /* flags indicating cursor capabilities, as defined below:
122 Indicates this cursor type describes one of several modes of a
123 single physical cursor. Consecutive cursor type categories
124 describe the modes; the CSR_MODE data item gives the mode number
127 Indicates this cursor type describes several physical cursors
128 that cannot be distinguished by software.
130 Indicates this cursor type describes the physical cursor in its
131 inverted orientation; the previous consecutive cursor type
132 category describes the normal orientation.
135 /* Manufacturer Unique id for the item type */
136 } WTI_CURSORS_INFO
, *LPWTI_CURSORS_INFO
;
139 typedef struct tagWTI_DEVICES_INFO
141 WCHAR NAME
[WT_MAX_NAME_LEN
];
142 /* a displayable null- terminated string describing the device,
143 * manufacturer, and revision level.
146 /* flags indicating hardware and driver capabilities, as defined
149 Indicates that the display and digitizer share the same surface.
151 Indicates that the cursor must be in physical contact with the
152 device to report position.
154 Indicates that device can generate events when the cursor is
155 entering and leaving the physical detection range.
157 Indicates that device can uniquely identify the active cursor in
161 /* the number of supported cursor types.*/
163 /* the first cursor type number for the device. */
165 /* the maximum packet report rate in Hertz. */
167 /* a bit mask indicating which packet data items are always available.*/
169 /* a bit mask indicating which packet data items are physically
170 * relative, i.e., items for which the hardware can only report change,
171 * not absolute measurement.
174 /* a bit mask indicating which packet data items are only available when
175 * certain cursors are connected. The individual cursor descriptions
176 * must be consulted to determine which cursors return which data.
181 /* the size of tablet context margins in tablet native coordinates, in
182 * the x, y, and z directions, respectively.
187 /* the tablet's range and resolution capabilities, in the x, y, and z
188 * axes, respectively.
192 /* the tablet's range and resolution capabilities, for the normal and
193 * tangential pressure inputs, respectively.
196 /* a 3-element array describing the tablet's orientation range and
197 * resolution capabilities.
200 /* a 3-element array describing the tablet's rotation range and
201 * resolution capabilities.
203 WCHAR PNPID
[WT_MAX_NAME_LEN
];
204 /* a null-terminated string containing the devices Plug and Play ID.*/
205 } WTI_DEVICES_INFO
, *LPWTI_DEVICES_INFO
;
208 /***********************************************************************
209 * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE
210 * In Wintab 1.2, a CSR_TYPE feature was added. This adds the
211 * ability to return a type of cursor on a tablet.
212 * Unfortunately, we cannot get the cursor type directly from X,
213 * and it is not specified directly anywhere. So we virtualize
214 * the type here. (This is unfortunate, the kernel module has
215 * the exact type, but we have no way of getting that module to
216 * pass us that type).
218 * Reference linuxwacom driver project wcmCommon.c function
219 * idtotype for a much larger list of CSR_TYPE.
221 * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wcmCommon.c?view=markup
223 * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this:
224 * (cursor.TYPE & 0x0F06) == target_cursor_type
225 * Reference: Section Unique ID
226 * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
228 #define CSR_TYPE_PEN 0x822
229 #define CSR_TYPE_ERASER 0x82a
230 #define CSR_TYPE_MOUSE_2D 0x007
231 #define CSR_TYPE_MOUSE_4D 0x094
232 /* CSR_TYPE_OTHER is a special value! assumed no real world significance
233 * if a stylus type or eraser type eventually have this value
234 * it'll be a bug. As of 2008 05 21 we can be sure because
235 * linux wacom lists all the known values and this isn't one of them */
236 #define CSR_TYPE_OTHER 0x000
238 typedef struct tagWTPACKET
{
249 UINT pkNormalPressure
;
250 UINT pkTangentPressure
;
251 ORIENTATION pkOrientation
;
252 ROTATION pkRotation
; /* 1.1 */
253 } WTPACKET
, *LPWTPACKET
;
258 #include <X11/Xlib.h>
259 #include <X11/extensions/XInput.h>
261 static int motion_type
;
262 static int button_press_type
;
263 static int button_release_type
;
264 static int key_press_type
;
265 static int key_release_type
;
266 static int proximity_in_type
;
267 static int proximity_out_type
;
269 static HWND hwndTabletDefault
;
270 static WTPACKET gMsgPacket
;
271 static DWORD gSerial
;
272 static WTPACKET last_packet
;
274 /* Reference: http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
276 * Cursors come in sets of 3 normally
277 * Cursor #0 = puck device 1
278 * Cursor #1 = stylus device 1
279 * Cursor #2 = eraser device 1
280 * Cursor #3 = puck device 2
281 * Cursor #4 = stylus device 2
282 * Cursor #5 = eraser device 2
285 * A dual tracking/multimode tablet is one
286 * that supports 2 independent cursors of the same or
287 * different types simultaneously on a single tablet.
288 * This makes our cursor layout potentially like this
289 * Cursor #0 = puck 1 device 1
290 * Cursor #1 = stylus 1 device 1
291 * Cursor #2 = eraser 1 device 1
292 * Cursor #3 = puck 2 device 1
293 * Cursor #4 = stylus 2 device 1
294 * Cursor #5 = eraser 2 device 1
295 * Cursor #6 = puck 1 device 2
298 * So with multimode tablets we could potentially need
299 * 2 slots of the same type per tablet i.e.
300 * you are using 2 styluses at once so they would
301 * get placed in Cursors #1 and Cursor #4
303 * Now say someone has 2 multimode tablets with 2 erasers each
304 * now we would need Cursor #2, #5, #8, #11
305 * So to support that we need CURSORMAX of 12 (0 to 11)
306 * FIXME: we don't support more than 4 regular tablets or 2 multimode tablets */
308 static INT button_state
[CURSORMAX
];
310 static LOGCONTEXTW gSysContext
;
311 static WTI_DEVICES_INFO gSysDevice
;
312 static WTI_CURSORS_INFO gSysCursor
[CURSORMAX
];
313 static INT gNumCursors
; /* do NOT use this to iterate through gSysCursor slots */
317 static void *xinput_handle
;
319 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
320 MAKE_FUNCPTR(XListInputDevices
)
321 MAKE_FUNCPTR(XFreeDeviceList
)
322 MAKE_FUNCPTR(XOpenDevice
)
323 MAKE_FUNCPTR(XQueryDeviceState
)
324 MAKE_FUNCPTR(XGetDeviceButtonMapping
)
325 MAKE_FUNCPTR(XCloseDevice
)
326 MAKE_FUNCPTR(XSelectExtensionEvent
)
327 MAKE_FUNCPTR(XFreeDeviceState
)
330 static INT
X11DRV_XInput_Init(void)
332 xinput_handle
= dlopen(SONAME_LIBXI
, RTLD_NOW
);
335 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xinput_handle, #f)) == NULL) goto sym_not_found
336 LOAD_FUNCPTR(XListInputDevices
);
337 LOAD_FUNCPTR(XFreeDeviceList
);
338 LOAD_FUNCPTR(XOpenDevice
);
339 LOAD_FUNCPTR(XGetDeviceButtonMapping
);
340 LOAD_FUNCPTR(XCloseDevice
);
341 LOAD_FUNCPTR(XSelectExtensionEvent
);
342 LOAD_FUNCPTR(XQueryDeviceState
);
343 LOAD_FUNCPTR(XFreeDeviceState
);
351 static int Tablet_ErrorHandler(Display
*dpy
, XErrorEvent
*event
, void* arg
)
356 static void trace_axes(XValuatorInfoPtr val
)
361 for (i
= 0, axis
= val
->axes
; i
< val
->num_axes
; i
++, axis
++)
362 TRACE(" Axis %d: [resolution %d|min_value %d|max_value %d]\n", i
, axis
->resolution
, axis
->min_value
, axis
->max_value
);
365 static BOOL
match_token(const char *haystack
, const char *needle
)
368 for (p
= haystack
; *p
; )
370 while (*p
&& isspace(*p
))
375 for (q
= needle
; *q
&& *p
&& tolower(*p
) == tolower(*q
); q
++)
377 if (! *q
&& (isspace(*p
) || *p
== ':' || !*p
))
380 while (*p
&& ! isspace(*p
))
386 /* Determining if an X device is a Tablet style device is an imperfect science.
387 ** We rely on common conventions around device names as well as the type reported
388 ** by Wacom tablets. This code will likely need to be expanded for alternate tablet types
390 ** Wintab refers to any device that interacts with the tablet as a cursor,
391 ** (stylus, eraser, tablet mouse, airbrush, etc)
392 ** this is not to be confused with wacom x11 configuration "cursor" device.
393 ** Wacoms x11 config "cursor" refers to its device slot (which we mirror with
394 ** our gSysCursors) for puck like devices (tablet mice essentially).
397 static BOOL
is_tablet_cursor(const char *name
, const char *type
)
400 static const char *tablet_cursor_allowlist
[] = {
412 for (i
=0; tablet_cursor_allowlist
[i
] != NULL
; i
++) {
413 if (name
&& match_token(name
, tablet_cursor_allowlist
[i
]))
415 if (type
&& match_token(type
, tablet_cursor_allowlist
[i
]))
421 static UINT
get_cursor_type(const char *name
, const char *type
)
424 static const char* tablet_stylus_allowlist
[] = {
432 /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
433 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
434 if (type
&& match_token(type
, tablet_stylus_allowlist
[i
]))
437 if (type
&& match_token(type
, "eraser"))
438 return CSR_TYPE_ERASER
;
439 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
440 if (name
&& match_token(name
, tablet_stylus_allowlist
[i
]))
443 if (name
&& match_token(name
, "eraser"))
444 return CSR_TYPE_ERASER
;
446 return CSR_TYPE_OTHER
;
449 /* cursors are placed in gSysCursor rows depending on their type
450 * see CURSORMAX comments for more detail */
451 static BOOL
add_system_cursor(LPWTI_CURSORS_INFO cursor
)
455 if (cursor
->TYPE
== CSR_TYPE_PEN
)
457 else if (cursor
->TYPE
== CSR_TYPE_ERASER
)
460 for (; offset
< CURSORMAX
; offset
+= 3)
462 if (!gSysCursor
[offset
].ACTIVE
)
464 gSysCursor
[offset
] = *cursor
;
473 static void disable_system_cursors(void)
477 for (i
= 0; i
< CURSORMAX
; ++i
)
479 gSysCursor
[i
].ACTIVE
= 0;
486 /***********************************************************************
487 * x11drv_tablet_load_info
489 NTSTATUS
x11drv_tablet_load_info( void *hwnd
)
491 static const WCHAR SZ_CONTEXT_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
492 static const WCHAR SZ_DEVICE_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
493 static const WCHAR SZ_NON_PLUG_N_PLAY
[] = {'n','o','n','-','p','l','u','g','-','n','-','p','l','a','y',0};
495 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
498 XDeviceInfo
*devices
;
499 XDeviceInfo
*target
= NULL
;
500 BOOL axis_read_complete
= FALSE
;
503 XButtonInfoPtr Button
;
504 XValuatorInfoPtr Val
;
509 if (!X11DRV_XInput_Init())
511 ERR("Unable to initialize the XInput library.\n");
515 hwndTabletDefault
= hwnd
;
517 /* Do base initialization */
518 wcscpy(gSysContext
.lcName
, SZ_CONTEXT_NAME
);
519 wcscpy(gSysDevice
.NAME
, SZ_DEVICE_NAME
);
521 gSysContext
.lcOptions
= CXO_SYSTEM
;
522 gSysContext
.lcLocks
= CXL_INSIZE
| CXL_INASPECT
| CXL_MARGIN
|
523 CXL_SENSITIVITY
| CXL_SYSOUT
;
525 gSysContext
.lcMsgBase
= WT_DEFBASE
;
526 gSysContext
.lcDevice
= 0;
527 gSysContext
.lcPktData
=
528 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
529 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
530 gSysContext
.lcMoveMask
=
531 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
532 gSysContext
.lcStatus
= CXS_ONTOP
;
533 gSysContext
.lcPktRate
= 100;
534 gSysContext
.lcBtnDnMask
= 0xffffffff;
535 gSysContext
.lcBtnUpMask
= 0xffffffff;
536 gSysContext
.lcSensX
= 65536;
537 gSysContext
.lcSensY
= 65536;
538 gSysContext
.lcSensX
= 65536;
539 gSysContext
.lcSensZ
= 65536;
540 gSysContext
.lcSysSensX
= 65536;
541 gSysContext
.lcSysSensY
= 65536;
542 gSysContext
.lcSysExtX
= NtUserGetSystemMetrics( SM_CXVIRTUALSCREEN
);
543 gSysContext
.lcSysExtY
= NtUserGetSystemMetrics( SM_CYVIRTUALSCREEN
);
545 /* initialize cursors */
546 disable_system_cursors();
548 /* Device Defaults */
549 gSysDevice
.HARDWARE
= HWC_HARDPROX
|HWC_PHYSID_CURSORS
;
550 gSysDevice
.FIRSTCSR
= 0;
551 gSysDevice
.PKTRATE
= 100;
553 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
554 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
555 wcscpy(gSysDevice
.PNPID
, SZ_NON_PLUG_N_PLAY
);
557 devices
= pXListInputDevices(data
->display
, &num_devices
);
560 WARN("XInput Extensions reported as not available\n");
563 TRACE("XListInputDevices reports %d devices\n", num_devices
);
564 for (loop
=0; loop
< num_devices
; loop
++)
567 char *device_type
= devices
[loop
].type
? XGetAtomName(data
->display
, devices
[loop
].type
) : NULL
;
568 WTI_CURSORS_INFO cursor
;
570 TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %d]\n",
571 loop
, (int) devices
[loop
].id
, devices
[loop
].name
, debugstr_a(device_type
),
572 devices
[loop
].num_classes
, devices
[loop
].use
);
574 switch (devices
[loop
].use
)
576 case IsXExtensionDevice
:
577 #ifdef IsXExtensionPointer
578 case IsXExtensionPointer
:
580 #ifdef IsXExtensionKeyboard
581 case IsXExtensionKeyboard
:
583 TRACE("Is XExtension: Device, Keyboard, or Pointer\n");
584 target
= &devices
[loop
];
586 if (strlen(target
->name
) >= WT_MAX_NAME_LEN
)
588 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target
->name
));
592 X11DRV_expect_error(data
->display
, Tablet_ErrorHandler
, NULL
);
593 opendevice
= pXOpenDevice(data
->display
,target
->id
);
594 if (!X11DRV_check_error() && opendevice
)
596 unsigned char map
[32];
600 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
601 cursor
.BUTTONS
= pXGetDeviceButtonMapping(data
->display
, opendevice
, map
, 32);
602 if (X11DRV_check_error() || cursor
.BUTTONS
<= 0)
604 TRACE("No buttons, Non Tablet Device\n");
605 pXCloseDevice(data
->display
, opendevice
);
609 for (i
=0; i
< cursor
.BUTTONS
; i
++,shft
++)
611 cursor
.BUTTONMAP
[i
] = map
[i
];
612 cursor
.SYSBTNMAP
[i
] = (1<<shft
);
614 pXCloseDevice(data
->display
, opendevice
);
618 WARN("Unable to open device %s\n",target
->name
);
621 ntdll_umbstowcs(target
->name
, strlen(target
->name
) + 1, cursor
.NAME
, WT_MAX_NAME_LEN
);
623 if (! is_tablet_cursor(target
->name
, device_type
))
625 WARN("Skipping device %d [name %s|type %s]; not apparently a tablet cursor type device\n",
626 loop
, devices
[loop
].name
, debugstr_a(device_type
));
631 cursor
.PKTDATA
= PK_TIME
| PK_CURSOR
| PK_BUTTONS
| PK_X
| PK_Y
|
632 PK_NORMAL_PRESSURE
| PK_TANGENT_PRESSURE
|
635 cursor
.PHYSID
= target
->id
;
637 cursor
.NPBTNMARKS
[0] = 0 ;
638 cursor
.NPBTNMARKS
[1] = 1 ;
639 cursor
.CAPABILITIES
= CRC_MULTIMODE
;
641 cursor
.TYPE
= get_cursor_type(target
->name
, device_type
);
643 any
= target
->inputclassinfo
;
645 for (class_loop
= 0; class_loop
< target
->num_classes
; class_loop
++)
651 Val
= (XValuatorInfoPtr
) any
;
652 TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n",
653 class_loop
, (int) Val
->class, Val
->length
, Val
->num_axes
, Val
->mode
, Val
->motion_buffer
);
654 if (TRACE_ON(wintab32
))
657 /* FIXME: This is imperfect; we compute our devices capabilities based upon the
658 ** first pen type device we find. However, a more correct implementation
659 ** would require acquiring a wide variety of tablets and running through
660 ** the various inputs to see what the values are. Odds are that a
661 ** more 'correct' algorithm would condense to this one anyway.
663 if (!axis_read_complete
&& cursor
.TYPE
== CSR_TYPE_PEN
)
665 Axis
= (XAxisInfoPtr
) ((char *) Val
+ sizeof
668 if (Val
->num_axes
>=1)
671 gSysDevice
.X
.axMin
= Axis
->min_value
;
672 gSysDevice
.X
.axMax
= Axis
->max_value
;
673 gSysDevice
.X
.axUnits
= TU_INCHES
;
674 gSysDevice
.X
.axResolution
= Axis
->resolution
;
675 gSysContext
.lcInOrgX
= Axis
->min_value
;
676 gSysContext
.lcOutOrgX
= Axis
->min_value
;
677 gSysContext
.lcInExtX
= Axis
->max_value
;
678 gSysContext
.lcOutExtX
= Axis
->max_value
;
681 if (Val
->num_axes
>=2)
684 gSysDevice
.Y
.axMin
= Axis
->min_value
;
685 gSysDevice
.Y
.axMax
= Axis
->max_value
;
686 gSysDevice
.Y
.axUnits
= TU_INCHES
;
687 gSysDevice
.Y
.axResolution
= Axis
->resolution
;
688 gSysContext
.lcInOrgY
= Axis
->min_value
;
689 gSysContext
.lcOutOrgY
= Axis
->min_value
;
690 gSysContext
.lcInExtY
= Axis
->max_value
;
691 gSysContext
.lcOutExtY
= Axis
->max_value
;
694 if (Val
->num_axes
>=3)
696 /* Axis 3 is Normal Pressure */
697 gSysDevice
.NPRESSURE
.axMin
= Axis
->min_value
;
698 gSysDevice
.NPRESSURE
.axMax
= Axis
->max_value
;
699 gSysDevice
.NPRESSURE
.axUnits
= TU_INCHES
;
700 gSysDevice
.NPRESSURE
.axResolution
=
704 if (Val
->num_axes
>= 5)
706 /* Axis 4 and 5 are X and Y tilt */
707 XAxisInfoPtr XAxis
= Axis
;
709 if (max (abs(Axis
->max_value
),
710 abs(XAxis
->max_value
)))
712 gSysDevice
.ORIENTATION
[0].axMin
= 0;
713 gSysDevice
.ORIENTATION
[0].axMax
= 3600;
714 gSysDevice
.ORIENTATION
[0].axUnits
= TU_CIRCLE
;
715 gSysDevice
.ORIENTATION
[0].axResolution
717 gSysDevice
.ORIENTATION
[1].axMin
= -1000;
718 gSysDevice
.ORIENTATION
[1].axMax
= 1000;
719 gSysDevice
.ORIENTATION
[1].axUnits
= TU_CIRCLE
;
720 gSysDevice
.ORIENTATION
[1].axResolution
722 gSysDevice
.ORIENTATION
[2].axMin
= 0;
723 gSysDevice
.ORIENTATION
[2].axMax
= 3600;
724 gSysDevice
.ORIENTATION
[2].axUnits
= TU_CIRCLE
;
725 gSysDevice
.ORIENTATION
[2].axResolution
730 axis_read_complete
= TRUE
;
739 Button
= (XButtonInfoPtr
) any
;
740 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
741 class_loop
, (int) Button
->class, Button
->length
, Button
->num_buttons
);
742 cursor
.BTNNAMES
= malloc( sizeof(WCHAR
) * cchBuf
);
743 for (i
= 0; i
< cursor
.BUTTONS
; i
++)
745 /* FIXME - these names are probably incorrect */
746 int cch
= wcslen(cursor
.NAME
) + 1;
747 while (cch
> cchBuf
- cchPos
- 1) /* we want one extra byte for the last NUL */
750 cursor
.BTNNAMES
= realloc( cursor
.BTNNAMES
, sizeof(WCHAR
) * cchBuf
);
753 wcscpy(cursor
.BTNNAMES
+ cchPos
, cursor
.NAME
);
756 cursor
.BTNNAMES
[cchPos
++] = 0;
757 cursor
.BTNNAMES
= realloc( cursor
.BTNNAMES
, sizeof(WCHAR
)*cchPos
);
758 cursor
.cchBTNNAMES
= cchPos
;
761 } /* switch any->class */
762 any
= (XAnyClassPtr
) ((char*) any
+ any
->length
);
763 } /* for class_loop */
764 if (!add_system_cursor(&cursor
))
765 FIXME("Skipping this cursor due to lack of system cursor slots.\n");
767 } /* switch devices.use */
769 } /* for XListInputDevices */
770 pXFreeDeviceList(devices
);
772 if (!axis_read_complete
)
774 disable_system_cursors();
775 WARN("Did not find a valid stylus, unable to determine system context parameters. Wintab is disabled.\n");
779 gSysDevice
.NCSRTYPES
= gNumCursors
;
783 static int figure_deg(int x
, int y
)
787 angle
= atan2((float)y
, (float)x
);
792 return (0.5 + (angle
* 1800.0 / M_PI
));
795 static int get_button_state(int curnum
)
797 return button_state
[curnum
];
800 static void set_button_state(int curnum
, XID deviceid
)
802 struct x11drv_thread_data
*data
= x11drv_thread_data();
809 device
= pXOpenDevice(data
->display
,deviceid
);
810 state
= pXQueryDeviceState(data
->display
,device
);
815 for (loop
= 0; loop
< state
->num_classes
; loop
++)
817 if (class->class == ButtonClass
)
820 XButtonState
*button_state
= (XButtonState
*)class;
821 for (loop2
= 0; loop2
< button_state
->num_buttons
; loop2
++)
823 if (button_state
->buttons
[loop2
/ 8] & (1 << (loop2
% 8)))
829 class = (XInputClass
*) ((char *) class + class->length
);
832 pXFreeDeviceState(state
);
833 button_state
[curnum
] = rc
;
836 static int cursor_from_device(DWORD deviceid
, LPWTI_CURSORS_INFO
*cursorp
)
839 for (i
= 0; i
< CURSORMAX
; i
++)
840 if (gSysCursor
[i
].ACTIVE
&& gSysCursor
[i
].PHYSID
== deviceid
)
842 *cursorp
= &gSysCursor
[i
];
846 ERR("Could not map device id %d to a cursor\n", (int) deviceid
);
850 static DWORD
get_changed_state( WTPACKET
*pkt
)
854 if (pkt
->pkX
!= last_packet
.pkX
)
856 if (pkt
->pkY
!= last_packet
.pkY
)
858 if (pkt
->pkZ
!= last_packet
.pkZ
)
860 if (pkt
->pkSerialNumber
!= last_packet
.pkSerialNumber
)
861 change
|= PK_SERIAL_NUMBER
;
862 if (pkt
->pkTime
!= last_packet
.pkTime
)
864 if (pkt
->pkNormalPressure
!= last_packet
.pkNormalPressure
)
865 change
|= PK_NORMAL_PRESSURE
;
866 if (pkt
->pkTangentPressure
!= last_packet
.pkTangentPressure
)
867 change
|= PK_TANGENT_PRESSURE
;
868 if (pkt
->pkCursor
!= last_packet
.pkCursor
)
870 if (pkt
->pkButtons
!= last_packet
.pkButtons
)
871 change
|= PK_BUTTONS
;
872 if (pkt
->pkOrientation
.orAzimuth
!= last_packet
.pkOrientation
.orAzimuth
||
873 pkt
->pkOrientation
.orAltitude
!= last_packet
.pkOrientation
.orAltitude
||
874 pkt
->pkOrientation
.orTwist
!= last_packet
.pkOrientation
.orTwist
)
875 change
|= PK_ORIENTATION
;
876 if (pkt
->pkRotation
.roPitch
!= last_packet
.pkRotation
.roPitch
||
877 pkt
->pkRotation
.roRoll
!= last_packet
.pkRotation
.roRoll
||
878 pkt
->pkRotation
.roYaw
!= last_packet
.pkRotation
.roYaw
)
879 change
|= PK_ROTATION
;
884 static BOOL
motion_event( HWND hwnd
, XEvent
*event
)
886 XDeviceMotionEvent
*motion
= (XDeviceMotionEvent
*)event
;
887 LPWTI_CURSORS_INFO cursor
;
888 int curnum
= cursor_from_device(motion
->deviceid
, &cursor
);
892 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
894 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd
, (int) motion
->deviceid
, curnum
);
896 /* Set cursor to inverted if cursor is the eraser */
897 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
898 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(motion
->time
);
899 gMsgPacket
.pkSerialNumber
= gSerial
++;
900 gMsgPacket
.pkCursor
= curnum
;
901 gMsgPacket
.pkX
= motion
->axis_data
[0];
902 gMsgPacket
.pkY
= motion
->axis_data
[1];
903 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(motion
->axis_data
[3],motion
->axis_data
[4]);
904 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max
905 (abs(motion
->axis_data
[3]),
906 abs(motion
->axis_data
[4])))
907 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
908 gMsgPacket
.pkNormalPressure
= motion
->axis_data
[2];
909 gMsgPacket
.pkButtons
= get_button_state(curnum
);
910 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
911 send_message( hwndTabletDefault
, WT_PACKET
, gMsgPacket
.pkSerialNumber
, (LPARAM
)hwnd
);
912 last_packet
= gMsgPacket
;
916 static BOOL
button_event( HWND hwnd
, XEvent
*event
)
918 XDeviceButtonEvent
*button
= (XDeviceButtonEvent
*) event
;
919 LPWTI_CURSORS_INFO cursor
;
920 int curnum
= cursor_from_device(button
->deviceid
, &cursor
);
924 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
926 TRACE("Received tablet button %s event\n", (event
->type
== button_press_type
)?"press":"release");
928 /* Set cursor to inverted if cursor is the eraser */
929 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
930 set_button_state(curnum
, button
->deviceid
);
931 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(button
->time
);
932 gMsgPacket
.pkSerialNumber
= gSerial
++;
933 gMsgPacket
.pkCursor
= curnum
;
934 if (button
->axes_count
> 0) {
935 gMsgPacket
.pkX
= button
->axis_data
[0];
936 gMsgPacket
.pkY
= button
->axis_data
[1];
937 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(button
->axis_data
[3],button
->axis_data
[4]);
938 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(button
->axis_data
[3]),
939 abs(button
->axis_data
[4])))
940 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
941 gMsgPacket
.pkNormalPressure
= button
->axis_data
[2];
943 gMsgPacket
.pkX
= last_packet
.pkX
;
944 gMsgPacket
.pkY
= last_packet
.pkY
;
945 gMsgPacket
.pkOrientation
= last_packet
.pkOrientation
;
946 gMsgPacket
.pkNormalPressure
= last_packet
.pkNormalPressure
;
948 gMsgPacket
.pkButtons
= get_button_state(curnum
);
949 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
950 send_message( hwndTabletDefault
, WT_PACKET
, gMsgPacket
.pkSerialNumber
, (LPARAM
)hwnd
);
951 last_packet
= gMsgPacket
;
955 static BOOL
key_event( HWND hwnd
, XEvent
*event
)
957 if (event
->type
== key_press_type
)
958 FIXME("Received tablet key press event\n");
960 FIXME("Received tablet key release event\n");
964 static BOOL
proximity_event( HWND hwnd
, XEvent
*event
)
966 XProximityNotifyEvent
*proximity
= (XProximityNotifyEvent
*) event
;
967 LPWTI_CURSORS_INFO cursor
;
968 int curnum
= cursor_from_device(proximity
->deviceid
, &cursor
);
969 LPARAM proximity_info
;
971 TRACE("hwnd=%p\n", hwnd
);
976 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
978 /* Set cursor to inverted if cursor is the eraser */
979 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
980 gMsgPacket
.pkStatus
|= (event
->type
==proximity_out_type
)?TPS_PROXIMITY
:0;
981 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(proximity
->time
);
982 gMsgPacket
.pkSerialNumber
= gSerial
++;
983 gMsgPacket
.pkCursor
= curnum
;
984 gMsgPacket
.pkX
= proximity
->axis_data
[0];
985 gMsgPacket
.pkY
= proximity
->axis_data
[1];
986 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(proximity
->axis_data
[3],proximity
->axis_data
[4]);
987 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(proximity
->axis_data
[3]),
988 abs(proximity
->axis_data
[4])))
989 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
990 gMsgPacket
.pkNormalPressure
= proximity
->axis_data
[2];
991 gMsgPacket
.pkButtons
= get_button_state(curnum
);
993 /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context
994 * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct
996 * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity"
997 * WPARAM contains context handle.
998 * HWND to HCTX is handled by wintab32.
1000 proximity_info
= MAKELPARAM((event
->type
== proximity_in_type
),
1001 (event
->type
== proximity_in_type
) || (event
->type
== proximity_out_type
));
1002 send_message( hwndTabletDefault
, WT_PROXIMITY
, (WPARAM
)hwnd
, proximity_info
);
1006 /***********************************************************************
1007 * x11drv_tablet_attach_queue
1009 NTSTATUS
x11drv_tablet_attach_queue( void *owner
)
1011 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
1015 XDeviceInfo
*devices
;
1016 XDeviceInfo
*target
= NULL
;
1017 XDevice
*the_device
;
1018 XEventClass event_list
[7];
1019 Window win
= X11DRV_get_whole_window( owner
);
1021 if (!win
|| !xinput_handle
) return 0;
1023 TRACE("Creating context for window %p (%lx) %i cursors\n", owner
, win
, gNumCursors
);
1025 devices
= pXListInputDevices(data
->display
, &num_devices
);
1027 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
1028 for (cur_loop
=0; cur_loop
< CURSORMAX
; cur_loop
++)
1030 char cursorNameA
[WT_MAX_NAME_LEN
];
1033 if (!gSysCursor
[cur_loop
].ACTIVE
) continue;
1035 /* the cursor name fits in the buffer because too long names are skipped */
1036 ntdll_wcstoumbs(gSysCursor
[cur_loop
].NAME
, wcslen(gSysCursor
[cur_loop
].NAME
) + 1,
1037 cursorNameA
, WT_MAX_NAME_LEN
, FALSE
);
1038 for (loop
=0; loop
< num_devices
; loop
++)
1039 if (strcmp(devices
[loop
].name
, cursorNameA
) == 0)
1040 target
= &devices
[loop
];
1042 WARN("Cursor Name %s not found in list of targets.\n", cursorNameA
);
1046 TRACE("Opening cursor %i id %i\n",cur_loop
,(INT
)target
->id
);
1048 the_device
= pXOpenDevice(data
->display
, target
->id
);
1052 WARN("Unable to Open device\n");
1056 if (the_device
->num_classes
> 0)
1058 DeviceKeyPress(the_device
, key_press_type
, event_list
[event_number
]);
1059 if (key_press_type
) event_number
++;
1060 DeviceKeyRelease(the_device
, key_release_type
, event_list
[event_number
]);
1061 if (key_release_type
) event_number
++;
1062 DeviceButtonPress(the_device
, button_press_type
, event_list
[event_number
]);
1063 if (button_press_type
) event_number
++;
1064 DeviceButtonRelease(the_device
, button_release_type
, event_list
[event_number
]);
1065 if (button_release_type
) event_number
++;
1066 DeviceMotionNotify(the_device
, motion_type
, event_list
[event_number
]);
1067 if (motion_type
) event_number
++;
1068 ProximityIn(the_device
, proximity_in_type
, event_list
[event_number
]);
1069 if (proximity_in_type
) event_number
++;
1070 ProximityOut(the_device
, proximity_out_type
, event_list
[event_number
]);
1071 if (proximity_out_type
) event_number
++;
1074 X11DRV_register_event_handler( key_press_type
, key_event
, "XInput KeyPress" );
1075 if (key_release_type
)
1076 X11DRV_register_event_handler( key_release_type
, key_event
, "XInput KeyRelease" );
1077 if (button_press_type
)
1078 X11DRV_register_event_handler( button_press_type
, button_event
, "XInput ButtonPress" );
1079 if (button_release_type
)
1080 X11DRV_register_event_handler( button_release_type
, button_event
, "XInput ButtonRelease" );
1082 X11DRV_register_event_handler( motion_type
, motion_event
, "XInput MotionNotify" );
1083 if (proximity_in_type
)
1084 X11DRV_register_event_handler( proximity_in_type
, proximity_event
, "XInput ProximityIn" );
1085 if (proximity_out_type
)
1086 X11DRV_register_event_handler( proximity_out_type
, proximity_event
, "XInput ProximityOut" );
1088 pXSelectExtensionEvent(data
->display
, win
, event_list
, event_number
);
1091 XSync(data
->display
, False
);
1092 X11DRV_check_error();
1094 if (NULL
!= devices
) pXFreeDeviceList(devices
);
1098 /***********************************************************************
1099 * x11drv_tablet_get_packet
1101 NTSTATUS
x11drv_tablet_get_packet( void *packet
)
1103 *(WTPACKET
*)packet
= gMsgPacket
;
1108 static inline int CopyTabletData(LPVOID target
, LPCVOID src
, INT size
)
1111 * It is valid to call CopyTabletData with NULL.
1112 * This handles the WTInfo() case where lpOutput is null.
1115 memcpy(target
,src
,size
);
1119 /***********************************************************************
1120 * x11drv_tablet_info
1122 NTSTATUS
x11drv_tablet_info( void *arg
)
1124 struct tablet_info_params
*params
= arg
;
1125 UINT wCategory
= params
->category
;
1126 UINT nIndex
= params
->index
;
1127 void *lpOutput
= params
->output
;
1130 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1131 * lpOutput == NULL signifies the user only wishes
1132 * to find the size of the data.
1134 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1138 LPWTI_CURSORS_INFO tgtcursor
;
1139 TRACE("(%u, %u, %p)\n", wCategory
, nIndex
, lpOutput
);
1141 if (!xinput_handle
) return 0;
1146 /* return largest necessary buffer */
1147 TRACE("%i cursors\n",gNumCursors
);
1150 FIXME("Return proper size\n");
1161 static const WCHAR driver
[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1162 rc
= CopyTabletData(lpOutput
, driver
, (wcslen(driver
) + 1) * sizeof(WCHAR
));
1165 case IFC_SPECVERSION
:
1166 version
= (0x01) | (0x01 << 8);
1167 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1169 case IFC_IMPLVERSION
:
1170 version
= (0x00) | (0x01 << 8);
1171 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1175 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1179 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1182 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex
);
1188 case WTI_DEFCONTEXT
:
1192 /* report 0 if wintab is disabled */
1193 if (0 == gNumCursors
)
1196 rc
= CopyTabletData(lpOutput
, &gSysContext
,
1197 sizeof(LOGCONTEXTW
));
1200 rc
= CopyTabletData(lpOutput
, gSysContext
.lcName
,
1201 (wcslen(gSysContext
.lcName
)+1) * sizeof(WCHAR
));
1204 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOptions
,
1208 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcStatus
,
1212 rc
= CopyTabletData (lpOutput
, &gSysContext
.lcLocks
,
1216 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMsgBase
,
1220 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcDevice
,
1224 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktRate
,
1228 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktData
,
1232 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktMode
,
1236 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMoveMask
,
1240 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnDnMask
,
1244 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnUpMask
,
1248 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgX
,
1252 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgY
,
1256 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgZ
,
1260 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtX
,
1264 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtY
,
1268 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtZ
,
1272 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgX
,
1276 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgY
,
1280 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgZ
,
1284 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtX
,
1288 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtY
,
1292 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtZ
,
1296 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensX
,
1300 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensY
,
1304 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensZ
,
1308 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysMode
,
1312 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgX
,
1316 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgY
,
1320 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtX
,
1324 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtY
,
1328 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensX
,
1332 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensY
,
1336 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex
);
1350 case WTI_CURSORS
+10:
1351 case WTI_CURSORS
+11:
1352 /* CURSORMAX == 12 */
1353 /* FIXME: dynamic cursor support */
1354 /* Apps will poll different slots to detect what cursors are available
1355 * if there isn't a cursor for this slot return 0 */
1356 if (!gSysCursor
[wCategory
- WTI_CURSORS
].ACTIVE
)
1360 tgtcursor
= &gSysCursor
[wCategory
- WTI_CURSORS
];
1364 rc
= CopyTabletData(lpOutput
, tgtcursor
->NAME
,
1365 (wcslen(tgtcursor
->NAME
)+1) * sizeof(WCHAR
));
1368 rc
= CopyTabletData(lpOutput
,&tgtcursor
->ACTIVE
,
1372 rc
= CopyTabletData(lpOutput
,&tgtcursor
->PKTDATA
,
1376 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONS
,
1379 case CSR_BUTTONBITS
:
1380 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONBITS
,
1384 FIXME("Button Names not returned correctly\n");
1385 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BTNNAMES
,
1386 tgtcursor
->cchBTNNAMES
*sizeof(WCHAR
));
1389 rc
= CopyTabletData(lpOutput
,tgtcursor
->BUTTONMAP
,
1393 rc
= CopyTabletData(lpOutput
,tgtcursor
->SYSBTNMAP
,
1396 case CSR_NPBTNMARKS
:
1397 rc
= CopyTabletData(lpOutput
,tgtcursor
->NPBTNMARKS
,
1401 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBUTTON
,
1404 case CSR_NPRESPONSE
:
1405 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1409 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBUTTON
,
1412 case CSR_TPBTNMARKS
:
1413 rc
= CopyTabletData(lpOutput
,tgtcursor
->TPBTNMARKS
,
1416 case CSR_TPRESPONSE
:
1417 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1423 id
= tgtcursor
->PHYSID
;
1424 rc
= CopyTabletData(lpOutput
,&id
,sizeof(DWORD
));
1428 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MODE
,sizeof(UINT
));
1430 case CSR_MINPKTDATA
:
1431 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINPKTDATA
,
1434 case CSR_MINBUTTONS
:
1435 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINBUTTONS
,
1438 case CSR_CAPABILITIES
:
1439 rc
= CopyTabletData(lpOutput
,&tgtcursor
->CAPABILITIES
,
1443 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TYPE
,
1447 FIXME("WTI_CURSORS unhandled index %i\n",nIndex
);
1456 rc
= CopyTabletData(lpOutput
,gSysDevice
.NAME
,
1457 (wcslen(gSysDevice
.NAME
)+1) * sizeof(WCHAR
));
1460 rc
= CopyTabletData(lpOutput
,&gSysDevice
.HARDWARE
,
1464 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NCSRTYPES
,
1468 rc
= CopyTabletData(lpOutput
,&gSysDevice
.FIRSTCSR
,
1472 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTRATE
,
1476 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTDATA
,
1480 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTMODE
,
1484 rc
= CopyTabletData(lpOutput
,&gSysDevice
.CSRDATA
,
1488 rc
= CopyTabletData(lpOutput
,&gSysDevice
.XMARGIN
,
1492 rc
= CopyTabletData(lpOutput
,&gSysDevice
.YMARGIN
,
1496 rc
= 0; /* unsupported */
1498 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1503 rc
= CopyTabletData(lpOutput
,&gSysDevice
.X
,
1507 rc
= CopyTabletData(lpOutput
,&gSysDevice
.Y
,
1511 rc
= 0; /* unsupported */
1513 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1518 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NPRESSURE
,
1522 rc
= 0; /* unsupported */
1524 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1528 case DVC_ORIENTATION
:
1529 rc
= CopyTabletData(lpOutput
,gSysDevice
.ORIENTATION
,
1533 rc
= 0; /* unsupported */
1535 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1540 rc
= CopyTabletData(lpOutput
,gSysDevice
.PNPID
,
1541 (wcslen(gSysDevice
.PNPID
)+1)*sizeof(WCHAR
));
1544 FIXME("WTI_DEVICES unhandled index %i\n",nIndex
);
1549 FIXME("Unhandled Category %i\n",wCategory
);
1554 #else /* SONAME_LIBXI */
1556 /***********************************************************************
1557 * x11drv_tablet_attach_queue
1559 NTSTATUS
x11drv_tablet_attach_queue( void *owner
)
1564 /***********************************************************************
1565 * x11drv_tablet_get_packet
1567 NTSTATUS
x11drv_tablet_get_packet( void *arg
)
1572 /***********************************************************************
1573 * x11drv_tablet_load_info
1575 NTSTATUS
x11drv_tablet_load_info( void *arg
)
1580 /***********************************************************************
1581 * x11drv_tablet_info
1583 NTSTATUS
x11drv_tablet_info( void *arg
)
1588 #endif /* SONAME_LIBXI */