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 #define IS_TABLET_CURSOR(n, t) (is_wacom((n), (t)) || is_cursor((n), (t)) || is_stylus((n), (t)) || is_eraser((n), (t)) || is_pad((n), (t)))
393 static BOOL is_wacom(const char *name, const char *type)
395 if (name && match_token(name, "wacom"))
397 if (type && match_token(type, "wacom"))
402 static BOOL is_cursor(const char *name, const char *type)
404 if (name && match_token(name, "cursor"))
406 if (type && match_token(type, "cursor"))
411 static BOOL is_stylus(const char *name, const char *type)
413 if (name && match_token(name, "stylus"))
415 if (type && match_token(type, "stylus"))
420 static BOOL is_eraser(const char *name, const char *type)
422 if (name && match_token(name, "eraser"))
424 if (type && match_token(type, "eraser"))
429 static BOOL is_pad(const char *name, const char *type)
431 if (name && match_token(name, "pad"))
433 if (type && match_token(type, "pad"))
439 void X11DRV_LoadTabletInfo(HWND hwnddefault)
441 const WCHAR SZ_CONTEXT_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0};
442 const WCHAR SZ_DEVICE_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0};
443 const WCHAR SZ_NON_PLUGINPLAY[] = {'n','o','n','-','p','l','u','g','i','n','p','l','a','y',0};
445 struct x11drv_thread_data *data = x11drv_thread_data();
449 XDeviceInfo *devices;
450 XDeviceInfo *target = NULL;
451 BOOL axis_read_complete= FALSE;
454 XButtonInfoPtr Button;
455 XValuatorInfoPtr Val;
460 if (!X11DRV_XInput_Init())
462 ERR("Unable to initialize the XInput library.\n");
466 hwndTabletDefault = hwnddefault;
468 /* Do base initialization */
469 strcpyW(gSysContext.lcName, SZ_CONTEXT_NAME);
470 strcpyW(gSysDevice.NAME, SZ_DEVICE_NAME);
472 gSysContext.lcOptions = CXO_SYSTEM;
473 gSysContext.lcLocks = CXL_INSIZE | CXL_INASPECT | CXL_MARGIN |
474 CXL_SENSITIVITY | CXL_SYSOUT;
476 gSysContext.lcMsgBase= WT_DEFBASE;
477 gSysContext.lcDevice = 0;
478 gSysContext.lcPktData =
479 PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR |
480 PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
481 gSysContext.lcMoveMask=
482 PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
483 gSysContext.lcStatus = CXS_ONTOP;
484 gSysContext.lcPktRate = 100;
485 gSysContext.lcBtnDnMask = 0xffffffff;
486 gSysContext.lcBtnUpMask = 0xffffffff;
487 gSysContext.lcSensX = 65536;
488 gSysContext.lcSensY = 65536;
489 gSysContext.lcSensX = 65536;
490 gSysContext.lcSensZ = 65536;
491 gSysContext.lcSysSensX= 65536;
492 gSysContext.lcSysSensY= 65536;
494 /* Device Defaults */
495 gSysDevice.HARDWARE = HWC_HARDPROX|HWC_PHYSID_CURSORS;
496 gSysDevice.FIRSTCSR= 0;
497 gSysDevice.PKTRATE = 100;
499 PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR |
500 PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION;
501 strcpyW(gSysDevice.PNPID, SZ_NON_PLUGINPLAY);
506 devices = pXListInputDevices(data->display, &num_devices);
509 WARN("XInput Extensions reported as not avalable\n");
513 TRACE("XListInputDevices reports %d devices\n", num_devices);
514 for (loop=0; loop < num_devices; loop++)
517 char *device_type = devices[loop].type ? XGetAtomName(data->display, devices[loop].type) : NULL;
519 TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %s]\n",
520 loop, (int) devices[loop].id, devices[loop].name, device_type ? device_type : "",
521 devices[loop].num_classes,
522 devices[loop].use == IsXKeyboard ? "IsXKeyboard" :
523 devices[loop].use == IsXPointer ? "IsXPointer" :
524 devices[loop].use == IsXExtensionDevice ? "IsXExtensionDevice" :
528 if (devices[loop].use == IsXExtensionDevice)
530 LPWTI_CURSORS_INFO cursor;
532 TRACE("Is Extension Device\n");
534 target = &devices[loop];
535 cursor = &gSysCursor[cursor_target];
537 if (strlen(target->name) >= WT_MAX_NAME_LEN)
539 ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target->name));
545 X11DRV_expect_error(data->display, Tablet_ErrorHandler, NULL);
546 opendevice = pXOpenDevice(data->display,target->id);
547 if (!X11DRV_check_error() && opendevice)
549 unsigned char map[32];
553 X11DRV_expect_error(data->display,Tablet_ErrorHandler,NULL);
554 cursor->BUTTONS = pXGetDeviceButtonMapping(data->display, opendevice, map, 32);
555 if (X11DRV_check_error() || cursor->BUTTONS <= 0)
557 TRACE("No buttons, Non Tablet Device\n");
558 pXCloseDevice(data->display, opendevice);
564 for (i=0; i< cursor->BUTTONS; i++,shft++)
566 cursor->BUTTONMAP[i] = map[i];
567 cursor->SYSBTNMAP[i] = (1<<shft);
569 pXCloseDevice(data->display, opendevice);
573 WARN("Unable to open device %s\n",target->name);
578 MultiByteToWideChar(CP_UNIXCP, 0, target->name, -1, cursor->NAME, WT_MAX_NAME_LEN);
580 if (! IS_TABLET_CURSOR(target->name, device_type))
582 WARN("Skipping device %d [name %s|type %s]; not apparently a tablet cursor type device\n",
583 loop, devices[loop].name, device_type ? device_type : "");
590 cursor->PKTDATA = PK_TIME | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y |
591 PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE |
594 cursor->PHYSID = target->id;
595 cursor->NPBUTTON = 1;
596 cursor->NPBTNMARKS[0] = 0 ;
597 cursor->NPBTNMARKS[1] = 1 ;
598 cursor->CAPABILITIES = CRC_MULTIMODE;
599 if (is_stylus(target->name, device_type))
600 cursor->TYPE = CSR_TYPE_PEN;
601 if (is_eraser(target->name, device_type))
602 cursor->TYPE = CSR_TYPE_ERASER;
605 any = target->inputclassinfo;
607 for (class_loop = 0; class_loop < target->num_classes; class_loop++)
613 Val = (XValuatorInfoPtr) any;
614 TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n",
615 class_loop, (int) Val->class, Val->length, Val->num_axes, Val->mode, Val->motion_buffer);
616 if (TRACE_ON(wintab32))
619 /* FIXME: This is imperfect; we compute our devices capabilities based upon the
620 ** first pen type device we find. However, a more correct implementation
621 ** would require acquiring a wide variety of tablets and running through
622 ** the various inputs to see what the values are. Odds are that a
623 ** more 'correct' algorithm would condense to this one anyway.
625 if (!axis_read_complete && Val->num_axes >= 5 && cursor->TYPE == CSR_TYPE_PEN)
627 Axis = (XAxisInfoPtr) ((char *) Val + sizeof
630 if (Val->num_axes>=1)
633 gSysDevice.X.axMin = Axis->min_value;
634 gSysDevice.X.axMax= Axis->max_value;
635 gSysDevice.X.axUnits = TU_INCHES;
636 gSysDevice.X.axResolution = Axis->resolution;
637 gSysContext.lcInOrgX = Axis->min_value;
638 gSysContext.lcSysOrgX = Axis->min_value;
639 gSysContext.lcInExtX = Axis->max_value;
640 gSysContext.lcSysExtX = Axis->max_value;
643 if (Val->num_axes>=2)
646 gSysDevice.Y.axMin = Axis->min_value;
647 gSysDevice.Y.axMax= Axis->max_value;
648 gSysDevice.Y.axUnits = TU_INCHES;
649 gSysDevice.Y.axResolution = Axis->resolution;
650 gSysContext.lcInOrgY = Axis->min_value;
651 gSysContext.lcSysOrgY = Axis->min_value;
652 gSysContext.lcInExtY = Axis->max_value;
653 gSysContext.lcSysExtY = Axis->max_value;
656 if (Val->num_axes>=3)
658 /* Axis 3 is Normal Pressure */
659 gSysDevice.NPRESSURE.axMin = Axis->min_value;
660 gSysDevice.NPRESSURE.axMax= Axis->max_value;
661 gSysDevice.NPRESSURE.axUnits = TU_INCHES;
662 gSysDevice.NPRESSURE.axResolution =
666 if (Val->num_axes >= 5)
668 /* Axis 4 and 5 are X and Y tilt */
669 XAxisInfoPtr XAxis = Axis;
671 if (max (abs(Axis->max_value),
672 abs(XAxis->max_value)))
674 gSysDevice.ORIENTATION[0].axMin = 0;
675 gSysDevice.ORIENTATION[0].axMax = 3600;
676 gSysDevice.ORIENTATION[0].axUnits = TU_CIRCLE;
677 gSysDevice.ORIENTATION[0].axResolution
679 gSysDevice.ORIENTATION[1].axMin = -1000;
680 gSysDevice.ORIENTATION[1].axMax = 1000;
681 gSysDevice.ORIENTATION[1].axUnits = TU_CIRCLE;
682 gSysDevice.ORIENTATION[1].axResolution
687 axis_read_complete = TRUE;
696 Button = (XButtonInfoPtr) any;
697 TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n",
698 class_loop, (int) Button->class, Button->length, Button->num_buttons);
699 cursor->BTNNAMES = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*cchBuf);
700 for (i = 0; i < cursor->BUTTONS; i++)
702 /* FIXME - these names are probably incorrect */
703 int cch = strlenW(cursor->NAME) + 1;
704 while (cch > cchBuf - cchPos - 1) /* we want one extra byte for the last NUL */
707 cursor->BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor->BTNNAMES, sizeof(WCHAR)*cchBuf);
710 strcpyW(cursor->BTNNAMES + cchPos, cursor->NAME);
713 cursor->BTNNAMES[cchPos++] = 0;
714 cursor->BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor->BTNNAMES, sizeof(WCHAR)*cchPos);
715 cursor->cchBTNNAMES = cchPos;
719 any = (XAnyClassPtr) ((char*) any + any->length);
726 pXFreeDeviceList(devices);
728 if (axis_read_complete)
730 gSysDevice.NCSRTYPES = cursor_target+1;
731 gNumCursors = cursor_target+1;
732 Tablet_FixupCursors();
735 WARN("Did not find a valid stylus cursor with >= 5 axes, returning 0 valid devices.\n");
740 static int figure_deg(int x, int y)
746 rc = (int) 10 * (atan( (FLOAT)abs(y) / (FLOAT)abs(x)) / (3.1415 / 180));
773 static int get_button_state(int curnum)
775 return button_state[curnum];
778 static void set_button_state(int curnum, XID deviceid)
780 struct x11drv_thread_data *data = x11drv_thread_data();
788 device = pXOpenDevice(data->display,deviceid);
789 state = pXQueryDeviceState(data->display,device);
794 for (loop = 0; loop < state->num_classes; loop++)
796 if (class->class == ButtonClass)
799 XButtonState *button_state = (XButtonState*)class;
800 for (loop2 = 0; loop2 < button_state->num_buttons; loop2++)
802 if (button_state->buttons[loop2 / 8] & (1 << (loop2 % 8)))
808 class = (XInputClass *) ((char *) class + class->length);
811 pXFreeDeviceState(state);
813 button_state[curnum] = rc;
816 static int cursor_from_device(DWORD deviceid, LPWTI_CURSORS_INFO *cursorp)
819 for (i = 0; i < gNumCursors; i++)
820 if (gSysCursor[i].PHYSID == deviceid)
822 *cursorp = &gSysCursor[i];
826 ERR("Could not map device id %d to a cursor\n", (int) deviceid);
830 static void motion_event( HWND hwnd, XEvent *event )
832 XDeviceMotionEvent *motion = (XDeviceMotionEvent *)event;
833 LPWTI_CURSORS_INFO cursor;
834 int curnum = cursor_from_device(motion->deviceid, &cursor);
838 memset(&gMsgPacket,0,sizeof(WTPACKET));
840 TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd, (int) motion->deviceid, curnum);
842 /* Set cursor to inverted if cursor is the eraser */
843 gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0);
844 gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(motion->time);
845 gMsgPacket.pkSerialNumber = gSerial++;
846 gMsgPacket.pkCursor = curnum;
847 gMsgPacket.pkX = motion->axis_data[0];
848 gMsgPacket.pkY = motion->axis_data[1];
849 gMsgPacket.pkOrientation.orAzimuth = figure_deg(motion->axis_data[3],motion->axis_data[4]);
850 gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max
851 (abs(motion->axis_data[3]),
852 abs(motion->axis_data[4])))
853 * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
854 gMsgPacket.pkNormalPressure = motion->axis_data[2];
855 gMsgPacket.pkButtons = get_button_state(curnum);
856 SendMessageW(hwndTabletDefault,WT_PACKET,0,(LPARAM)hwnd);
859 static void button_event( HWND hwnd, XEvent *event )
861 XDeviceButtonEvent *button = (XDeviceButtonEvent *) event;
862 LPWTI_CURSORS_INFO cursor;
863 int curnum = cursor_from_device(button->deviceid, &cursor);
867 memset(&gMsgPacket,0,sizeof(WTPACKET));
869 TRACE("Received tablet button %s event\n", (event->type == button_press_type)?"press":"release");
871 /* Set cursor to inverted if cursor is the eraser */
872 gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0);
873 set_button_state(curnum, button->deviceid);
874 gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(button->time);
875 gMsgPacket.pkSerialNumber = gSerial++;
876 gMsgPacket.pkCursor = curnum;
877 gMsgPacket.pkX = button->axis_data[0];
878 gMsgPacket.pkY = button->axis_data[1];
879 gMsgPacket.pkOrientation.orAzimuth = figure_deg(button->axis_data[3],button->axis_data[4]);
880 gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(button->axis_data[3]),
881 abs(button->axis_data[4])))
882 * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
883 gMsgPacket.pkNormalPressure = button->axis_data[2];
884 gMsgPacket.pkButtons = get_button_state(curnum);
885 SendMessageW(hwndTabletDefault,WT_PACKET,0,(LPARAM)hwnd);
888 static void key_event( HWND hwnd, XEvent *event )
890 if (event->type == key_press_type)
891 FIXME("Received tablet key press event\n");
893 FIXME("Received tablet key release event\n");
896 static void proximity_event( HWND hwnd, XEvent *event )
898 XProximityNotifyEvent *proximity = (XProximityNotifyEvent *) event;
899 LPWTI_CURSORS_INFO cursor;
900 int curnum = cursor_from_device(proximity->deviceid, &cursor);
904 memset(&gMsgPacket,0,sizeof(WTPACKET));
906 TRACE("Received tablet proximity event\n");
907 /* Set cursor to inverted if cursor is the eraser */
908 gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0);
909 gMsgPacket.pkStatus |= (event->type==proximity_out_type)?TPS_PROXIMITY:0;
910 gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(proximity->time);
911 gMsgPacket.pkSerialNumber = gSerial++;
912 gMsgPacket.pkCursor = curnum;
913 gMsgPacket.pkX = proximity->axis_data[0];
914 gMsgPacket.pkY = proximity->axis_data[1];
915 gMsgPacket.pkOrientation.orAzimuth = figure_deg(proximity->axis_data[3],proximity->axis_data[4]);
916 gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(proximity->axis_data[3]),
917 abs(proximity->axis_data[4])))
918 * (gMsgPacket.pkStatus & TPS_INVERT?-1:1));
919 gMsgPacket.pkNormalPressure = proximity->axis_data[2];
920 gMsgPacket.pkButtons = get_button_state(curnum);
922 SendMessageW(hwndTabletDefault, WT_PROXIMITY, (event->type == proximity_in_type), (LPARAM)hwnd);
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 int X11DRV_GetCurrentPacket(LPWTPACKET *packet)
1004 memcpy(packet,&gMsgPacket,sizeof(WTPACKET));
1009 static inline int CopyTabletData(LPVOID target, LPCVOID src, INT size)
1012 * It is valid to call CopyTabletData with NULL.
1013 * This handles the WTInfo() case where lpOutput is null.
1016 memcpy(target,src,size);
1020 /***********************************************************************
1021 * X11DRV_WTInfoW (X11DRV.@)
1023 UINT X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
1026 * It is valid to call WTInfoA with lpOutput == NULL, as per standard.
1027 * lpOutput == NULL signifies the user only wishes
1028 * to find the size of the data.
1030 * From now on use CopyTabletData to fill lpOutput. memcpy will break
1034 LPWTI_CURSORS_INFO tgtcursor;
1035 TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput);
1040 /* return largest necessary buffer */
1041 TRACE("%i cursors\n",gNumCursors);
1044 FIXME("Return proper size\n");
1055 static const WCHAR driver[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0};
1056 rc = CopyTabletData(lpOutput, driver, (strlenW(driver) + 1) * sizeof(WCHAR));
1059 case IFC_SPECVERSION:
1060 version = (0x01) | (0x01 << 8);
1061 rc = CopyTabletData(lpOutput, &version,sizeof(WORD));
1063 case IFC_IMPLVERSION:
1064 version = (0x00) | (0x01 << 8);
1065 rc = CopyTabletData(lpOutput, &version,sizeof(WORD));
1069 rc = CopyTabletData(lpOutput, &num,sizeof(num));
1073 rc = CopyTabletData(lpOutput, &num,sizeof(num));
1076 FIXME("WTI_INTERFACE unhandled index %i\n",nIndex);
1082 case WTI_DEFCONTEXT:
1086 rc = CopyTabletData(lpOutput, &gSysContext,
1087 sizeof(LOGCONTEXTW));
1090 rc = CopyTabletData(lpOutput, &gSysContext.lcName,
1091 (strlenW(gSysContext.lcName)+1) * sizeof(WCHAR));
1094 rc = CopyTabletData(lpOutput, &gSysContext.lcOptions,
1098 rc = CopyTabletData(lpOutput, &gSysContext.lcStatus,
1102 rc= CopyTabletData (lpOutput, &gSysContext.lcLocks,
1106 rc = CopyTabletData(lpOutput, &gSysContext.lcMsgBase,
1110 rc = CopyTabletData(lpOutput, &gSysContext.lcDevice,
1114 rc = CopyTabletData(lpOutput, &gSysContext.lcPktRate,
1118 rc = CopyTabletData(lpOutput, &gSysContext.lcPktData,
1122 rc = CopyTabletData(lpOutput, &gSysContext.lcPktMode,
1126 rc = CopyTabletData(lpOutput, &gSysContext.lcMoveMask,
1130 rc = CopyTabletData(lpOutput, &gSysContext.lcBtnDnMask,
1134 rc = CopyTabletData(lpOutput, &gSysContext.lcBtnUpMask,
1138 rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgX,
1142 rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgY,
1146 rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgZ,
1150 rc = CopyTabletData(lpOutput, &gSysContext.lcInExtX,
1154 rc = CopyTabletData(lpOutput, &gSysContext.lcInExtY,
1158 rc = CopyTabletData(lpOutput, &gSysContext.lcInExtZ,
1162 rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgX,
1166 rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgY,
1170 rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgZ,
1174 rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtX,
1178 rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtY,
1182 rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtZ,
1186 rc = CopyTabletData(lpOutput, &gSysContext.lcSensX,
1190 rc = CopyTabletData(lpOutput, &gSysContext.lcSensY,
1194 rc = CopyTabletData(lpOutput, &gSysContext.lcSensZ,
1198 rc = CopyTabletData(lpOutput, &gSysContext.lcSysMode,
1202 rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgX,
1206 rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgY,
1210 rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtX,
1214 rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtY,
1218 rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensX,
1222 rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensY,
1226 FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex);
1240 if (wCategory - WTI_CURSORS >= gNumCursors)
1243 WARN("Requested cursor information for nonexistent cursor %d; only %d cursors\n",
1244 wCategory - WTI_CURSORS, gNumCursors);
1248 tgtcursor = &gSysCursor[wCategory - WTI_CURSORS];
1252 rc = CopyTabletData(lpOutput, &tgtcursor->NAME,
1253 (strlenW(tgtcursor->NAME)+1) * sizeof(WCHAR));
1256 rc = CopyTabletData(lpOutput,&tgtcursor->ACTIVE,
1260 rc = CopyTabletData(lpOutput,&tgtcursor->PKTDATA,
1264 rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONS,
1267 case CSR_BUTTONBITS:
1268 rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONBITS,
1272 FIXME("Button Names not returned correctly\n");
1273 rc = CopyTabletData(lpOutput,&tgtcursor->BTNNAMES,
1274 tgtcursor->cchBTNNAMES*sizeof(WCHAR));
1277 rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONMAP,
1281 rc = CopyTabletData(lpOutput,&tgtcursor->SYSBTNMAP,
1284 case CSR_NPBTNMARKS:
1285 rc = CopyTabletData(lpOutput,&tgtcursor->NPBTNMARKS,
1289 rc = CopyTabletData(lpOutput,&tgtcursor->NPBUTTON,
1292 case CSR_NPRESPONSE:
1293 FIXME("Not returning CSR_NPRESPONSE correctly\n");
1297 rc = CopyTabletData(lpOutput,&tgtcursor->TPBUTTON,
1300 case CSR_TPBTNMARKS:
1301 rc = CopyTabletData(lpOutput,&tgtcursor->TPBTNMARKS,
1304 case CSR_TPRESPONSE:
1305 FIXME("Not returning CSR_TPRESPONSE correctly\n");
1311 id = tgtcursor->PHYSID;
1312 rc = CopyTabletData(lpOutput,&id,sizeof(DWORD));
1316 rc = CopyTabletData(lpOutput,&tgtcursor->MODE,sizeof(UINT));
1318 case CSR_MINPKTDATA:
1319 rc = CopyTabletData(lpOutput,&tgtcursor->MINPKTDATA,
1322 case CSR_MINBUTTONS:
1323 rc = CopyTabletData(lpOutput,&tgtcursor->MINBUTTONS,
1326 case CSR_CAPABILITIES:
1327 rc = CopyTabletData(lpOutput,&tgtcursor->CAPABILITIES,
1331 rc = CopyTabletData(lpOutput,&tgtcursor->TYPE,
1335 FIXME("WTI_CURSORS unhandled index %i\n",nIndex);
1344 rc = CopyTabletData(lpOutput,gSysDevice.NAME,
1345 (strlenW(gSysDevice.NAME)+1) * sizeof(WCHAR));
1348 rc = CopyTabletData(lpOutput,&gSysDevice.HARDWARE,
1352 rc = CopyTabletData(lpOutput,&gSysDevice.NCSRTYPES,
1356 rc = CopyTabletData(lpOutput,&gSysDevice.FIRSTCSR,
1360 rc = CopyTabletData(lpOutput,&gSysDevice.PKTRATE,
1364 rc = CopyTabletData(lpOutput,&gSysDevice.PKTDATA,
1368 rc = CopyTabletData(lpOutput,&gSysDevice.PKTMODE,
1372 rc = CopyTabletData(lpOutput,&gSysDevice.CSRDATA,
1376 rc = CopyTabletData(lpOutput,&gSysDevice.XMARGIN,
1380 rc = CopyTabletData(lpOutput,&gSysDevice.YMARGIN,
1384 rc = 0; /* unsupported */
1386 rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN,
1391 rc = CopyTabletData(lpOutput,&gSysDevice.X,
1395 rc = CopyTabletData(lpOutput,&gSysDevice.Y,
1399 rc = 0; /* unsupported */
1401 rc = CopyTabletData(lpOutput,&gSysDevice.Z,
1406 rc = CopyTabletData(lpOutput,&gSysDevice.NPRESSURE,
1410 rc = 0; /* unsupported */
1412 rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE,
1416 case DVC_ORIENTATION:
1417 rc = CopyTabletData(lpOutput,&gSysDevice.ORIENTATION,
1421 rc = 0; /* unsupported */
1423 rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION,
1428 rc = CopyTabletData(lpOutput,gSysDevice.PNPID,
1429 (strlenW(gSysDevice.PNPID)+1)*sizeof(WCHAR));
1432 FIXME("WTI_DEVICES unhandled index %i\n",nIndex);
1437 FIXME("Unhandled Category %i\n",wCategory);
1442 #else /* SONAME_LIBXI */
1444 /***********************************************************************
1445 * AttachEventQueueToTablet (X11DRV.@)
1447 int X11DRV_AttachEventQueueToTablet(HWND hOwner)
1452 /***********************************************************************
1453 * GetCurrentPacket (X11DRV.@)
1455 int X11DRV_GetCurrentPacket(LPWTPACKET *packet)
1460 /***********************************************************************
1461 * LoadTabletInfo (X11DRV.@)
1463 void X11DRV_LoadTabletInfo(HWND hwnddefault)
1467 /***********************************************************************
1468 * WTInfoW (X11DRV.@)
1470 UINT X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
1475 #endif /* SONAME_LIBXI */