4 * Copyright 2003 CodeWeavers (Aric Stewart)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/port.h"
31 #include "wine/library.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wintab32
);
38 #define WT_MAX_NAME_LEN 256
40 typedef struct tagWTI_CURSORS_INFO
42 WCHAR NAME
[WT_MAX_NAME_LEN
];
43 /* a displayable zero-terminated string containing the name of the
47 /* whether the cursor is currently connected. */
49 /* a bit mask indicating the packet data items supported when this
50 * cursor is connected.
53 /* the number of buttons on this cursor. */
55 /* the number of bits of raw button data returned by the hardware.*/
58 /* a list of zero-terminated strings containing the names of the
59 * cursor's buttons. The number of names in the list is the same as the
60 * number of buttons on the cursor. The names are separated by a single
61 * zero character; the list is terminated by two zero characters.
64 /* a 32 byte array of logical button numbers, one for each physical
68 /* a 32 byte array of button action codes, one for each logical
72 /* the physical button number of the button that is controlled by normal
76 /* an array of two UINTs, specifying the button marks for the normal
77 * pressure button. The first UINT contains the release mark; the second
78 * contains the press mark.
81 /* an array of UINTs describing the pressure response curve for normal
85 /* the physical button number of the button that is controlled by
86 * tangential pressure.
89 /* an array of two UINTs, specifying the button marks for the tangential
90 * pressure button. The first UINT contains the release mark; the second
91 * contains the press mark.
94 /* an array of UINTs describing the pressure response curve for
95 * tangential pressure.
98 /* a manufacturer-specific physical identifier for the cursor. This
99 * value will distinguish the physical cursor from others on the same
100 * device. This physical identifier allows applications to bind
101 * functions to specific physical cursors, even if category numbers
102 * change and multiple, otherwise identical, physical cursors are
106 /* the cursor mode number of this cursor type, if this cursor type has
107 * the CRC_MULTIMODE capability.
110 /* the minimum set of data available from a physical cursor in this
111 * cursor type, if this cursor type has the CRC_AGGREGATE capability.
114 /* the minimum number of buttons of physical cursors in the cursor type,
115 * if this cursor type has the CRC_AGGREGATE capability.
118 /* flags indicating cursor capabilities, as defined below:
120 Indicates this cursor type describes one of several modes of a
121 single physical cursor. Consecutive cursor type categories
122 describe the modes; the CSR_MODE data item gives the mode number
125 Indicates this cursor type describes several physical cursors
126 that cannot be distinguished by software.
128 Indicates this cursor type describes the physical cursor in its
129 inverted orientation; the previous consecutive cursor type
130 category describes the normal orientation.
133 /* Manufacturer Unique id for the item type */
134 } WTI_CURSORS_INFO
, *LPWTI_CURSORS_INFO
;
137 typedef struct tagWTI_DEVICES_INFO
139 WCHAR NAME
[WT_MAX_NAME_LEN
];
140 /* a displayable null- terminated string describing the device,
141 * manufacturer, and revision level.
144 /* flags indicating hardware and driver capabilities, as defined
147 Indicates that the display and digitizer share the same surface.
149 Indicates that the cursor must be in physical contact with the
150 device to report position.
152 Indicates that device can generate events when the cursor is
153 entering and leaving the physical detection range.
155 Indicates that device can uniquely identify the active cursor in
159 /* the number of supported cursor types.*/
161 /* the first cursor type number for the device. */
163 /* the maximum packet report rate in Hertz. */
165 /* a bit mask indicating which packet data items are always available.*/
167 /* a bit mask indicating which packet data items are physically
168 * relative, i.e., items for which the hardware can only report change,
169 * not absolute measurement.
172 /* a bit mask indicating which packet data items are only available when
173 * certain cursors are connected. The individual cursor descriptions
174 * must be consulted to determine which cursors return which data.
179 /* the size of tablet context margins in tablet native coordinates, in
180 * the x, y, and z directions, respectively.
185 /* the tablet's range and resolution capabilities, in the x, y, and z
186 * axes, respectively.
190 /* the tablet's range and resolution capabilities, for the normal and
191 * tangential pressure inputs, respectively.
194 /* a 3-element array describing the tablet's orientation range and
195 * resolution capabilities.
198 /* a 3-element array describing the tablet's rotation range and
199 * resolution capabilities.
201 WCHAR PNPID
[WT_MAX_NAME_LEN
];
202 /* a null-terminated string containing the devices Plug and Play ID.*/
203 } WTI_DEVICES_INFO
, *LPWTI_DEVICES_INFO
;
206 /***********************************************************************
207 * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE
208 * In Wintab 1.2, a CSR_TYPE feature was added. This adds the
209 * ability to return a type of cursor on a tablet.
210 * Unfortunately, we cannot get the cursor type directly from X,
211 * and it is not specified directly anywhere. So we virtualize
212 * the type here. (This is unfortunate, the kernel module has
213 * the exact type, but we have no way of getting that module to
214 * pass us that type).
217 #define CSR_TYPE_PEN 0x822
218 #define CSR_TYPE_ERASER 0x82a
219 #define CSR_TYPE_MOUSE_2D 0x007
220 #define CSR_TYPE_MOUSE_4D 0x094
223 typedef struct tagWTPACKET
{
234 UINT pkNormalPressure
;
235 UINT pkTangentPressure
;
236 ORIENTATION pkOrientation
;
237 ROTATION pkRotation
; /* 1.1 */
238 } WTPACKET
, *LPWTPACKET
;
243 #include <X11/Xlib.h>
244 #include <X11/extensions/XInput.h>
246 static int motion_type
;
247 static int button_press_type
;
248 static int button_release_type
;
249 static int key_press_type
;
250 static int key_release_type
;
251 static int proximity_in_type
;
252 static int proximity_out_type
;
254 static HWND hwndTabletDefault
;
255 static WTPACKET gMsgPacket
;
256 static DWORD gSerial
;
257 static INT button_state
[10];
261 static LOGCONTEXTW gSysContext
;
262 static WTI_DEVICES_INFO gSysDevice
;
263 static WTI_CURSORS_INFO gSysCursor
[CURSORMAX
];
264 static INT gNumCursors
;
268 static void *xinput_handle
;
270 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
271 MAKE_FUNCPTR(XListInputDevices
)
272 MAKE_FUNCPTR(XFreeDeviceList
)
273 MAKE_FUNCPTR(XOpenDevice
)
274 MAKE_FUNCPTR(XQueryDeviceState
)
275 MAKE_FUNCPTR(XGetDeviceButtonMapping
)
276 MAKE_FUNCPTR(XCloseDevice
)
277 MAKE_FUNCPTR(XSelectExtensionEvent
)
278 MAKE_FUNCPTR(XFreeDeviceState
)
281 static INT
X11DRV_XInput_Init(void)
283 xinput_handle
= wine_dlopen(SONAME_LIBXI
, RTLD_NOW
, NULL
, 0);
286 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xinput_handle, #f, NULL, 0)) == NULL) goto sym_not_found;
287 LOAD_FUNCPTR(XListInputDevices
)
288 LOAD_FUNCPTR(XFreeDeviceList
)
289 LOAD_FUNCPTR(XOpenDevice
)
290 LOAD_FUNCPTR(XGetDeviceButtonMapping
)
291 LOAD_FUNCPTR(XCloseDevice
)
292 LOAD_FUNCPTR(XSelectExtensionEvent
)
293 LOAD_FUNCPTR(XQueryDeviceState
)
294 LOAD_FUNCPTR(XFreeDeviceState
)
302 static int Tablet_ErrorHandler(Display
*dpy
, XErrorEvent
*event
, void* arg
)
307 static int find_cursor_by_type(int cursor_type
, int exclude
)
310 for (i
= 0; i
< gNumCursors
; i
++)
312 if (gSysCursor
[i
].TYPE
== cursor_type
)
318 static void swap_cursors(int a
, int b
)
320 WTI_CURSORS_INFO temp
;
321 temp
= gSysCursor
[a
];
322 gSysCursor
[a
] = gSysCursor
[b
];
323 gSysCursor
[b
] = temp
;
326 /* Adobe Photoshop 7.0 relies on the eraser being cursor #2 or #5, and it assumes the stylus is 1.
327 ** If the X configuration is not set up that way, make it
329 static void Tablet_FixupCursors(void)
331 if (gNumCursors
>= 1)
332 if (gSysCursor
[1].TYPE
!= CSR_TYPE_PEN
)
335 stylus
= find_cursor_by_type(CSR_TYPE_PEN
, 1);
338 swap_cursors(1, stylus
);
339 TRACE("Swapped cursor %d with stylus slot (1) for compatibility with older programs\n", stylus
);
343 if (gNumCursors
>= 2)
344 if (gSysCursor
[2].TYPE
!= CSR_TYPE_ERASER
)
347 eraser
= find_cursor_by_type(CSR_TYPE_ERASER
, 2);
350 swap_cursors(2, eraser
);
351 TRACE("Swapped cursor %d with eraser slot (2) for compatibility with older programs\n", eraser
);
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 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
))
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
391 static BOOL
is_tablet_cursor(const char *name
, const char *type
)
394 static const char *tablet_cursor_whitelist
[] = {
406 for (i
=0; tablet_cursor_whitelist
[i
] != NULL
; i
++) {
407 if (name
&& match_token(name
, tablet_cursor_whitelist
[i
]))
409 if (type
&& match_token(type
, tablet_cursor_whitelist
[i
]))
415 static BOOL
is_stylus(const char *name
, const char *type
)
418 static const char* tablet_stylus_whitelist
[] = {
425 for (i
=0; tablet_stylus_whitelist
[i
] != NULL
; i
++) {
426 if (name
&& match_token(name
, tablet_stylus_whitelist
[i
]))
428 if (type
&& match_token(type
, tablet_stylus_whitelist
[i
]))
435 static BOOL
is_eraser(const char *name
, const char *type
)
437 if (name
&& match_token(name
, "eraser"))
439 if (type
&& match_token(type
, "eraser"))
445 /***********************************************************************
446 * X11DRV_LoadTabletInfo (X11DRV.@)
448 void X11DRV_LoadTabletInfo(HWND hwnddefault
)
450 const WCHAR SZ_CONTEXT_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
451 const WCHAR SZ_DEVICE_NAME
[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
452 const WCHAR SZ_NON_PLUGINPLAY
[] = {'n','o','n','-','p','l','u','g','i','n','p','l','a','y',0};
454 struct x11drv_thread_data
*data
= x11drv_thread_data();
458 XDeviceInfo
*devices
;
459 XDeviceInfo
*target
= NULL
;
460 BOOL axis_read_complete
= FALSE
;
463 XButtonInfoPtr Button
;
464 XValuatorInfoPtr Val
;
469 if (!X11DRV_XInput_Init())
471 ERR("Unable to initialize the XInput library.\n");
475 hwndTabletDefault
= hwnddefault
;
477 /* Do base initialization */
478 strcpyW(gSysContext
.lcName
, SZ_CONTEXT_NAME
);
479 strcpyW(gSysDevice
.NAME
, SZ_DEVICE_NAME
);
481 gSysContext
.lcOptions
= CXO_SYSTEM
;
482 gSysContext
.lcLocks
= CXL_INSIZE
| CXL_INASPECT
| CXL_MARGIN
|
483 CXL_SENSITIVITY
| CXL_SYSOUT
;
485 gSysContext
.lcMsgBase
= WT_DEFBASE
;
486 gSysContext
.lcDevice
= 0;
487 gSysContext
.lcPktData
=
488 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
489 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
490 gSysContext
.lcMoveMask
=
491 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
492 gSysContext
.lcStatus
= CXS_ONTOP
;
493 gSysContext
.lcPktRate
= 100;
494 gSysContext
.lcBtnDnMask
= 0xffffffff;
495 gSysContext
.lcBtnUpMask
= 0xffffffff;
496 gSysContext
.lcSensX
= 65536;
497 gSysContext
.lcSensY
= 65536;
498 gSysContext
.lcSensX
= 65536;
499 gSysContext
.lcSensZ
= 65536;
500 gSysContext
.lcSysSensX
= 65536;
501 gSysContext
.lcSysSensY
= 65536;
503 /* Device Defaults */
504 gSysDevice
.HARDWARE
= HWC_HARDPROX
|HWC_PHYSID_CURSORS
;
505 gSysDevice
.FIRSTCSR
= 0;
506 gSysDevice
.PKTRATE
= 100;
508 PK_CONTEXT
| PK_STATUS
| PK_SERIAL_NUMBER
| PK_TIME
| PK_CURSOR
|
509 PK_BUTTONS
| PK_X
| PK_Y
| PK_NORMAL_PRESSURE
| PK_ORIENTATION
;
510 strcpyW(gSysDevice
.PNPID
, SZ_NON_PLUGINPLAY
);
515 devices
= pXListInputDevices(data
->display
, &num_devices
);
518 WARN("XInput Extensions reported as not avalable\n");
522 TRACE("XListInputDevices reports %d devices\n", num_devices
);
523 for (loop
=0; loop
< num_devices
; loop
++)
526 char *device_type
= devices
[loop
].type
? XGetAtomName(data
->display
, devices
[loop
].type
) : NULL
;
527 LPWTI_CURSORS_INFO cursor
;
529 TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %d]\n",
530 loop
, (int) devices
[loop
].id
, devices
[loop
].name
, device_type
? device_type
: "",
531 devices
[loop
].num_classes
, devices
[loop
].use
);
533 switch (devices
[loop
].use
)
535 case IsXExtensionDevice
:
536 #ifdef IsXExtensionPointer
537 case IsXExtensionPointer
:
539 #ifdef IsXExtensionKeyboard
540 case IsXExtensionKeyboard
:
542 TRACE("Is XExtension: Device, Keyboard, or Pointer\n");
544 target
= &devices
[loop
];
545 cursor
= &gSysCursor
[cursor_target
];
547 if (strlen(target
->name
) >= WT_MAX_NAME_LEN
)
549 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target
->name
));
554 X11DRV_expect_error(data
->display
, Tablet_ErrorHandler
, NULL
);
555 opendevice
= pXOpenDevice(data
->display
,target
->id
);
556 if (!X11DRV_check_error() && opendevice
)
558 unsigned char map
[32];
562 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
563 cursor
->BUTTONS
= pXGetDeviceButtonMapping(data
->display
, opendevice
, map
, 32);
564 if (X11DRV_check_error() || cursor
->BUTTONS
<= 0)
566 TRACE("No buttons, Non Tablet Device\n");
567 pXCloseDevice(data
->display
, opendevice
);
572 for (i
=0; i
< cursor
->BUTTONS
; i
++,shft
++)
574 cursor
->BUTTONMAP
[i
] = map
[i
];
575 cursor
->SYSBTNMAP
[i
] = (1<<shft
);
577 pXCloseDevice(data
->display
, opendevice
);
581 WARN("Unable to open device %s\n",target
->name
);
585 MultiByteToWideChar(CP_UNIXCP
, 0, target
->name
, -1, cursor
->NAME
, WT_MAX_NAME_LEN
);
587 if (! is_tablet_cursor(target
->name
, device_type
))
589 WARN("Skipping device %d [name %s|type %s]; not apparently a tablet cursor type device. If this is wrong, please report it to wine-devel@winehq.org\n",
590 loop
, devices
[loop
].name
, device_type
? device_type
: "");
596 cursor
->PKTDATA
= PK_TIME
| PK_CURSOR
| PK_BUTTONS
| PK_X
| PK_Y
|
597 PK_NORMAL_PRESSURE
| PK_TANGENT_PRESSURE
|
600 cursor
->PHYSID
= target
->id
;
601 cursor
->NPBUTTON
= 1;
602 cursor
->NPBTNMARKS
[0] = 0 ;
603 cursor
->NPBTNMARKS
[1] = 1 ;
604 cursor
->CAPABILITIES
= CRC_MULTIMODE
;
605 if (is_stylus(target
->name
, device_type
))
606 cursor
->TYPE
= CSR_TYPE_PEN
;
607 if (is_eraser(target
->name
, device_type
))
608 cursor
->TYPE
= CSR_TYPE_ERASER
;
611 any
= target
->inputclassinfo
;
613 for (class_loop
= 0; class_loop
< target
->num_classes
; class_loop
++)
619 Val
= (XValuatorInfoPtr
) any
;
620 TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n",
621 class_loop
, (int) Val
->class, Val
->length
, Val
->num_axes
, Val
->mode
, Val
->motion_buffer
);
622 if (TRACE_ON(wintab32
))
625 /* FIXME: This is imperfect; we compute our devices capabilities based upon the
626 ** first pen type device we find. However, a more correct implementation
627 ** would require acquiring a wide variety of tablets and running through
628 ** the various inputs to see what the values are. Odds are that a
629 ** more 'correct' algorithm would condense to this one anyway.
631 if (!axis_read_complete
&& cursor
->TYPE
== CSR_TYPE_PEN
)
633 Axis
= (XAxisInfoPtr
) ((char *) Val
+ sizeof
636 if (Val
->num_axes
>=1)
639 gSysDevice
.X
.axMin
= Axis
->min_value
;
640 gSysDevice
.X
.axMax
= Axis
->max_value
;
641 gSysDevice
.X
.axUnits
= TU_INCHES
;
642 gSysDevice
.X
.axResolution
= Axis
->resolution
;
643 gSysContext
.lcInOrgX
= Axis
->min_value
;
644 gSysContext
.lcSysOrgX
= Axis
->min_value
;
645 gSysContext
.lcInExtX
= Axis
->max_value
;
646 gSysContext
.lcSysExtX
= Axis
->max_value
;
649 if (Val
->num_axes
>=2)
652 gSysDevice
.Y
.axMin
= Axis
->min_value
;
653 gSysDevice
.Y
.axMax
= Axis
->max_value
;
654 gSysDevice
.Y
.axUnits
= TU_INCHES
;
655 gSysDevice
.Y
.axResolution
= Axis
->resolution
;
656 gSysContext
.lcInOrgY
= Axis
->min_value
;
657 gSysContext
.lcSysOrgY
= Axis
->min_value
;
658 gSysContext
.lcInExtY
= Axis
->max_value
;
659 gSysContext
.lcSysExtY
= Axis
->max_value
;
662 if (Val
->num_axes
>=3)
664 /* Axis 3 is Normal Pressure */
665 gSysDevice
.NPRESSURE
.axMin
= Axis
->min_value
;
666 gSysDevice
.NPRESSURE
.axMax
= Axis
->max_value
;
667 gSysDevice
.NPRESSURE
.axUnits
= TU_INCHES
;
668 gSysDevice
.NPRESSURE
.axResolution
=
672 if (Val
->num_axes
>= 5)
674 /* Axis 4 and 5 are X and Y tilt */
675 XAxisInfoPtr XAxis
= Axis
;
677 if (max (abs(Axis
->max_value
),
678 abs(XAxis
->max_value
)))
680 gSysDevice
.ORIENTATION
[0].axMin
= 0;
681 gSysDevice
.ORIENTATION
[0].axMax
= 3600;
682 gSysDevice
.ORIENTATION
[0].axUnits
= TU_CIRCLE
;
683 gSysDevice
.ORIENTATION
[0].axResolution
685 gSysDevice
.ORIENTATION
[1].axMin
= -1000;
686 gSysDevice
.ORIENTATION
[1].axMax
= 1000;
687 gSysDevice
.ORIENTATION
[1].axUnits
= TU_CIRCLE
;
688 gSysDevice
.ORIENTATION
[1].axResolution
693 axis_read_complete
= TRUE
;
702 Button
= (XButtonInfoPtr
) any
;
703 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
704 class_loop
, (int) Button
->class, Button
->length
, Button
->num_buttons
);
705 cursor
->BTNNAMES
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
)*cchBuf
);
706 for (i
= 0; i
< cursor
->BUTTONS
; i
++)
708 /* FIXME - these names are probably incorrect */
709 int cch
= strlenW(cursor
->NAME
) + 1;
710 while (cch
> cchBuf
- cchPos
- 1) /* we want one extra byte for the last NUL */
713 cursor
->BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
->BTNNAMES
, sizeof(WCHAR
)*cchBuf
);
716 strcpyW(cursor
->BTNNAMES
+ cchPos
, cursor
->NAME
);
719 cursor
->BTNNAMES
[cchPos
++] = 0;
720 cursor
->BTNNAMES
= HeapReAlloc(GetProcessHeap(), 0, cursor
->BTNNAMES
, sizeof(WCHAR
)*cchPos
);
721 cursor
->cchBTNNAMES
= cchPos
;
725 any
= (XAnyClassPtr
) ((char*) any
+ any
->length
);
732 pXFreeDeviceList(devices
);
734 if (axis_read_complete
)
736 gSysDevice
.NCSRTYPES
= cursor_target
+1;
737 gNumCursors
= cursor_target
+1;
738 Tablet_FixupCursors();
741 WARN("Did not find a valid stylus cursor with >= 5 axes, returning 0 valid devices.\n");
746 static int figure_deg(int x
, int y
)
750 angle
= atan2((float)y
, (float)x
);
755 return (0.5 + (angle
* 1800.0 / M_PI
));
758 static int get_button_state(int curnum
)
760 return button_state
[curnum
];
763 static void set_button_state(int curnum
, XID deviceid
)
765 struct x11drv_thread_data
*data
= x11drv_thread_data();
773 device
= pXOpenDevice(data
->display
,deviceid
);
774 state
= pXQueryDeviceState(data
->display
,device
);
779 for (loop
= 0; loop
< state
->num_classes
; loop
++)
781 if (class->class == ButtonClass
)
784 XButtonState
*button_state
= (XButtonState
*)class;
785 for (loop2
= 0; loop2
< button_state
->num_buttons
; loop2
++)
787 if (button_state
->buttons
[loop2
/ 8] & (1 << (loop2
% 8)))
793 class = (XInputClass
*) ((char *) class + class->length
);
796 pXFreeDeviceState(state
);
798 button_state
[curnum
] = rc
;
801 static int cursor_from_device(DWORD deviceid
, LPWTI_CURSORS_INFO
*cursorp
)
804 for (i
= 0; i
< gNumCursors
; i
++)
805 if (gSysCursor
[i
].PHYSID
== deviceid
)
807 *cursorp
= &gSysCursor
[i
];
811 ERR("Could not map device id %d to a cursor\n", (int) deviceid
);
815 static void motion_event( HWND hwnd
, XEvent
*event
)
817 XDeviceMotionEvent
*motion
= (XDeviceMotionEvent
*)event
;
818 LPWTI_CURSORS_INFO cursor
;
819 int curnum
= cursor_from_device(motion
->deviceid
, &cursor
);
823 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
825 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd
, (int) motion
->deviceid
, curnum
);
827 /* Set cursor to inverted if cursor is the eraser */
828 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
829 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(motion
->time
);
830 gMsgPacket
.pkSerialNumber
= gSerial
++;
831 gMsgPacket
.pkCursor
= curnum
;
832 gMsgPacket
.pkX
= motion
->axis_data
[0];
833 gMsgPacket
.pkY
= motion
->axis_data
[1];
834 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(motion
->axis_data
[3],motion
->axis_data
[4]);
835 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max
836 (abs(motion
->axis_data
[3]),
837 abs(motion
->axis_data
[4])))
838 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
839 gMsgPacket
.pkNormalPressure
= motion
->axis_data
[2];
840 gMsgPacket
.pkButtons
= get_button_state(curnum
);
841 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
844 static void button_event( HWND hwnd
, XEvent
*event
)
846 XDeviceButtonEvent
*button
= (XDeviceButtonEvent
*) event
;
847 LPWTI_CURSORS_INFO cursor
;
848 int curnum
= cursor_from_device(button
->deviceid
, &cursor
);
852 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
854 TRACE("Received tablet button %s event\n", (event
->type
== button_press_type
)?"press":"release");
856 /* Set cursor to inverted if cursor is the eraser */
857 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
858 set_button_state(curnum
, button
->deviceid
);
859 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(button
->time
);
860 gMsgPacket
.pkSerialNumber
= gSerial
++;
861 gMsgPacket
.pkCursor
= curnum
;
862 gMsgPacket
.pkX
= button
->axis_data
[0];
863 gMsgPacket
.pkY
= button
->axis_data
[1];
864 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(button
->axis_data
[3],button
->axis_data
[4]);
865 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(button
->axis_data
[3]),
866 abs(button
->axis_data
[4])))
867 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
868 gMsgPacket
.pkNormalPressure
= button
->axis_data
[2];
869 gMsgPacket
.pkButtons
= get_button_state(curnum
);
870 SendMessageW(hwndTabletDefault
,WT_PACKET
,gMsgPacket
.pkSerialNumber
,(LPARAM
)hwnd
);
873 static void key_event( HWND hwnd
, XEvent
*event
)
875 if (event
->type
== key_press_type
)
876 FIXME("Received tablet key press event\n");
878 FIXME("Received tablet key release event\n");
881 static void proximity_event( HWND hwnd
, XEvent
*event
)
883 XProximityNotifyEvent
*proximity
= (XProximityNotifyEvent
*) event
;
884 LPWTI_CURSORS_INFO cursor
;
885 int curnum
= cursor_from_device(proximity
->deviceid
, &cursor
);
886 LPARAM proximity_info
;
888 TRACE("hwnd=%p\n", hwnd
);
893 memset(&gMsgPacket
,0,sizeof(WTPACKET
));
895 /* Set cursor to inverted if cursor is the eraser */
896 gMsgPacket
.pkStatus
= (cursor
->TYPE
== CSR_TYPE_ERASER
? TPS_INVERT
:0);
897 gMsgPacket
.pkStatus
|= (event
->type
==proximity_out_type
)?TPS_PROXIMITY
:0;
898 gMsgPacket
.pkTime
= EVENT_x11_time_to_win32_time(proximity
->time
);
899 gMsgPacket
.pkSerialNumber
= gSerial
++;
900 gMsgPacket
.pkCursor
= curnum
;
901 gMsgPacket
.pkX
= proximity
->axis_data
[0];
902 gMsgPacket
.pkY
= proximity
->axis_data
[1];
903 gMsgPacket
.pkOrientation
.orAzimuth
= figure_deg(proximity
->axis_data
[3],proximity
->axis_data
[4]);
904 gMsgPacket
.pkOrientation
.orAltitude
= ((1000 - 15 * max(abs(proximity
->axis_data
[3]),
905 abs(proximity
->axis_data
[4])))
906 * (gMsgPacket
.pkStatus
& TPS_INVERT
?-1:1));
907 gMsgPacket
.pkNormalPressure
= proximity
->axis_data
[2];
908 gMsgPacket
.pkButtons
= get_button_state(curnum
);
910 /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context
911 * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct
913 * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity"
914 * WPARAM contains context handle.
915 * HWND to HCTX is handled by wintab32.
917 proximity_info
= MAKELPARAM((event
->type
== proximity_in_type
),
918 (event
->type
== proximity_in_type
) || (event
->type
== proximity_out_type
));
919 SendMessageW(hwndTabletDefault
, WT_PROXIMITY
, (WPARAM
)hwnd
, proximity_info
);
922 /***********************************************************************
923 * X11DRV_AttachEventQueueToTablet (X11DRV.@)
925 int X11DRV_AttachEventQueueToTablet(HWND hOwner
)
927 struct x11drv_thread_data
*data
= x11drv_thread_data();
931 XDeviceInfo
*devices
;
932 XDeviceInfo
*target
= NULL
;
934 XEventClass event_list
[7];
935 Window win
= X11DRV_get_whole_window( hOwner
);
939 TRACE("Creating context for window %p (%lx) %i cursors\n", hOwner
, win
, gNumCursors
);
942 devices
= pXListInputDevices(data
->display
, &num_devices
);
944 X11DRV_expect_error(data
->display
,Tablet_ErrorHandler
,NULL
);
945 for (cur_loop
=0; cur_loop
< gNumCursors
; cur_loop
++)
947 char cursorNameA
[WT_MAX_NAME_LEN
];
950 /* the cursor name fits in the buffer because too long names are skipped */
951 WideCharToMultiByte(CP_UNIXCP
, 0, gSysCursor
[cur_loop
].NAME
, -1, cursorNameA
, WT_MAX_NAME_LEN
, NULL
, NULL
);
952 for (loop
=0; loop
< num_devices
; loop
++)
953 if (strcmp(devices
[loop
].name
, cursorNameA
) == 0)
954 target
= &devices
[loop
];
956 TRACE("Opening cursor %i id %i\n",cur_loop
,(INT
)target
->id
);
958 the_device
= pXOpenDevice(data
->display
, target
->id
);
962 WARN("Unable to Open device\n");
966 if (the_device
->num_classes
> 0)
968 DeviceKeyPress(the_device
, key_press_type
, event_list
[event_number
]);
969 if (key_press_type
) event_number
++;
970 DeviceKeyRelease(the_device
, key_release_type
, event_list
[event_number
]);
971 if (key_release_type
) event_number
++;
972 DeviceButtonPress(the_device
, button_press_type
, event_list
[event_number
]);
973 if (button_press_type
) event_number
++;
974 DeviceButtonRelease(the_device
, button_release_type
, event_list
[event_number
]);
975 if (button_release_type
) event_number
++;
976 DeviceMotionNotify(the_device
, motion_type
, event_list
[event_number
]);
977 if (motion_type
) event_number
++;
978 ProximityIn(the_device
, proximity_in_type
, event_list
[event_number
]);
979 if (proximity_in_type
) event_number
++;
980 ProximityOut(the_device
, proximity_out_type
, event_list
[event_number
]);
981 if (proximity_out_type
) event_number
++;
983 if (key_press_type
) X11DRV_register_event_handler( key_press_type
, key_event
);
984 if (key_release_type
) X11DRV_register_event_handler( key_release_type
, key_event
);
985 if (button_press_type
) X11DRV_register_event_handler( button_press_type
, button_event
);
986 if (button_release_type
) X11DRV_register_event_handler( button_release_type
, button_event
);
987 if (motion_type
) X11DRV_register_event_handler( motion_type
, motion_event
);
988 if (proximity_in_type
) X11DRV_register_event_handler( proximity_in_type
, proximity_event
);
989 if (proximity_out_type
) X11DRV_register_event_handler( proximity_out_type
, proximity_event
);
991 pXSelectExtensionEvent(data
->display
, win
, event_list
, event_number
);
994 XSync(data
->display
, False
);
995 X11DRV_check_error();
997 if (NULL
!= devices
) pXFreeDeviceList(devices
);
1002 /***********************************************************************
1003 * X11DRV_GetCurrentPacket (X11DRV.@)
1005 int X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1007 *packet
= gMsgPacket
;
1012 static inline int CopyTabletData(LPVOID target
, LPCVOID src
, INT size
)
1015 * It is valid to call CopyTabletData with NULL.
1016 * This handles the WTInfo() case where lpOutput is null.
1019 memcpy(target
,src
,size
);
1023 /***********************************************************************
1024 * X11DRV_WTInfoW (X11DRV.@)
1026 UINT
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1029 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1030 * lpOutput == NULL signifies the user only wishes
1031 * to find the size of the data.
1033 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1037 LPWTI_CURSORS_INFO tgtcursor
;
1038 TRACE("(%u, %u, %p)\n", wCategory
, nIndex
, lpOutput
);
1043 /* return largest necessary buffer */
1044 TRACE("%i cursors\n",gNumCursors
);
1047 FIXME("Return proper size\n");
1058 static const WCHAR driver
[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1059 rc
= CopyTabletData(lpOutput
, driver
, (strlenW(driver
) + 1) * sizeof(WCHAR
));
1062 case IFC_SPECVERSION
:
1063 version
= (0x01) | (0x01 << 8);
1064 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1066 case IFC_IMPLVERSION
:
1067 version
= (0x00) | (0x01 << 8);
1068 rc
= CopyTabletData(lpOutput
, &version
,sizeof(WORD
));
1072 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1076 rc
= CopyTabletData(lpOutput
, &num
,sizeof(num
));
1079 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex
);
1085 case WTI_DEFCONTEXT
:
1089 rc
= CopyTabletData(lpOutput
, &gSysContext
,
1090 sizeof(LOGCONTEXTW
));
1093 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcName
,
1094 (strlenW(gSysContext
.lcName
)+1) * sizeof(WCHAR
));
1097 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOptions
,
1101 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcStatus
,
1105 rc
= CopyTabletData (lpOutput
, &gSysContext
.lcLocks
,
1109 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMsgBase
,
1113 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcDevice
,
1117 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktRate
,
1121 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktData
,
1125 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcPktMode
,
1129 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcMoveMask
,
1133 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnDnMask
,
1137 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcBtnUpMask
,
1141 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgX
,
1145 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgY
,
1149 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInOrgZ
,
1153 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtX
,
1157 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtY
,
1161 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcInExtZ
,
1165 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgX
,
1169 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgY
,
1173 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutOrgZ
,
1177 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtX
,
1181 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtY
,
1185 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcOutExtZ
,
1189 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensX
,
1193 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensY
,
1197 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSensZ
,
1201 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysMode
,
1205 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgX
,
1209 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysOrgY
,
1213 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtX
,
1217 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysExtY
,
1221 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensX
,
1225 rc
= CopyTabletData(lpOutput
, &gSysContext
.lcSysSensY
,
1229 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex
);
1243 if (wCategory
- WTI_CURSORS
>= gNumCursors
)
1246 WARN("Requested cursor information for nonexistent cursor %d; only %d cursors\n",
1247 wCategory
- WTI_CURSORS
, gNumCursors
);
1251 tgtcursor
= &gSysCursor
[wCategory
- WTI_CURSORS
];
1255 rc
= CopyTabletData(lpOutput
, &tgtcursor
->NAME
,
1256 (strlenW(tgtcursor
->NAME
)+1) * sizeof(WCHAR
));
1259 rc
= CopyTabletData(lpOutput
,&tgtcursor
->ACTIVE
,
1263 rc
= CopyTabletData(lpOutput
,&tgtcursor
->PKTDATA
,
1267 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONS
,
1270 case CSR_BUTTONBITS
:
1271 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONBITS
,
1275 FIXME("Button Names not returned correctly\n");
1276 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BTNNAMES
,
1277 tgtcursor
->cchBTNNAMES
*sizeof(WCHAR
));
1280 rc
= CopyTabletData(lpOutput
,&tgtcursor
->BUTTONMAP
,
1284 rc
= CopyTabletData(lpOutput
,&tgtcursor
->SYSBTNMAP
,
1287 case CSR_NPBTNMARKS
:
1288 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBTNMARKS
,
1292 rc
= CopyTabletData(lpOutput
,&tgtcursor
->NPBUTTON
,
1295 case CSR_NPRESPONSE
:
1296 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1300 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBUTTON
,
1303 case CSR_TPBTNMARKS
:
1304 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TPBTNMARKS
,
1307 case CSR_TPRESPONSE
:
1308 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1314 id
= tgtcursor
->PHYSID
;
1315 rc
= CopyTabletData(lpOutput
,&id
,sizeof(DWORD
));
1319 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MODE
,sizeof(UINT
));
1321 case CSR_MINPKTDATA
:
1322 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINPKTDATA
,
1325 case CSR_MINBUTTONS
:
1326 rc
= CopyTabletData(lpOutput
,&tgtcursor
->MINBUTTONS
,
1329 case CSR_CAPABILITIES
:
1330 rc
= CopyTabletData(lpOutput
,&tgtcursor
->CAPABILITIES
,
1334 rc
= CopyTabletData(lpOutput
,&tgtcursor
->TYPE
,
1338 FIXME("WTI_CURSORS unhandled index %i\n",nIndex
);
1347 rc
= CopyTabletData(lpOutput
,gSysDevice
.NAME
,
1348 (strlenW(gSysDevice
.NAME
)+1) * sizeof(WCHAR
));
1351 rc
= CopyTabletData(lpOutput
,&gSysDevice
.HARDWARE
,
1355 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NCSRTYPES
,
1359 rc
= CopyTabletData(lpOutput
,&gSysDevice
.FIRSTCSR
,
1363 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTRATE
,
1367 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTDATA
,
1371 rc
= CopyTabletData(lpOutput
,&gSysDevice
.PKTMODE
,
1375 rc
= CopyTabletData(lpOutput
,&gSysDevice
.CSRDATA
,
1379 rc
= CopyTabletData(lpOutput
,&gSysDevice
.XMARGIN
,
1383 rc
= CopyTabletData(lpOutput
,&gSysDevice
.YMARGIN
,
1387 rc
= 0; /* unsupported */
1389 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1394 rc
= CopyTabletData(lpOutput
,&gSysDevice
.X
,
1398 rc
= CopyTabletData(lpOutput
,&gSysDevice
.Y
,
1402 rc
= 0; /* unsupported */
1404 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1409 rc
= CopyTabletData(lpOutput
,&gSysDevice
.NPRESSURE
,
1413 rc
= 0; /* unsupported */
1415 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1419 case DVC_ORIENTATION
:
1420 rc
= CopyTabletData(lpOutput
,&gSysDevice
.ORIENTATION
,
1424 rc
= 0; /* unsupported */
1426 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1431 rc
= CopyTabletData(lpOutput
,gSysDevice
.PNPID
,
1432 (strlenW(gSysDevice
.PNPID
)+1)*sizeof(WCHAR
));
1435 FIXME("WTI_DEVICES unhandled index %i\n",nIndex
);
1440 FIXME("Unhandled Category %i\n",wCategory
);
1445 #else /* SONAME_LIBXI */
1447 /***********************************************************************
1448 * AttachEventQueueToTablet (X11DRV.@)
1450 int X11DRV_AttachEventQueueToTablet(HWND hOwner
)
1455 /***********************************************************************
1456 * GetCurrentPacket (X11DRV.@)
1458 int X11DRV_GetCurrentPacket(LPWTPACKET packet
)
1463 /***********************************************************************
1464 * LoadTabletInfo (X11DRV.@)
1466 void X11DRV_LoadTabletInfo(HWND hwnddefault
)
1470 /***********************************************************************
1471 * WTInfoW (X11DRV.@)
1473 UINT
X11DRV_WTInfoW(UINT wCategory
, UINT nIndex
, LPVOID lpOutput
)
1478 #endif /* SONAME_LIBXI */