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/unicode.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wintab32
);
37 #define WT_MAX_NAME_LEN 256
39 typedef struct tagWTI_CURSORS_INFO
41 WCHAR NAME
[WT_MAX_NAME_LEN
];
42 /* a displayable zero-terminated string containing the name of the
46 /* whether the cursor is currently connected. */
48 /* a bit mask indicating the packet data items supported when this
49 * cursor is connected.
52 /* the number of buttons on this cursor. */
54 /* the number of bits of raw button data returned by the hardware.*/
57 /* a list of zero-terminated strings containing the names of the
58 * cursor's buttons. The number of names in the list is the same as the
59 * number of buttons on the cursor. The names are separated by a single
60 * zero character; the list is terminated by two zero characters.
63 /* a 32 byte array of logical button numbers, one for each physical
67 /* a 32 byte array of button action codes, one for each logical
71 /* the physical button number of the button that is controlled by normal
75 /* an array of two UINTs, specifying the button marks for the normal
76 * pressure button. The first UINT contains the release mark; the second
77 * contains the press mark.
80 /* an array of UINTs describing the pressure response curve for normal
84 /* the physical button number of the button that is controlled by
85 * tangential pressure.
88 /* an array of two UINTs, specifying the button marks for the tangential
89 * pressure button. The first UINT contains the release mark; the second
90 * contains the press mark.
93 /* an array of UINTs describing the pressure response curve for
94 * tangential pressure.
97 /* a manufacturer-specific physical identifier for the cursor. This
98 * value will distinguish the physical cursor from others on the same
99 * device. This physical identifier allows applications to bind
100 * functions to specific physical cursors, even if category numbers
101 * change and multiple, otherwise identical, physical cursors are
105 /* the cursor mode number of this cursor type, if this cursor type has
106 * the CRC_MULTIMODE capability.
109 /* the minimum set of data available from a physical cursor in this
110 * cursor type, if this cursor type has the CRC_AGGREGATE capability.
113 /* the minimum number of buttons of physical cursors in the cursor type,
114 * if this cursor type has the CRC_AGGREGATE capability.
117 /* flags indicating cursor capabilities, as defined below:
119 Indicates this cursor type describes one of several modes of a
120 single physical cursor. Consecutive cursor type categories
121 describe the modes; the CSR_MODE data item gives the mode number
124 Indicates this cursor type describes several physical cursors
125 that cannot be distinguished by software.
127 Indicates this cursor type describes the physical cursor in its
128 inverted orientation; the previous consecutive cursor type
129 category describes the normal orientation.
132 /* Manufacturer Unique id for the item type */
133 } WTI_CURSORS_INFO
, *LPWTI_CURSORS_INFO
;
136 typedef struct tagWTI_DEVICES_INFO
138 WCHAR NAME
[WT_MAX_NAME_LEN
];
139 /* a displayable null- terminated string describing the device,
140 * manufacturer, and revision level.
143 /* flags indicating hardware and driver capabilities, as defined
146 Indicates that the display and digitizer share the same surface.
148 Indicates that the cursor must be in physical contact with the
149 device to report position.
151 Indicates that device can generate events when the cursor is
152 entering and leaving the physical detection range.
154 Indicates that device can uniquely identify the active cursor in
158 /* the number of supported cursor types.*/
160 /* the first cursor type number for the device. */
162 /* the maximum packet report rate in Hertz. */
164 /* a bit mask indicating which packet data items are always available.*/
166 /* a bit mask indicating which packet data items are physically
167 * relative, i.e., items for which the hardware can only report change,
168 * not absolute measurement.
171 /* a bit mask indicating which packet data items are only available when
172 * certain cursors are connected. The individual cursor descriptions
173 * must be consulted to determine which cursors return which data.
178 /* the size of tablet context margins in tablet native coordinates, in
179 * the x, y, and z directions, respectively.
184 /* the tablet's range and resolution capabilities, in the x, y, and z
185 * axes, respectively.
189 /* the tablet's range and resolution capabilities, for the normal and
190 * tangential pressure inputs, respectively.
193 /* a 3-element array describing the tablet's orientation range and
194 * resolution capabilities.
197 /* a 3-element array describing the tablet's rotation range and
198 * resolution capabilities.
200 WCHAR PNPID
[WT_MAX_NAME_LEN
];
201 /* a null-terminated string containing the devices Plug and Play ID.*/
202 } WTI_DEVICES_INFO
, *LPWTI_DEVICES_INFO
;
205 /***********************************************************************
206 * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE
207 * In Wintab 1.2, a CSR_TYPE feature was added. This adds the
208 * ability to return a type of cursor on a tablet.
209 * Unfortunately, we cannot get the cursor type directly from X,
210 * and it is not specified directly anywhere. So we virtualize
211 * the type here. (This is unfortunate, the kernel module has
212 * the exact type, but we have no way of getting that module to
213 * pass us that type).
215 * Reference linuxwacom driver project wcmCommon.c function
216 * idtotype for a much larger list of CSR_TYPE.
218 * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wcmCommon.c?view=markup
220 * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this:
221 * (cursor.TYPE & 0x0F06) == target_cursor_type
222 * Reference: Section Unique ID
223 * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html
225 #define CSR_TYPE_PEN 0x822
226 #define CSR_TYPE_ERASER 0x82a
227 #define CSR_TYPE_MOUSE_2D 0x007
228 #define CSR_TYPE_MOUSE_4D 0x094
229 /* CSR_TYPE_OTHER is a special value! assumed no real world significance
230 * if a stylus type or eraser type eventually have this value
231 * it'll be a bug. As of 2008 05 21 we can be sure because
232 * linux wacom lists all the known values and this isn't one of them */
233 #define CSR_TYPE_OTHER 0x000
235 typedef struct tagWTPACKET
{
246 UINT pkNormalPressure
;
247 UINT pkTangentPressure
;
248 ORIENTATION pkOrientation
;
249 ROTATION pkRotation
; /* 1.1 */
250 } WTPACKET
, *LPWTPACKET
;
255 #include <X11/Xlib.h>
256 #include <X11/extensions/XInput.h>
258 static int motion_type
;
259 static int button_press_type
;
260 static int button_release_type
;
261 static int key_press_type
;
262 static int key_release_type
;
263 static int proximity_in_type
;
264 static int proximity_out_type
;
266 static HWND hwndTabletDefault
;
267 static WTPACKET gMsgPacket
;
268 static DWORD gSerial
;
269 static WTPACKET last_packet
;
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
= dlopen(SONAME_LIBXI
, RTLD_NOW
);
332 #define LOAD_FUNCPTR(f) if((p##f = dlsym(xinput_handle, #f)) == 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_allowlist
[] = {
409 for (i
=0; tablet_cursor_allowlist
[i
] != NULL
; i
++) {
410 if (name
&& match_token(name
, tablet_cursor_allowlist
[i
]))
412 if (type
&& match_token(type
, tablet_cursor_allowlist
[i
]))
418 static UINT
get_cursor_type(const char *name
, const char *type
)
421 static const char* tablet_stylus_allowlist
[] = {
429 /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
430 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
431 if (type
&& match_token(type
, tablet_stylus_allowlist
[i
]))
434 if (type
&& match_token(type
, "eraser"))
435 return CSR_TYPE_ERASER
;
436 for (i
=0; tablet_stylus_allowlist
[i
] != NULL
; i
++) {
437 if (name
&& match_token(name
, tablet_stylus_allowlist
[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 static const WCHAR SZ_CONTEXT_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
489 static const WCHAR SZ_DEVICE_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
490 static const WCHAR SZ_NON_PLUG_N_PLAY
[] = {'n','o','n','-','p','l','u','g','-','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
.lcSysExtX
= GetSystemMetrics(SM_CXVIRTUALSCREEN
);
540 gSysContext
.lcSysExtY
= GetSystemMetrics(SM_CYVIRTUALSCREEN
);
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_PLUG_N_PLAY
);
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
, debugstr_a(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\n",
623 loop
, devices
[loop
].name
, debugstr_a(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
.lcOutOrgX
= Axis
->min_value
;
674 gSysContext
.lcInExtX
= Axis
->max_value
;
675 gSysContext
.lcOutExtX
= 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
.lcOutOrgY
= Axis
->min_value
;
687 gSysContext
.lcInExtY
= Axis
->max_value
;
688 gSysContext
.lcOutExtY
= 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
719 gSysDevice
.ORIENTATION
[2].axMin
= 0;
720 gSysDevice
.ORIENTATION
[2].axMax
= 3600;
721 gSysDevice
.ORIENTATION
[2].axUnits
= TU_CIRCLE
;
722 gSysDevice
.ORIENTATION
[2].axResolution
727 axis_read_complete
= TRUE
;
736 Button
= (XButtonInfoPtr
) any
;
737 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
738 class_loop
, (int) Button
->class, Button
->length
, Button
->num_buttons
);
739 cursor
.BTNNAMES
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*cchBuf
);
740 for (i
= 0; i
< cursor
.BUTTONS
; i
++)
742 /* FIXME - these names are probably incorrect */
743 int cch
= strlenW(cursor
.NAME
) + 1;
744 while (cch
> cchBuf
- cchPos
- 1) /* we want one extra byte for the last NUL */
747 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchBuf
);
750 strcpyW(cursor
.BTNNAMES
+ cchPos
, cursor
.NAME
);
753 cursor
.BTNNAMES
[cchPos
++] = 0;
754 cursor
.BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
.BTNNAMES
, sizeof(WCHAR
)*cchPos
);
755 cursor
.cchBTNNAMES
= cchPos
;
758 } /* switch any->class */
759 any
= (XAnyClassPtr
) ((char*) any
+ any
->length
);
760 } /* for class_loop */
761 if (!add_system_cursor(&cursor
))
762 FIXME("Skipping this cursor due to lack of system cursor slots.\n");
764 } /* switch devices.use */
766 } /* for XListInputDevices */
767 pXFreeDeviceList(devices
);
769 if (!axis_read_complete
)
771 disable_system_cursors();
772 WARN("Did not find a valid stylus, unable to determine system context parameters. Wintab is disabled.\n");
776 gSysDevice
.NCSRTYPES
= gNumCursors
;
780 static int figure_deg(int x
, int y
)
784 angle
= atan2((float)y
, (float)x
);
789 return (0.5 + (angle
* 1800.0 / M_PI
));
792 static int get_button_state(int curnum
)
794 return button_state
[curnum
];
797 static void set_button_state(int curnum
, XID deviceid
)
799 struct x11drv_thread_data
*data
= x11drv_thread_data();
806 device
= pXOpenDevice(data
->display
,deviceid
);
807 state
= pXQueryDeviceState(data
->display
,device
);
812 for (loop
= 0; loop
< state
->num_classes
; loop
++)
814 if (class->class == ButtonClass
)
817 XButtonState
*button_state
= (XButtonState
*)class;
818 for (loop2
= 0; loop2
< button_state
->num_buttons
; loop2
++)
820 if (button_state
->buttons
[loop2
/ 8] & (1 << (loop2
% 8)))
826 class = (XInputClass
*) ((char *) class + class->length
);
829 pXFreeDeviceState(state
);
830 button_state
[curnum
] = rc
;
833 static int cursor_from_device(DWORD deviceid
, LPWTI_CURSORS_INFO
*cursorp
)
836 for (i
= 0; i
< CURSORMAX
; i
++)
837 if (gSysCursor
[i
].ACTIVE
&& gSysCursor
[i
].PHYSID
== deviceid
)
839 *cursorp
= &gSysCursor
[i
];
843 ERR("Could not map device id %d to a cursor\n", (int) deviceid
);
847 static DWORD
get_changed_state( WTPACKET
*pkt
)
851 if (pkt
->pkX
!= last_packet
.pkX
)
853 if (pkt
->pkY
!= last_packet
.pkY
)
855 if (pkt
->pkZ
!= last_packet
.pkZ
)
857 if (pkt
->pkSerialNumber
!= last_packet
.pkSerialNumber
)
858 change
|= PK_SERIAL_NUMBER
;
859 if (pkt
->pkTime
!= last_packet
.pkTime
)
861 if (pkt
->pkNormalPressure
!= last_packet
.pkNormalPressure
)
862 change
|= PK_NORMAL_PRESSURE
;
863 if (pkt
->pkTangentPressure
!= last_packet
.pkTangentPressure
)
864 change
|= PK_TANGENT_PRESSURE
;
865 if (pkt
->pkCursor
!= last_packet
.pkCursor
)
867 if (pkt
->pkButtons
!= last_packet
.pkButtons
)
868 change
|= PK_BUTTONS
;
869 if (pkt
->pkOrientation
.orAzimuth
!= last_packet
.pkOrientation
.orAzimuth
||
870 pkt
->pkOrientation
.orAltitude
!= last_packet
.pkOrientation
.orAltitude
||
871 pkt
->pkOrientation
.orTwist
!= last_packet
.pkOrientation
.orTwist
)
872 change
|= PK_ORIENTATION
;
873 if (pkt
->pkRotation
.roPitch
!= last_packet
.pkRotation
.roPitch
||
874 pkt
->pkRotation
.roRoll
!= last_packet
.pkRotation
.roRoll
||
875 pkt
->pkRotation
.roYaw
!= last_packet
.pkRotation
.roYaw
)
876 change
|= PK_ROTATION
;
881 static BOOL
motion_event( HWND hwnd
, XEvent
*event
)
883 XDeviceMotionEvent
*motion
= (XDeviceMotionEvent
*)event
;
884 LPWTI_CURSORS_INFO cursor
;
885 int curnum
= cursor_from_device(motion
->deviceid
, &cursor
);
889 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
891 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd
, (int) motion
->deviceid
, curnum
);
893 /* Set cursor to inverted if cursor is the eraser */
894 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
895 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(motion
->time
);
896 gMsgPacket
.pkSerialNumber
= gSerial
++;
897 gMsgPacket
.pkCursor
= curnum
;
898 gMsgPacket
.pkX
= motion
->axis_data
[0];
899 gMsgPacket
.pkY
= motion
->axis_data
[1];
900 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(motion
->axis_data
[3],motion
->axis_data
[4]);
901 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max
902 (abs(motion
->axis_data
[3]),
903 abs(motion
->axis_data
[4])))
904 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
905 gMsgPacket
.pkNormalPressure
= motion
->axis_data
[2];
906 gMsgPacket
.pkButtons
= get_button_state(curnum
);
907 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
908 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
909 last_packet
= gMsgPacket
;
913 static BOOL
button_event( HWND hwnd
, XEvent
*event
)
915 XDeviceButtonEvent
*button
= (XDeviceButtonEvent
*) event
;
916 LPWTI_CURSORS_INFO cursor
;
917 int curnum
= cursor_from_device(button
->deviceid
, &cursor
);
921 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
923 TRACE("Received tablet button %s event\n", (event
->type
== button_press_type
)?"press":"release");
925 /* Set cursor to inverted if cursor is the eraser */
926 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
927 set_button_state(curnum
, button
->deviceid
);
928 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(button
->time
);
929 gMsgPacket
.pkSerialNumber
= gSerial
++;
930 gMsgPacket
.pkCursor
= curnum
;
931 if (button
->axes_count
> 0) {
932 gMsgPacket
.pkX
= button
->axis_data
[0];
933 gMsgPacket
.pkY
= button
->axis_data
[1];
934 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(button
->axis_data
[3],button
->axis_data
[4]);
935 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(button
->axis_data
[3]),
936 abs(button
->axis_data
[4])))
937 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
938 gMsgPacket
.pkNormalPressure
= button
->axis_data
[2];
940 gMsgPacket
.pkX
= last_packet
.pkX
;
941 gMsgPacket
.pkY
= last_packet
.pkY
;
942 gMsgPacket
.pkOrientation
= last_packet
.pkOrientation
;
943 gMsgPacket
.pkNormalPressure
= last_packet
.pkNormalPressure
;
945 gMsgPacket
.pkButtons
= get_button_state(curnum
);
946 gMsgPacket
.pkChanged
= get_changed_state(&gMsgPacket
);
947 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
948 last_packet
= gMsgPacket
;
952 static BOOL
key_event( HWND hwnd
, XEvent
*event
)
954 if (event
->type
== key_press_type
)
955 FIXME("Received tablet key press event\n");
957 FIXME("Received tablet key release event\n");
961 static BOOL
proximity_event( HWND hwnd
, XEvent
*event
)
963 XProximityNotifyEvent
*proximity
= (XProximityNotifyEvent
*) event
;
964 LPWTI_CURSORS_INFO cursor
;
965 int curnum
= cursor_from_device(proximity
->deviceid
, &cursor
);
966 LPARAM proximity_info
;
968 TRACE("hwnd=%p\n", hwnd
);
973 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
975 /* Set cursor to inverted if cursor is the eraser */
976 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
977 gMsgPacket
.pkStatus
|= (event
->type
==proximity_out_type
)?TPS_PROXIMITY
:0;
978 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(proximity
->time
);
979 gMsgPacket
.pkSerialNumber
= gSerial
++;
980 gMsgPacket
.pkCursor
= curnum
;
981 gMsgPacket
.pkX
= proximity
->axis_data
[0];
982 gMsgPacket
.pkY
= proximity
->axis_data
[1];
983 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(proximity
->axis_data
[3],proximity
->axis_data
[4]);
984 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(proximity
->axis_data
[3]),
985 abs(proximity
->axis_data
[4])))
986 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
987 gMsgPacket
.pkNormalPressure
= proximity
->axis_data
[2];
988 gMsgPacket
.pkButtons
= get_button_state(curnum
);
990 /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context
991 * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct
993 * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity"
994 * WPARAM contains context handle.
995 * HWND to HCTX is handled by wintab32.
997 proximity_info
= MAKELPARAM((event
->type
== proximity_in_type
),
998 (event
->type
== proximity_in_type
) || (event
->type
== proximity_out_type
));
999 SendMessageW(hwndTabletDefault
, WT_PROXIMITY
, (WPARAM
)hwnd
, proximity_info
);
1003 /***********************************************************************
1004 * X11DRV_AttachEventQueueToTablet (X11DRV.@)
1006 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1008 struct x11drv_thread_data
*data
= x11drv_init_thread_data();
1012 XDeviceInfo
*devices
;
1013 XDeviceInfo
*target
= NULL
;
1014 XDevice
*the_device
;
1015 XEventClass event_list
[7];
1016 Window win
= X11DRV_get_whole_window( hOwner
);
1018 if (!win
|| !xinput_handle
) return 0;
1020 TRACE("Creating context for window %p (%lx) %i cursors\n", hOwner
, win
, gNumCursors
);
1022 devices
= pXListInputDevices(data
->display
, &num_devices
);
1024 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
1025 for (cur_loop
=0; cur_loop
< CURSORMAX
; cur_loop
++)
1027 char cursorNameA
[WT_MAX_NAME_LEN
];
1030 if (!gSysCursor
[cur_loop
].ACTIVE
) continue;
1032 /* the cursor name fits in the buffer because too long names are skipped */
1033 WideCharToMultiByte(CP_UNIXCP
, 0, gSysCursor
[cur_loop
].NAME
, -1, cursorNameA
, WT_MAX_NAME_LEN
, NULL
, NULL
);
1034 for (loop
=0; loop
< num_devices
; loop
++)
1035 if (strcmp(devices
[loop
].name
, cursorNameA
) == 0)
1036 target
= &devices
[loop
];
1038 WARN("Cursor Name %s not found in list of targets.\n", cursorNameA
);
1042 TRACE("Opening cursor %i id %i\n",cur_loop
,(INT
)target
->id
);
1044 the_device
= pXOpenDevice(data
->display
, target
->id
);
1048 WARN("Unable to Open device\n");
1052 if (the_device
->num_classes
> 0)
1054 DeviceKeyPress(the_device
, key_press_type
, event_list
[event_number
]);
1055 if (key_press_type
) event_number
++;
1056 DeviceKeyRelease(the_device
, key_release_type
, event_list
[event_number
]);
1057 if (key_release_type
) event_number
++;
1058 DeviceButtonPress(the_device
, button_press_type
, event_list
[event_number
]);
1059 if (button_press_type
) event_number
++;
1060 DeviceButtonRelease(the_device
, button_release_type
, event_list
[event_number
]);
1061 if (button_release_type
) event_number
++;
1062 DeviceMotionNotify(the_device
, motion_type
, event_list
[event_number
]);
1063 if (motion_type
) event_number
++;
1064 ProximityIn(the_device
, proximity_in_type
, event_list
[event_number
]);
1065 if (proximity_in_type
) event_number
++;
1066 ProximityOut(the_device
, proximity_out_type
, event_list
[event_number
]);
1067 if (proximity_out_type
) event_number
++;
1070 X11DRV_register_event_handler( key_press_type
, key_event
, "XInput KeyPress" );
1071 if (key_release_type
)
1072 X11DRV_register_event_handler( key_release_type
, key_event
, "XInput KeyRelease" );
1073 if (button_press_type
)
1074 X11DRV_register_event_handler( button_press_type
, button_event
, "XInput ButtonPress" );
1075 if (button_release_type
)
1076 X11DRV_register_event_handler( button_release_type
, button_event
, "XInput ButtonRelease" );
1078 X11DRV_register_event_handler( motion_type
, motion_event
, "XInput MotionNotify" );
1079 if (proximity_in_type
)
1080 X11DRV_register_event_handler( proximity_in_type
, proximity_event
, "XInput ProximityIn" );
1081 if (proximity_out_type
)
1082 X11DRV_register_event_handler( proximity_out_type
, proximity_event
, "XInput ProximityOut" );
1084 pXSelectExtensionEvent(data
->display
, win
, event_list
, event_number
);
1087 XSync(data
->display
, False
);
1088 X11DRV_check_error();
1090 if (NULL
!= devices
) pXFreeDeviceList(devices
);
1094 /***********************************************************************
1095 * X11DRV_GetCurrentPacket (X11DRV.@)
1097 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1099 *packet
= gMsgPacket
;
1104 static inline int CopyTabletData(LPVOID target
, LPCVOID src
, INT size
)
1107 * It is valid to call CopyTabletData with NULL.
1108 * This handles the WTInfo() case where lpOutput is null.
1111 memcpy(target
,src
,size
);
1115 /***********************************************************************
1116 * X11DRV_WTInfoW (X11DRV.@)
1118 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1121 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1122 * lpOutput == NULL signifies the user only wishes
1123 * to find the size of the data.
1125 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1129 LPWTI_CURSORS_INFO tgtcursor
;
1130 TRACE("(%u, %u, %p)\n", wCategory
, nIndex
, lpOutput
);
1132 if (!xinput_handle
) return 0;
1137 /* return largest necessary buffer */
1138 TRACE("%i cursors\n",gNumCursors
);
1141 FIXME("Return proper size\n");
1152 static const WCHAR driver
[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1153 rc
= CopyTabletData(lpOutput
, driver
, (strlenW(driver
) + 1) * sizeof(WCHAR
));
1156 case IFC_SPECVERSION
:
1157 version
= (0x01) | (0x01 << 8);
1158 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1160 case IFC_IMPLVERSION
:
1161 version
= (0x00) | (0x01 << 8);
1162 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1166 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1170 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1173 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex
);
1179 case WTI_DEFCONTEXT
:
1183 /* report 0 if wintab is disabled */
1184 if (0 == gNumCursors
)
1187 rc
= CopyTabletData(lpOutput
, &gSysContext
,
1188 sizeof(LOGCONTEXTW
));
1191 rc
= CopyTabletData(lpOutput
, gSysContext
.lcName
,
1192 (strlenW(gSysContext
.lcName
)+1) * sizeof(WCHAR
));
1195 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOptions
,
1199 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcStatus
,
1203 rc
= CopyTabletData (lpOutput
, &gSysContext
.lcLocks
,
1207 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMsgBase
,
1211 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcDevice
,
1215 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktRate
,
1219 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktData
,
1223 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktMode
,
1227 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMoveMask
,
1231 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnDnMask
,
1235 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnUpMask
,
1239 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgX
,
1243 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgY
,
1247 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgZ
,
1251 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtX
,
1255 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtY
,
1259 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtZ
,
1263 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgX
,
1267 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgY
,
1271 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgZ
,
1275 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtX
,
1279 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtY
,
1283 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtZ
,
1287 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensX
,
1291 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensY
,
1295 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensZ
,
1299 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysMode
,
1303 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgX
,
1307 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgY
,
1311 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtX
,
1315 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtY
,
1319 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensX
,
1323 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensY
,
1327 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex
);
1341 case WTI_CURSORS
+10:
1342 case WTI_CURSORS
+11:
1343 /* CURSORMAX == 12 */
1344 /* FIXME: dynamic cursor support */
1345 /* Apps will poll different slots to detect what cursors are available
1346 * if there isn't a cursor for this slot return 0 */
1347 if (!gSysCursor
[wCategory
- WTI_CURSORS
].ACTIVE
)
1351 tgtcursor
= &gSysCursor
[wCategory
- WTI_CURSORS
];
1355 rc
= CopyTabletData(lpOutput
, tgtcursor
->NAME
,
1356 (strlenW(tgtcursor
->NAME
)+1) * sizeof(WCHAR
));
1359 rc
= CopyTabletData(lpOutput
,&tgtcursor
->ACTIVE
,
1363 rc
= CopyTabletData(lpOutput
,&tgtcursor
->PKTDATA
,
1367 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONS
,
1370 case CSR_BUTTONBITS
:
1371 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONBITS
,
1375 FIXME("Button Names not returned correctly\n");
1376 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BTNNAMES
,
1377 tgtcursor
->cchBTNNAMES
*sizeof(WCHAR
));
1380 rc
= CopyTabletData(lpOutput
,tgtcursor
->BUTTONMAP
,
1384 rc
= CopyTabletData(lpOutput
,tgtcursor
->SYSBTNMAP
,
1387 case CSR_NPBTNMARKS
:
1388 rc
= CopyTabletData(lpOutput
,tgtcursor
->NPBTNMARKS
,
1392 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBUTTON
,
1395 case CSR_NPRESPONSE
:
1396 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1400 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBUTTON
,
1403 case CSR_TPBTNMARKS
:
1404 rc
= CopyTabletData(lpOutput
,tgtcursor
->TPBTNMARKS
,
1407 case CSR_TPRESPONSE
:
1408 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1414 id
= tgtcursor
->PHYSID
;
1415 rc
= CopyTabletData(lpOutput
,&id
,sizeof(DWORD
));
1419 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MODE
,sizeof(UINT
));
1421 case CSR_MINPKTDATA
:
1422 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINPKTDATA
,
1425 case CSR_MINBUTTONS
:
1426 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINBUTTONS
,
1429 case CSR_CAPABILITIES
:
1430 rc
= CopyTabletData(lpOutput
,&tgtcursor
->CAPABILITIES
,
1434 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TYPE
,
1438 FIXME("WTI_CURSORS unhandled index %i\n",nIndex
);
1447 rc
= CopyTabletData(lpOutput
,gSysDevice
.NAME
,
1448 (strlenW(gSysDevice
.NAME
)+1) * sizeof(WCHAR
));
1451 rc
= CopyTabletData(lpOutput
,&gSysDevice
.HARDWARE
,
1455 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NCSRTYPES
,
1459 rc
= CopyTabletData(lpOutput
,&gSysDevice
.FIRSTCSR
,
1463 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTRATE
,
1467 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTDATA
,
1471 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTMODE
,
1475 rc
= CopyTabletData(lpOutput
,&gSysDevice
.CSRDATA
,
1479 rc
= CopyTabletData(lpOutput
,&gSysDevice
.XMARGIN
,
1483 rc
= CopyTabletData(lpOutput
,&gSysDevice
.YMARGIN
,
1487 rc
= 0; /* unsupported */
1489 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1494 rc
= CopyTabletData(lpOutput
,&gSysDevice
.X
,
1498 rc
= CopyTabletData(lpOutput
,&gSysDevice
.Y
,
1502 rc
= 0; /* unsupported */
1504 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1509 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NPRESSURE
,
1513 rc
= 0; /* unsupported */
1515 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1519 case DVC_ORIENTATION
:
1520 rc
= CopyTabletData(lpOutput
,gSysDevice
.ORIENTATION
,
1524 rc
= 0; /* unsupported */
1526 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1531 rc
= CopyTabletData(lpOutput
,gSysDevice
.PNPID
,
1532 (strlenW(gSysDevice
.PNPID
)+1)*sizeof(WCHAR
));
1535 FIXME("WTI_DEVICES unhandled index %i\n",nIndex
);
1540 FIXME("Unhandled Category %i\n",wCategory
);
1545 #else /* SONAME_LIBXI */
1547 /***********************************************************************
1548 * AttachEventQueueToTablet (X11DRV.@)
1550 int CDECL
X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1555 /***********************************************************************
1556 * GetCurrentPacket (X11DRV.@)
1558 int CDECL
X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1563 /***********************************************************************
1564 * LoadTabletInfo (X11DRV.@)
1566 BOOL CDECL
X11DRV_LoadTabletInfo(HWND hwnddefault
)
1571 /***********************************************************************
1572 * WTInfoW (X11DRV.@)
1574 UINT CDECL
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1579 #endif /* SONAME_LIBXI */