| /* |
| * X11 tablet driver |
| * |
| * Copyright 2003 CodeWeavers (Aric Stewart) |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdlib.h> |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winnls.h" |
| #include "x11drv.h" |
| #include "wine/library.h" |
| #include "wine/unicode.h" |
| #include "wine/debug.h" |
| #include "wintab.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(wintab32); |
| |
| #define WT_MAX_NAME_LEN 256 |
| |
| typedef struct tagWTI_CURSORS_INFO |
| { |
| WCHAR NAME[WT_MAX_NAME_LEN]; |
| /* a displayable zero-terminated string containing the name of the |
| * cursor. |
| */ |
| BOOL ACTIVE; |
| /* whether the cursor is currently connected. */ |
| WTPKT PKTDATA; |
| /* a bit mask indicating the packet data items supported when this |
| * cursor is connected. |
| */ |
| BYTE BUTTONS; |
| /* the number of buttons on this cursor. */ |
| BYTE BUTTONBITS; |
| /* the number of bits of raw button data returned by the hardware.*/ |
| DWORD cchBTNNAMES; |
| WCHAR *BTNNAMES; |
| /* a list of zero-terminated strings containing the names of the |
| * cursor's buttons. The number of names in the list is the same as the |
| * number of buttons on the cursor. The names are separated by a single |
| * zero character; the list is terminated by two zero characters. |
| */ |
| BYTE BUTTONMAP[32]; |
| /* a 32 byte array of logical button numbers, one for each physical |
| * button. |
| */ |
| BYTE SYSBTNMAP[32]; |
| /* a 32 byte array of button action codes, one for each logical |
| * button. |
| */ |
| BYTE NPBUTTON; |
| /* the physical button number of the button that is controlled by normal |
| * pressure. |
| */ |
| UINT NPBTNMARKS[2]; |
| /* an array of two UINTs, specifying the button marks for the normal |
| * pressure button. The first UINT contains the release mark; the second |
| * contains the press mark. |
| */ |
| UINT *NPRESPONSE; |
| /* an array of UINTs describing the pressure response curve for normal |
| * pressure. |
| */ |
| BYTE TPBUTTON; |
| /* the physical button number of the button that is controlled by |
| * tangential pressure. |
| */ |
| UINT TPBTNMARKS[2]; |
| /* an array of two UINTs, specifying the button marks for the tangential |
| * pressure button. The first UINT contains the release mark; the second |
| * contains the press mark. |
| */ |
| UINT *TPRESPONSE; |
| /* an array of UINTs describing the pressure response curve for |
| * tangential pressure. |
| */ |
| DWORD PHYSID; |
| /* a manufacturer-specific physical identifier for the cursor. This |
| * value will distinguish the physical cursor from others on the same |
| * device. This physical identifier allows applications to bind |
| * functions to specific physical cursors, even if category numbers |
| * change and multiple, otherwise identical, physical cursors are |
| * present. |
| */ |
| UINT MODE; |
| /* the cursor mode number of this cursor type, if this cursor type has |
| * the CRC_MULTIMODE capability. |
| */ |
| UINT MINPKTDATA; |
| /* the minimum set of data available from a physical cursor in this |
| * cursor type, if this cursor type has the CRC_AGGREGATE capability. |
| */ |
| UINT MINBUTTONS; |
| /* the minimum number of buttons of physical cursors in the cursor type, |
| * if this cursor type has the CRC_AGGREGATE capability. |
| */ |
| UINT CAPABILITIES; |
| /* flags indicating cursor capabilities, as defined below: |
| CRC_MULTIMODE |
| Indicates this cursor type describes one of several modes of a |
| single physical cursor. Consecutive cursor type categories |
| describe the modes; the CSR_MODE data item gives the mode number |
| of each cursor type. |
| CRC_AGGREGATE |
| Indicates this cursor type describes several physical cursors |
| that cannot be distinguished by software. |
| CRC_INVERT |
| Indicates this cursor type describes the physical cursor in its |
| inverted orientation; the previous consecutive cursor type |
| category describes the normal orientation. |
| */ |
| UINT TYPE; |
| /* Manufacturer Unique id for the item type */ |
| } WTI_CURSORS_INFO, *LPWTI_CURSORS_INFO; |
| |
| |
| typedef struct tagWTI_DEVICES_INFO |
| { |
| WCHAR NAME[WT_MAX_NAME_LEN]; |
| /* a displayable null- terminated string describing the device, |
| * manufacturer, and revision level. |
| */ |
| UINT HARDWARE; |
| /* flags indicating hardware and driver capabilities, as defined |
| * below: |
| HWC_INTEGRATED: |
| Indicates that the display and digitizer share the same surface. |
| HWC_TOUCH |
| Indicates that the cursor must be in physical contact with the |
| device to report position. |
| HWC_HARDPROX |
| Indicates that device can generate events when the cursor is |
| entering and leaving the physical detection range. |
| HWC_PHYSID_CURSORS |
| Indicates that device can uniquely identify the active cursor in |
| hardware. |
| */ |
| UINT NCSRTYPES; |
| /* the number of supported cursor types.*/ |
| UINT FIRSTCSR; |
| /* the first cursor type number for the device. */ |
| UINT PKTRATE; |
| /* the maximum packet report rate in Hertz. */ |
| WTPKT PKTDATA; |
| /* a bit mask indicating which packet data items are always available.*/ |
| WTPKT PKTMODE; |
| /* a bit mask indicating which packet data items are physically |
| * relative, i.e., items for which the hardware can only report change, |
| * not absolute measurement. |
| */ |
| WTPKT CSRDATA; |
| /* a bit mask indicating which packet data items are only available when |
| * certain cursors are connected. The individual cursor descriptions |
| * must be consulted to determine which cursors return which data. |
| */ |
| INT XMARGIN; |
| INT YMARGIN; |
| INT ZMARGIN; |
| /* the size of tablet context margins in tablet native coordinates, in |
| * the x, y, and z directions, respectively. |
| */ |
| AXIS X; |
| AXIS Y; |
| AXIS Z; |
| /* the tablet's range and resolution capabilities, in the x, y, and z |
| * axes, respectively. |
| */ |
| AXIS NPRESSURE; |
| AXIS TPRESSURE; |
| /* the tablet's range and resolution capabilities, for the normal and |
| * tangential pressure inputs, respectively. |
| */ |
| AXIS ORIENTATION[3]; |
| /* a 3-element array describing the tablet's orientation range and |
| * resolution capabilities. |
| */ |
| AXIS ROTATION[3]; |
| /* a 3-element array describing the tablet's rotation range and |
| * resolution capabilities. |
| */ |
| WCHAR PNPID[WT_MAX_NAME_LEN]; |
| /* a null-terminated string containing the devices Plug and Play ID.*/ |
| } WTI_DEVICES_INFO, *LPWTI_DEVICES_INFO; |
| |
| |
| /*********************************************************************** |
| * WACOM WINTAB EXTENSIONS TO SUPPORT CSR_TYPE |
| * In Wintab 1.2, a CSR_TYPE feature was added. This adds the |
| * ability to return a type of cursor on a tablet. |
| * Unfortunately, we cannot get the cursor type directly from X, |
| * and it is not specified directly anywhere. So we virtualize |
| * the type here. (This is unfortunate, the kernel module has |
| * the exact type, but we have no way of getting that module to |
| * pass us that type). |
| * |
| * Reference linuxwacom driver project wcmCommon.c function |
| * idtotype for a much larger list of CSR_TYPE. |
| * |
| * http://linuxwacom.cvs.sourceforge.net/linuxwacom/linuxwacom-prod/src/xdrv/wcmCommon.c?view=markup |
| * |
| * The WTI_CURSORS_INFO.TYPE data is supposed to be used like this: |
| * (cursor.TYPE & 0x0F06) == target_cursor_type |
| * Reference: Section Unique ID |
| * http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html |
| */ |
| #define CSR_TYPE_PEN 0x822 |
| #define CSR_TYPE_ERASER 0x82a |
| #define CSR_TYPE_MOUSE_2D 0x007 |
| #define CSR_TYPE_MOUSE_4D 0x094 |
| /* CSR_TYPE_OTHER is a special value! assumed no real world significance |
| * if a stylus type or eraser type eventually have this value |
| * it'll be a bug. As of 2008 05 21 we can be sure because |
| * linux wacom lists all the known values and this isn't one of them */ |
| #define CSR_TYPE_OTHER 0x000 |
| |
| typedef struct tagWTPACKET { |
| HCTX pkContext; |
| UINT pkStatus; |
| LONG pkTime; |
| WTPKT pkChanged; |
| UINT pkSerialNumber; |
| UINT pkCursor; |
| DWORD pkButtons; |
| DWORD pkX; |
| DWORD pkY; |
| DWORD pkZ; |
| UINT pkNormalPressure; |
| UINT pkTangentPressure; |
| ORIENTATION pkOrientation; |
| ROTATION pkRotation; /* 1.1 */ |
| } WTPACKET, *LPWTPACKET; |
| |
| |
| #ifdef SONAME_LIBXI |
| |
| #include <X11/Xlib.h> |
| #include <X11/extensions/XInput.h> |
| |
| static int motion_type; |
| static int button_press_type; |
| static int button_release_type; |
| static int key_press_type; |
| static int key_release_type; |
| static int proximity_in_type; |
| static int proximity_out_type; |
| |
| static HWND hwndTabletDefault; |
| static WTPACKET gMsgPacket; |
| static DWORD gSerial; |
| |
| /* Reference: http://www.wacomeng.com/devsupport/ibmpc/gddevpc.html |
| * |
| * Cursors come in sets of 3 normally |
| * Cursor #0 = puck device 1 |
| * Cursor #1 = stylus device 1 |
| * Cursor #2 = eraser device 1 |
| * Cursor #3 = puck device 2 |
| * Cursor #4 = stylus device 2 |
| * Cursor #5 = eraser device 2 |
| * etc.... |
| * |
| * A dual tracking/multimode tablet is one |
| * that supports 2 independent cursors of the same or |
| * different types simultaneously on a single tablet. |
| * This makes our cursor layout potentially like this |
| * Cursor #0 = puck 1 device 1 |
| * Cursor #1 = stylus 1 device 1 |
| * Cursor #2 = eraser 1 device 1 |
| * Cursor #3 = puck 2 device 1 |
| * Cursor #4 = stylus 2 device 1 |
| * Cursor #5 = eraser 2 device 1 |
| * Cursor #6 = puck 1 device 2 |
| * etc..... |
| * |
| * So with multimode tablets we could potentially need |
| * 2 slots of the same type per tablet i.e. |
| * you are using 2 styluses at once so they would |
| * get placed in Cursors #1 and Cursor #4 |
| * |
| * Now say someone has 2 multimode tablets with 2 erasers each |
| * now we would need Cursor #2, #5, #8, #11 |
| * So to support that we need CURSORMAX of 12 (0 to 11) |
| * FIXME: we don't support more than 4 regular tablets or 2 multimode tablets */ |
| #define CURSORMAX 12 |
| static INT button_state[CURSORMAX]; |
| |
| static LOGCONTEXTW gSysContext; |
| static WTI_DEVICES_INFO gSysDevice; |
| static WTI_CURSORS_INFO gSysCursor[CURSORMAX]; |
| static INT gNumCursors; /* do NOT use this to iterate through gSysCursor slots */ |
| |
| |
| /* XInput stuff */ |
| static void *xinput_handle; |
| |
| #define MAKE_FUNCPTR(f) static typeof(f) * p##f; |
| MAKE_FUNCPTR(XListInputDevices) |
| MAKE_FUNCPTR(XFreeDeviceList) |
| MAKE_FUNCPTR(XOpenDevice) |
| MAKE_FUNCPTR(XQueryDeviceState) |
| MAKE_FUNCPTR(XGetDeviceButtonMapping) |
| MAKE_FUNCPTR(XCloseDevice) |
| MAKE_FUNCPTR(XSelectExtensionEvent) |
| MAKE_FUNCPTR(XFreeDeviceState) |
| #undef MAKE_FUNCPTR |
| |
| static INT X11DRV_XInput_Init(void) |
| { |
| xinput_handle = wine_dlopen(SONAME_LIBXI, RTLD_NOW, NULL, 0); |
| if (xinput_handle) |
| { |
| #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(xinput_handle, #f, NULL, 0)) == NULL) goto sym_not_found; |
| LOAD_FUNCPTR(XListInputDevices) |
| LOAD_FUNCPTR(XFreeDeviceList) |
| LOAD_FUNCPTR(XOpenDevice) |
| LOAD_FUNCPTR(XGetDeviceButtonMapping) |
| LOAD_FUNCPTR(XCloseDevice) |
| LOAD_FUNCPTR(XSelectExtensionEvent) |
| LOAD_FUNCPTR(XQueryDeviceState) |
| LOAD_FUNCPTR(XFreeDeviceState) |
| #undef LOAD_FUNCPTR |
| return 1; |
| } |
| sym_not_found: |
| return 0; |
| } |
| |
| static int Tablet_ErrorHandler(Display *dpy, XErrorEvent *event, void* arg) |
| { |
| return 1; |
| } |
| |
| static void trace_axes(XValuatorInfoPtr val) |
| { |
| int i; |
| XAxisInfoPtr axis; |
| |
| for (i = 0, axis = val->axes ; i < val->num_axes; i++, axis++) |
| TRACE(" Axis %d: [resolution %d|min_value %d|max_value %d]\n", i, axis->resolution, axis->min_value, axis->max_value); |
| } |
| |
| static BOOL match_token(const char *haystack, const char *needle) |
| { |
| const char *p, *q; |
| for (p = haystack; *p; ) |
| { |
| while (*p && isspace(*p)) |
| p++; |
| if (! *p) |
| break; |
| |
| for (q = needle; *q && *p && tolower(*p) == tolower(*q); q++) |
| p++; |
| if (! *q && (isspace(*p) || !*p)) |
| return TRUE; |
| |
| while (*p && ! isspace(*p)) |
| p++; |
| } |
| return FALSE; |
| } |
| |
| /* Determining if an X device is a Tablet style device is an imperfect science. |
| ** We rely on common conventions around device names as well as the type reported |
| ** by Wacom tablets. This code will likely need to be expanded for alternate tablet types |
| ** |
| ** Wintab refers to any device that interacts with the tablet as a cursor, |
| ** (stylus, eraser, tablet mouse, airbrush, etc) |
| ** this is not to be confused with wacom x11 configuration "cursor" device. |
| ** Wacoms x11 config "cursor" refers to its device slot (which we mirror with |
| ** our gSysCursors) for puck like devices (tablet mice essentially). |
| */ |
| |
| static BOOL is_tablet_cursor(const char *name, const char *type) |
| { |
| int i; |
| static const char *tablet_cursor_whitelist[] = { |
| "wacom", |
| "wizardpen", |
| "acecad", |
| "tablet", |
| "cursor", |
| "stylus", |
| "eraser", |
| "pad", |
| NULL |
| }; |
| |
| for (i=0; tablet_cursor_whitelist[i] != NULL; i++) { |
| if (name && match_token(name, tablet_cursor_whitelist[i])) |
| return TRUE; |
| if (type && match_token(type, tablet_cursor_whitelist[i])) |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| static UINT get_cursor_type(const char *name, const char *type) |
| { |
| int i; |
| static const char* tablet_stylus_whitelist[] = { |
| "stylus", |
| "wizardpen", |
| "acecad", |
| "pen", |
| NULL |
| }; |
| |
| /* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */ |
| for (i=0; tablet_stylus_whitelist[i] != NULL; i++) { |
| if (type && match_token(type, tablet_stylus_whitelist[i])) |
| return CSR_TYPE_PEN; |
| } |
| if (type && match_token(type, "eraser")) |
| return CSR_TYPE_ERASER; |
| for (i=0; tablet_stylus_whitelist[i] != NULL; i++) { |
| if (name && match_token(name, tablet_stylus_whitelist[i])) |
| return CSR_TYPE_PEN; |
| } |
| if (name && match_token(name, "eraser")) |
| return CSR_TYPE_ERASER; |
| |
| return CSR_TYPE_OTHER; |
| } |
| |
| /* cursors are placed in gSysCursor rows depending on their type |
| * see CURSORMAX comments for more detail */ |
| static BOOL add_system_cursor(LPWTI_CURSORS_INFO cursor) |
| { |
| UINT offset = 0; |
| |
| if (cursor->TYPE == CSR_TYPE_PEN) |
| offset = 1; |
| else if (cursor->TYPE == CSR_TYPE_ERASER) |
| offset = 2; |
| |
| for (; offset < CURSORMAX; offset += 3) |
| { |
| if (!gSysCursor[offset].ACTIVE) |
| { |
| gSysCursor[offset] = *cursor; |
| ++gNumCursors; |
| return TRUE; |
| } |
| } |
| |
| return FALSE; |
| } |
| |
| static void disable_system_cursors(void) |
| { |
| UINT i; |
| |
| for (i = 0; i < CURSORMAX; ++i) |
| { |
| gSysCursor[i].ACTIVE = 0; |
| } |
| |
| gNumCursors = 0; |
| } |
| |
| |
| /*********************************************************************** |
| * X11DRV_LoadTabletInfo (X11DRV.@) |
| */ |
| BOOL CDECL X11DRV_LoadTabletInfo(HWND hwnddefault) |
| { |
| const WCHAR SZ_CONTEXT_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','C','o','n','t','e','x','t',0}; |
| const WCHAR SZ_DEVICE_NAME[] = {'W','i','n','e',' ','T','a','b','l','e','t',' ','D','e','v','i','c','e',0}; |
| const WCHAR SZ_NON_PLUGINPLAY[] = {'n','o','n','-','p','l','u','g','i','n','p','l','a','y',0}; |
| |
| struct x11drv_thread_data *data = x11drv_init_thread_data(); |
| int num_devices; |
| int loop; |
| XDeviceInfo *devices; |
| XDeviceInfo *target = NULL; |
| BOOL axis_read_complete= FALSE; |
| |
| XAnyClassPtr any; |
| XButtonInfoPtr Button; |
| XValuatorInfoPtr Val; |
| XAxisInfoPtr Axis; |
| |
| XDevice *opendevice; |
| |
| if (!X11DRV_XInput_Init()) |
| { |
| ERR("Unable to initialize the XInput library.\n"); |
| return FALSE; |
| } |
| |
| hwndTabletDefault = hwnddefault; |
| |
| /* Do base initialization */ |
| strcpyW(gSysContext.lcName, SZ_CONTEXT_NAME); |
| strcpyW(gSysDevice.NAME, SZ_DEVICE_NAME); |
| |
| gSysContext.lcOptions = CXO_SYSTEM; |
| gSysContext.lcLocks = CXL_INSIZE | CXL_INASPECT | CXL_MARGIN | |
| CXL_SENSITIVITY | CXL_SYSOUT; |
| |
| gSysContext.lcMsgBase= WT_DEFBASE; |
| gSysContext.lcDevice = 0; |
| gSysContext.lcPktData = |
| PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR | |
| PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION; |
| gSysContext.lcMoveMask= |
| PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION; |
| gSysContext.lcStatus = CXS_ONTOP; |
| gSysContext.lcPktRate = 100; |
| gSysContext.lcBtnDnMask = 0xffffffff; |
| gSysContext.lcBtnUpMask = 0xffffffff; |
| gSysContext.lcSensX = 65536; |
| gSysContext.lcSensY = 65536; |
| gSysContext.lcSensX = 65536; |
| gSysContext.lcSensZ = 65536; |
| gSysContext.lcSysSensX= 65536; |
| gSysContext.lcSysSensY= 65536; |
| gSysContext.lcOutExtX= GetSystemMetrics(SM_CXSCREEN); |
| gSysContext.lcOutExtY= GetSystemMetrics(SM_CYSCREEN); |
| |
| /* initialize cursors */ |
| disable_system_cursors(); |
| |
| /* Device Defaults */ |
| gSysDevice.HARDWARE = HWC_HARDPROX|HWC_PHYSID_CURSORS; |
| gSysDevice.FIRSTCSR= 0; |
| gSysDevice.PKTRATE = 100; |
| gSysDevice.PKTDATA = |
| PK_CONTEXT | PK_STATUS | PK_SERIAL_NUMBER| PK_TIME | PK_CURSOR | |
| PK_BUTTONS | PK_X | PK_Y | PK_NORMAL_PRESSURE | PK_ORIENTATION; |
| strcpyW(gSysDevice.PNPID, SZ_NON_PLUGINPLAY); |
| |
| devices = pXListInputDevices(data->display, &num_devices); |
| if (!devices) |
| { |
| WARN("XInput Extensions reported as not available\n"); |
| return FALSE; |
| } |
| TRACE("XListInputDevices reports %d devices\n", num_devices); |
| for (loop=0; loop < num_devices; loop++) |
| { |
| int class_loop; |
| char *device_type = devices[loop].type ? XGetAtomName(data->display, devices[loop].type) : NULL; |
| WTI_CURSORS_INFO cursor; |
| |
| TRACE("Device %i: [id %d|name %s|type %s|num_classes %d|use %d]\n", |
| loop, (int) devices[loop].id, devices[loop].name, debugstr_a(device_type), |
| devices[loop].num_classes, devices[loop].use ); |
| |
| switch (devices[loop].use) |
| { |
| case IsXExtensionDevice: |
| #ifdef IsXExtensionPointer |
| case IsXExtensionPointer: |
| #endif |
| #ifdef IsXExtensionKeyboard |
| case IsXExtensionKeyboard: |
| #endif |
| TRACE("Is XExtension: Device, Keyboard, or Pointer\n"); |
| target = &devices[loop]; |
| |
| if (strlen(target->name) >= WT_MAX_NAME_LEN) |
| { |
| ERR("Input device '%s' name too long - skipping\n", wine_dbgstr_a(target->name)); |
| break; |
| } |
| |
| X11DRV_expect_error(data->display, Tablet_ErrorHandler, NULL); |
| opendevice = pXOpenDevice(data->display,target->id); |
| if (!X11DRV_check_error() && opendevice) |
| { |
| unsigned char map[32]; |
| int i; |
| int shft = 0; |
| |
| X11DRV_expect_error(data->display,Tablet_ErrorHandler,NULL); |
| cursor.BUTTONS = pXGetDeviceButtonMapping(data->display, opendevice, map, 32); |
| if (X11DRV_check_error() || cursor.BUTTONS <= 0) |
| { |
| TRACE("No buttons, Non Tablet Device\n"); |
| pXCloseDevice(data->display, opendevice); |
| break; |
| } |
| |
| for (i=0; i< cursor.BUTTONS; i++,shft++) |
| { |
| cursor.BUTTONMAP[i] = map[i]; |
| cursor.SYSBTNMAP[i] = (1<<shft); |
| } |
| pXCloseDevice(data->display, opendevice); |
| } |
| else |
| { |
| WARN("Unable to open device %s\n",target->name); |
| break; |
| } |
| MultiByteToWideChar(CP_UNIXCP, 0, target->name, -1, cursor.NAME, WT_MAX_NAME_LEN); |
| |
| if (! is_tablet_cursor(target->name, device_type)) |
| { |
| 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", |
| loop, devices[loop].name, debugstr_a(device_type)); |
| break; |
| } |
| |
| cursor.ACTIVE = 1; |
| cursor.PKTDATA = PK_TIME | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y | |
| PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | |
| PK_ORIENTATION; |
| |
| cursor.PHYSID = target->id; |
| cursor.NPBUTTON = 1; |
| cursor.NPBTNMARKS[0] = 0 ; |
| cursor.NPBTNMARKS[1] = 1 ; |
| cursor.CAPABILITIES = CRC_MULTIMODE; |
| |
| cursor.TYPE = get_cursor_type(target->name, device_type); |
| |
| any = target->inputclassinfo; |
| |
| for (class_loop = 0; class_loop < target->num_classes; class_loop++) |
| { |
| switch (any->class) |
| { |
| |
| case ValuatorClass: |
| Val = (XValuatorInfoPtr) any; |
| TRACE(" ValidatorInput %d: [class %d|length %d|num_axes %d|mode %d|motion_buffer %ld]\n", |
| class_loop, (int) Val->class, Val->length, Val->num_axes, Val->mode, Val->motion_buffer); |
| if (TRACE_ON(wintab32)) |
| trace_axes(Val); |
| |
| /* FIXME: This is imperfect; we compute our devices capabilities based upon the |
| ** first pen type device we find. However, a more correct implementation |
| ** would require acquiring a wide variety of tablets and running through |
| ** the various inputs to see what the values are. Odds are that a |
| ** more 'correct' algorithm would condense to this one anyway. |
| */ |
| if (!axis_read_complete && cursor.TYPE == CSR_TYPE_PEN) |
| { |
| Axis = (XAxisInfoPtr) ((char *) Val + sizeof |
| (XValuatorInfo)); |
| |
| if (Val->num_axes>=1) |
| { |
| /* Axis 1 is X */ |
| gSysDevice.X.axMin = Axis->min_value; |
| gSysDevice.X.axMax= Axis->max_value; |
| gSysDevice.X.axUnits = TU_INCHES; |
| gSysDevice.X.axResolution = Axis->resolution; |
| gSysContext.lcInOrgX = Axis->min_value; |
| gSysContext.lcSysOrgX = Axis->min_value; |
| gSysContext.lcInExtX = Axis->max_value; |
| gSysContext.lcSysExtX = Axis->max_value; |
| Axis++; |
| } |
| if (Val->num_axes>=2) |
| { |
| /* Axis 2 is Y */ |
| gSysDevice.Y.axMin = Axis->min_value; |
| gSysDevice.Y.axMax= Axis->max_value; |
| gSysDevice.Y.axUnits = TU_INCHES; |
| gSysDevice.Y.axResolution = Axis->resolution; |
| gSysContext.lcInOrgY = Axis->min_value; |
| gSysContext.lcSysOrgY = Axis->min_value; |
| gSysContext.lcInExtY = Axis->max_value; |
| gSysContext.lcSysExtY = Axis->max_value; |
| Axis++; |
| } |
| if (Val->num_axes>=3) |
| { |
| /* Axis 3 is Normal Pressure */ |
| gSysDevice.NPRESSURE.axMin = Axis->min_value; |
| gSysDevice.NPRESSURE.axMax= Axis->max_value; |
| gSysDevice.NPRESSURE.axUnits = TU_INCHES; |
| gSysDevice.NPRESSURE.axResolution = |
| Axis->resolution; |
| Axis++; |
| } |
| if (Val->num_axes >= 5) |
| { |
| /* Axis 4 and 5 are X and Y tilt */ |
| XAxisInfoPtr XAxis = Axis; |
| Axis++; |
| if (max (abs(Axis->max_value), |
| abs(XAxis->max_value))) |
| { |
| gSysDevice.ORIENTATION[0].axMin = 0; |
| gSysDevice.ORIENTATION[0].axMax = 3600; |
| gSysDevice.ORIENTATION[0].axUnits = TU_CIRCLE; |
| gSysDevice.ORIENTATION[0].axResolution |
| = CASTFIX32(3600); |
| gSysDevice.ORIENTATION[1].axMin = -1000; |
| gSysDevice.ORIENTATION[1].axMax = 1000; |
| gSysDevice.ORIENTATION[1].axUnits = TU_CIRCLE; |
| gSysDevice.ORIENTATION[1].axResolution |
| = CASTFIX32(3600); |
| Axis++; |
| } |
| } |
| axis_read_complete = TRUE; |
| } |
| break; |
| case ButtonClass: |
| { |
| int cchBuf = 512; |
| int cchPos = 0; |
| int i; |
| |
| Button = (XButtonInfoPtr) any; |
| TRACE(" ButtonInput %d: [class %d|length %d|num_buttons %d]\n", |
| class_loop, (int) Button->class, Button->length, Button->num_buttons); |
| cursor.BTNNAMES = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*cchBuf); |
| for (i = 0; i < cursor.BUTTONS; i++) |
| { |
| /* FIXME - these names are probably incorrect */ |
| int cch = strlenW(cursor.NAME) + 1; |
| while (cch > cchBuf - cchPos - 1) /* we want one extra byte for the last NUL */ |
| { |
| cchBuf *= 2; |
| cursor.BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor.BTNNAMES, sizeof(WCHAR)*cchBuf); |
| } |
| |
| strcpyW(cursor.BTNNAMES + cchPos, cursor.NAME); |
| cchPos += cch; |
| } |
| cursor.BTNNAMES[cchPos++] = 0; |
| cursor.BTNNAMES = HeapReAlloc(GetProcessHeap(), 0, cursor.BTNNAMES, sizeof(WCHAR)*cchPos); |
| cursor.cchBTNNAMES = cchPos; |
| } |
| break; |
| } /* switch any->class */ |
| any = (XAnyClassPtr) ((char*) any + any->length); |
| } /* for class_loop */ |
| if (!add_system_cursor(&cursor)) |
| FIXME("Skipping this cursor due to lack of system cursor slots.\n"); |
| break; |
| } /* switch devices.use */ |
| XFree(device_type); |
| } /* for XListInputDevices */ |
| pXFreeDeviceList(devices); |
| |
| if (axis_read_complete) |
| gSysDevice.NCSRTYPES = gNumCursors; |
| else |
| { |
| disable_system_cursors(); |
| WARN("Did not find a valid stylus, unable to determine system context parameters. Wintab is disabled.\n"); |
| } |
| |
| return TRUE; |
| } |
| |
| static int figure_deg(int x, int y) |
| { |
| float angle; |
| |
| angle = atan2((float)y, (float)x); |
| angle += M_PI_2; |
| if (angle <= 0) |
| angle += 2 * M_PI; |
| |
| return (0.5 + (angle * 1800.0 / M_PI)); |
| } |
| |
| static int get_button_state(int curnum) |
| { |
| return button_state[curnum]; |
| } |
| |
| static void set_button_state(int curnum, XID deviceid) |
| { |
| struct x11drv_thread_data *data = x11drv_thread_data(); |
| XDevice *device; |
| XDeviceState *state; |
| XInputClass *class; |
| int loop; |
| int rc = 0; |
| |
| device = pXOpenDevice(data->display,deviceid); |
| state = pXQueryDeviceState(data->display,device); |
| |
| if (state) |
| { |
| class = state->data; |
| for (loop = 0; loop < state->num_classes; loop++) |
| { |
| if (class->class == ButtonClass) |
| { |
| int loop2; |
| XButtonState *button_state = (XButtonState*)class; |
| for (loop2 = 0; loop2 < button_state->num_buttons; loop2++) |
| { |
| if (button_state->buttons[loop2 / 8] & (1 << (loop2 % 8))) |
| { |
| rc |= (1<<loop2); |
| } |
| } |
| } |
| class = (XInputClass *) ((char *) class + class->length); |
| } |
| } |
| pXFreeDeviceState(state); |
| button_state[curnum] = rc; |
| } |
| |
| static int cursor_from_device(DWORD deviceid, LPWTI_CURSORS_INFO *cursorp) |
| { |
| int i; |
| for (i = 0; i < CURSORMAX; i++) |
| if (gSysCursor[i].ACTIVE && gSysCursor[i].PHYSID == deviceid) |
| { |
| *cursorp = &gSysCursor[i]; |
| return i; |
| } |
| |
| ERR("Could not map device id %d to a cursor\n", (int) deviceid); |
| return -1; |
| } |
| |
| static BOOL motion_event( HWND hwnd, XEvent *event ) |
| { |
| XDeviceMotionEvent *motion = (XDeviceMotionEvent *)event; |
| LPWTI_CURSORS_INFO cursor; |
| int curnum = cursor_from_device(motion->deviceid, &cursor); |
| if (curnum < 0) |
| return FALSE; |
| |
| memset(&gMsgPacket,0,sizeof(WTPACKET)); |
| |
| TRACE("Received tablet motion event (%p); device id %d, cursor num %d\n",hwnd, (int) motion->deviceid, curnum); |
| |
| /* Set cursor to inverted if cursor is the eraser */ |
| gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); |
| gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(motion->time); |
| gMsgPacket.pkSerialNumber = gSerial++; |
| gMsgPacket.pkCursor = curnum; |
| gMsgPacket.pkX = motion->axis_data[0]; |
| gMsgPacket.pkY = motion->axis_data[1]; |
| gMsgPacket.pkOrientation.orAzimuth = figure_deg(motion->axis_data[3],motion->axis_data[4]); |
| gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max |
| (abs(motion->axis_data[3]), |
| abs(motion->axis_data[4]))) |
| * (gMsgPacket.pkStatus & TPS_INVERT?-1:1)); |
| gMsgPacket.pkNormalPressure = motion->axis_data[2]; |
| gMsgPacket.pkButtons = get_button_state(curnum); |
| SendMessageW(hwndTabletDefault,WT_PACKET,gMsgPacket.pkSerialNumber,(LPARAM)hwnd); |
| return TRUE; |
| } |
| |
| static BOOL button_event( HWND hwnd, XEvent *event ) |
| { |
| XDeviceButtonEvent *button = (XDeviceButtonEvent *) event; |
| LPWTI_CURSORS_INFO cursor; |
| int curnum = cursor_from_device(button->deviceid, &cursor); |
| if (curnum < 0) |
| return FALSE; |
| |
| memset(&gMsgPacket,0,sizeof(WTPACKET)); |
| |
| TRACE("Received tablet button %s event\n", (event->type == button_press_type)?"press":"release"); |
| |
| /* Set cursor to inverted if cursor is the eraser */ |
| gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); |
| set_button_state(curnum, button->deviceid); |
| gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(button->time); |
| gMsgPacket.pkSerialNumber = gSerial++; |
| gMsgPacket.pkCursor = curnum; |
| gMsgPacket.pkX = button->axis_data[0]; |
| gMsgPacket.pkY = button->axis_data[1]; |
| gMsgPacket.pkOrientation.orAzimuth = figure_deg(button->axis_data[3],button->axis_data[4]); |
| gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(button->axis_data[3]), |
| abs(button->axis_data[4]))) |
| * (gMsgPacket.pkStatus & TPS_INVERT?-1:1)); |
| gMsgPacket.pkNormalPressure = button->axis_data[2]; |
| gMsgPacket.pkButtons = get_button_state(curnum); |
| SendMessageW(hwndTabletDefault,WT_PACKET,gMsgPacket.pkSerialNumber,(LPARAM)hwnd); |
| return TRUE; |
| } |
| |
| static BOOL key_event( HWND hwnd, XEvent *event ) |
| { |
| if (event->type == key_press_type) |
| FIXME("Received tablet key press event\n"); |
| else |
| FIXME("Received tablet key release event\n"); |
| return FALSE; |
| } |
| |
| static BOOL proximity_event( HWND hwnd, XEvent *event ) |
| { |
| XProximityNotifyEvent *proximity = (XProximityNotifyEvent *) event; |
| LPWTI_CURSORS_INFO cursor; |
| int curnum = cursor_from_device(proximity->deviceid, &cursor); |
| LPARAM proximity_info; |
| |
| TRACE("hwnd=%p\n", hwnd); |
| |
| if (curnum < 0) |
| return FALSE; |
| |
| memset(&gMsgPacket,0,sizeof(WTPACKET)); |
| |
| /* Set cursor to inverted if cursor is the eraser */ |
| gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); |
| gMsgPacket.pkStatus |= (event->type==proximity_out_type)?TPS_PROXIMITY:0; |
| gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(proximity->time); |
| gMsgPacket.pkSerialNumber = gSerial++; |
| gMsgPacket.pkCursor = curnum; |
| gMsgPacket.pkX = proximity->axis_data[0]; |
| gMsgPacket.pkY = proximity->axis_data[1]; |
| gMsgPacket.pkOrientation.orAzimuth = figure_deg(proximity->axis_data[3],proximity->axis_data[4]); |
| gMsgPacket.pkOrientation.orAltitude = ((1000 - 15 * max(abs(proximity->axis_data[3]), |
| abs(proximity->axis_data[4]))) |
| * (gMsgPacket.pkStatus & TPS_INVERT?-1:1)); |
| gMsgPacket.pkNormalPressure = proximity->axis_data[2]; |
| gMsgPacket.pkButtons = get_button_state(curnum); |
| |
| /* FIXME: LPARAM loword is true when cursor entering context, false when leaving context |
| * This needs to be handled here or in wintab32. Using the proximity_in_type is not correct |
| * but kept for now. |
| * LPARAM hiword is "non-zero when the cursor is leaving or entering hardware proximity" |
| * WPARAM contains context handle. |
| * HWND to HCTX is handled by wintab32. |
| */ |
| proximity_info = MAKELPARAM((event->type == proximity_in_type), |
| (event->type == proximity_in_type) || (event->type == proximity_out_type)); |
| SendMessageW(hwndTabletDefault, WT_PROXIMITY, (WPARAM)hwnd, proximity_info); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * X11DRV_AttachEventQueueToTablet (X11DRV.@) |
| */ |
| int CDECL X11DRV_AttachEventQueueToTablet(HWND hOwner) |
| { |
| struct x11drv_thread_data *data = x11drv_init_thread_data(); |
| int num_devices; |
| int loop; |
| int cur_loop; |
| XDeviceInfo *devices; |
| XDeviceInfo *target = NULL; |
| XDevice *the_device; |
| XEventClass event_list[7]; |
| Window win = X11DRV_get_whole_window( hOwner ); |
| |
| if (!win || !xinput_handle) return 0; |
| |
| TRACE("Creating context for window %p (%lx) %i cursors\n", hOwner, win, gNumCursors); |
| |
| devices = pXListInputDevices(data->display, &num_devices); |
| |
| X11DRV_expect_error(data->display,Tablet_ErrorHandler,NULL); |
| for (cur_loop=0; cur_loop < CURSORMAX; cur_loop++) |
| { |
| char cursorNameA[WT_MAX_NAME_LEN]; |
| int event_number=0; |
| |
| if (!gSysCursor[cur_loop].ACTIVE) continue; |
| |
| /* the cursor name fits in the buffer because too long names are skipped */ |
| WideCharToMultiByte(CP_UNIXCP, 0, gSysCursor[cur_loop].NAME, -1, cursorNameA, WT_MAX_NAME_LEN, NULL, NULL); |
| for (loop=0; loop < num_devices; loop ++) |
| if (strcmp(devices[loop].name, cursorNameA) == 0) |
| target = &devices[loop]; |
| if (!target) { |
| WARN("Cursor Name %s not found in list of targets.\n", cursorNameA); |
| continue; |
| } |
| |
| TRACE("Opening cursor %i id %i\n",cur_loop,(INT)target->id); |
| |
| the_device = pXOpenDevice(data->display, target->id); |
| |
| if (!the_device) |
| { |
| WARN("Unable to Open device\n"); |
| continue; |
| } |
| |
| if (the_device->num_classes > 0) |
| { |
| DeviceKeyPress(the_device, key_press_type, event_list[event_number]); |
| if (key_press_type) event_number++; |
| DeviceKeyRelease(the_device, key_release_type, event_list[event_number]); |
| if (key_release_type) event_number++; |
| DeviceButtonPress(the_device, button_press_type, event_list[event_number]); |
| if (button_press_type) event_number++; |
| DeviceButtonRelease(the_device, button_release_type, event_list[event_number]); |
| if (button_release_type) event_number++; |
| DeviceMotionNotify(the_device, motion_type, event_list[event_number]); |
| if (motion_type) event_number++; |
| ProximityIn(the_device, proximity_in_type, event_list[event_number]); |
| if (proximity_in_type) event_number++; |
| ProximityOut(the_device, proximity_out_type, event_list[event_number]); |
| if (proximity_out_type) event_number++; |
| |
| if (key_press_type) |
| X11DRV_register_event_handler( key_press_type, key_event, "XInput KeyPress" ); |
| if (key_release_type) |
| X11DRV_register_event_handler( key_release_type, key_event, "XInput KeyRelease" ); |
| if (button_press_type) |
| X11DRV_register_event_handler( button_press_type, button_event, "XInput ButtonPress" ); |
| if (button_release_type) |
| X11DRV_register_event_handler( button_release_type, button_event, "XInput ButtonRelease" ); |
| if (motion_type) |
| X11DRV_register_event_handler( motion_type, motion_event, "XInput MotionNotify" ); |
| if (proximity_in_type) |
| X11DRV_register_event_handler( proximity_in_type, proximity_event, "XInput ProximityIn" ); |
| if (proximity_out_type) |
| X11DRV_register_event_handler( proximity_out_type, proximity_event, "XInput ProximityOut" ); |
| |
| pXSelectExtensionEvent(data->display, win, event_list, event_number); |
| } |
| } |
| XSync(data->display, False); |
| X11DRV_check_error(); |
| |
| if (NULL != devices) pXFreeDeviceList(devices); |
| return 0; |
| } |
| |
| /*********************************************************************** |
| * X11DRV_GetCurrentPacket (X11DRV.@) |
| */ |
| int CDECL X11DRV_GetCurrentPacket(LPWTPACKET packet) |
| { |
| *packet = gMsgPacket; |
| return 1; |
| } |
| |
| |
| static inline int CopyTabletData(LPVOID target, LPCVOID src, INT size) |
| { |
| /* |
| * It is valid to call CopyTabletData with NULL. |
| * This handles the WTInfo() case where lpOutput is null. |
| */ |
| if(target != NULL) |
| memcpy(target,src,size); |
| return(size); |
| } |
| |
| /*********************************************************************** |
| * X11DRV_WTInfoW (X11DRV.@) |
| */ |
| UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) |
| { |
| /* |
| * It is valid to call WTInfoA with lpOutput == NULL, as per standard. |
| * lpOutput == NULL signifies the user only wishes |
| * to find the size of the data. |
| * NOTE: |
| * From now on use CopyTabletData to fill lpOutput. memcpy will break |
| * the code. |
| */ |
| int rc = 0; |
| LPWTI_CURSORS_INFO tgtcursor; |
| TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput); |
| |
| if (!xinput_handle) return 0; |
| |
| switch(wCategory) |
| { |
| case 0: |
| /* return largest necessary buffer */ |
| TRACE("%i cursors\n",gNumCursors); |
| if (gNumCursors>0) |
| { |
| FIXME("Return proper size\n"); |
| rc = 200; |
| } |
| break; |
| case WTI_INTERFACE: |
| switch (nIndex) |
| { |
| WORD version; |
| UINT num; |
| case IFC_WINTABID: |
| { |
| static const WCHAR driver[] = {'W','i','n','e',' ','W','i','n','t','a','b',' ','1','.','1',0}; |
| rc = CopyTabletData(lpOutput, driver, (strlenW(driver) + 1) * sizeof(WCHAR)); |
| break; |
| } |
| case IFC_SPECVERSION: |
| version = (0x01) | (0x01 << 8); |
| rc = CopyTabletData(lpOutput, &version,sizeof(WORD)); |
| break; |
| case IFC_IMPLVERSION: |
| version = (0x00) | (0x01 << 8); |
| rc = CopyTabletData(lpOutput, &version,sizeof(WORD)); |
| break; |
| case IFC_NDEVICES: |
| num = 1; |
| rc = CopyTabletData(lpOutput, &num,sizeof(num)); |
| break; |
| case IFC_NCURSORS: |
| num = gNumCursors; |
| rc = CopyTabletData(lpOutput, &num,sizeof(num)); |
| break; |
| default: |
| FIXME("WTI_INTERFACE unhandled index %i\n",nIndex); |
| rc = 0; |
| } |
| break; |
| case WTI_DEFSYSCTX: |
| case WTI_DDCTXS: |
| case WTI_DEFCONTEXT: |
| switch (nIndex) |
| { |
| case 0: |
| /* report 0 if wintab is disabled */ |
| if (0 == gNumCursors) |
| rc = 0; |
| else |
| rc = CopyTabletData(lpOutput, &gSysContext, |
| sizeof(LOGCONTEXTW)); |
| break; |
| case CTX_NAME: |
| rc = CopyTabletData(lpOutput, gSysContext.lcName, |
| (strlenW(gSysContext.lcName)+1) * sizeof(WCHAR)); |
| break; |
| case CTX_OPTIONS: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOptions, |
| sizeof(UINT)); |
| break; |
| case CTX_STATUS: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcStatus, |
| sizeof(UINT)); |
| break; |
| case CTX_LOCKS: |
| rc= CopyTabletData (lpOutput, &gSysContext.lcLocks, |
| sizeof(UINT)); |
| break; |
| case CTX_MSGBASE: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcMsgBase, |
| sizeof(UINT)); |
| break; |
| case CTX_DEVICE: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcDevice, |
| sizeof(UINT)); |
| break; |
| case CTX_PKTRATE: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcPktRate, |
| sizeof(UINT)); |
| break; |
| case CTX_PKTDATA: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcPktData, |
| sizeof(WTPKT)); |
| break; |
| case CTX_PKTMODE: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcPktMode, |
| sizeof(WTPKT)); |
| break; |
| case CTX_MOVEMASK: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcMoveMask, |
| sizeof(WTPKT)); |
| break; |
| case CTX_BTNDNMASK: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcBtnDnMask, |
| sizeof(DWORD)); |
| break; |
| case CTX_BTNUPMASK: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcBtnUpMask, |
| sizeof(DWORD)); |
| break; |
| case CTX_INORGX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgX, |
| sizeof(LONG)); |
| break; |
| case CTX_INORGY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgY, |
| sizeof(LONG)); |
| break; |
| case CTX_INORGZ: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInOrgZ, |
| sizeof(LONG)); |
| break; |
| case CTX_INEXTX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInExtX, |
| sizeof(LONG)); |
| break; |
| case CTX_INEXTY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInExtY, |
| sizeof(LONG)); |
| break; |
| case CTX_INEXTZ: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcInExtZ, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTORGX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgX, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTORGY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgY, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTORGZ: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutOrgZ, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTEXTX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtX, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTEXTY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtY, |
| sizeof(LONG)); |
| break; |
| case CTX_OUTEXTZ: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcOutExtZ, |
| sizeof(LONG)); |
| break; |
| case CTX_SENSX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSensX, |
| sizeof(LONG)); |
| break; |
| case CTX_SENSY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSensY, |
| sizeof(LONG)); |
| break; |
| case CTX_SENSZ: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSensZ, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSMODE: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysMode, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSORGX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgX, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSORGY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysOrgY, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSEXTX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtX, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSEXTY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysExtY, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSSENSX: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensX, |
| sizeof(LONG)); |
| break; |
| case CTX_SYSSENSY: |
| rc = CopyTabletData(lpOutput, &gSysContext.lcSysSensY, |
| sizeof(LONG)); |
| break; |
| default: |
| FIXME("WTI_DEFSYSCTX unhandled index %i\n",nIndex); |
| rc = 0; |
| } |
| break; |
| case WTI_CURSORS: |
| case WTI_CURSORS+1: |
| case WTI_CURSORS+2: |
| case WTI_CURSORS+3: |
| case WTI_CURSORS+4: |
| case WTI_CURSORS+5: |
| case WTI_CURSORS+6: |
| case WTI_CURSORS+7: |
| case WTI_CURSORS+8: |
| case WTI_CURSORS+9: |
| case WTI_CURSORS+10: |
| case WTI_CURSORS+11: |
| /* CURSORMAX == 12 */ |
| /* FIXME: dynamic cursor support */ |
| /* Apps will poll different slots to detect what cursors are available |
| * if there isn't a cursor for this slot return 0 */ |
| if (!gSysCursor[wCategory - WTI_CURSORS].ACTIVE) |
| rc = 0; |
| else |
| { |
| tgtcursor = &gSysCursor[wCategory - WTI_CURSORS]; |
| switch (nIndex) |
| { |
| case CSR_NAME: |
| rc = CopyTabletData(lpOutput, tgtcursor->NAME, |
| (strlenW(tgtcursor->NAME)+1) * sizeof(WCHAR)); |
| break; |
| case CSR_ACTIVE: |
| rc = CopyTabletData(lpOutput,&tgtcursor->ACTIVE, |
| sizeof(BOOL)); |
| break; |
| case CSR_PKTDATA: |
| rc = CopyTabletData(lpOutput,&tgtcursor->PKTDATA, |
| sizeof(WTPKT)); |
| break; |
| case CSR_BUTTONS: |
| rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONS, |
| sizeof(BYTE)); |
| break; |
| case CSR_BUTTONBITS: |
| rc = CopyTabletData(lpOutput,&tgtcursor->BUTTONBITS, |
| sizeof(BYTE)); |
| break; |
| case CSR_BTNNAMES: |
| FIXME("Button Names not returned correctly\n"); |
| rc = CopyTabletData(lpOutput,&tgtcursor->BTNNAMES, |
| tgtcursor->cchBTNNAMES*sizeof(WCHAR)); |
| break; |
| case CSR_BUTTONMAP: |
| rc = CopyTabletData(lpOutput,tgtcursor->BUTTONMAP, |
| sizeof(BYTE)*32); |
| break; |
| case CSR_SYSBTNMAP: |
| rc = CopyTabletData(lpOutput,tgtcursor->SYSBTNMAP, |
| sizeof(BYTE)*32); |
| break; |
| case CSR_NPBTNMARKS: |
| rc = CopyTabletData(lpOutput,tgtcursor->NPBTNMARKS, |
| sizeof(UINT)*2); |
| break; |
| case CSR_NPBUTTON: |
| rc = CopyTabletData(lpOutput,&tgtcursor->NPBUTTON, |
| sizeof(BYTE)); |
| break; |
| case CSR_NPRESPONSE: |
| FIXME("Not returning CSR_NPRESPONSE correctly\n"); |
| rc = 0; |
| break; |
| case CSR_TPBUTTON: |
| rc = CopyTabletData(lpOutput,&tgtcursor->TPBUTTON, |
| sizeof(BYTE)); |
| break; |
| case CSR_TPBTNMARKS: |
| rc = CopyTabletData(lpOutput,tgtcursor->TPBTNMARKS, |
| sizeof(UINT)*2); |
| break; |
| case CSR_TPRESPONSE: |
| FIXME("Not returning CSR_TPRESPONSE correctly\n"); |
| rc = 0; |
| break; |
| case CSR_PHYSID: |
| { |
| DWORD id; |
| id = tgtcursor->PHYSID; |
| rc = CopyTabletData(lpOutput,&id,sizeof(DWORD)); |
| } |
| break; |
| case CSR_MODE: |
| rc = CopyTabletData(lpOutput,&tgtcursor->MODE,sizeof(UINT)); |
| break; |
| case CSR_MINPKTDATA: |
| rc = CopyTabletData(lpOutput,&tgtcursor->MINPKTDATA, |
| sizeof(UINT)); |
| break; |
| case CSR_MINBUTTONS: |
| rc = CopyTabletData(lpOutput,&tgtcursor->MINBUTTONS, |
| sizeof(UINT)); |
| break; |
| case CSR_CAPABILITIES: |
| rc = CopyTabletData(lpOutput,&tgtcursor->CAPABILITIES, |
| sizeof(UINT)); |
| break; |
| case CSR_TYPE: |
| rc = CopyTabletData(lpOutput,&tgtcursor->TYPE, |
| sizeof(UINT)); |
| break; |
| default: |
| FIXME("WTI_CURSORS unhandled index %i\n",nIndex); |
| rc = 0; |
| } |
| } |
| break; |
| case WTI_DEVICES: |
| switch (nIndex) |
| { |
| case DVC_NAME: |
| rc = CopyTabletData(lpOutput,gSysDevice.NAME, |
| (strlenW(gSysDevice.NAME)+1) * sizeof(WCHAR)); |
| break; |
| case DVC_HARDWARE: |
| rc = CopyTabletData(lpOutput,&gSysDevice.HARDWARE, |
| sizeof(UINT)); |
| break; |
| case DVC_NCSRTYPES: |
| rc = CopyTabletData(lpOutput,&gSysDevice.NCSRTYPES, |
| sizeof(UINT)); |
| break; |
| case DVC_FIRSTCSR: |
| rc = CopyTabletData(lpOutput,&gSysDevice.FIRSTCSR, |
| sizeof(UINT)); |
| break; |
| case DVC_PKTRATE: |
| rc = CopyTabletData(lpOutput,&gSysDevice.PKTRATE, |
| sizeof(UINT)); |
| break; |
| case DVC_PKTDATA: |
| rc = CopyTabletData(lpOutput,&gSysDevice.PKTDATA, |
| sizeof(WTPKT)); |
| break; |
| case DVC_PKTMODE: |
| rc = CopyTabletData(lpOutput,&gSysDevice.PKTMODE, |
| sizeof(WTPKT)); |
| break; |
| case DVC_CSRDATA: |
| rc = CopyTabletData(lpOutput,&gSysDevice.CSRDATA, |
| sizeof(WTPKT)); |
| break; |
| case DVC_XMARGIN: |
| rc = CopyTabletData(lpOutput,&gSysDevice.XMARGIN, |
| sizeof(INT)); |
| break; |
| case DVC_YMARGIN: |
| rc = CopyTabletData(lpOutput,&gSysDevice.YMARGIN, |
| sizeof(INT)); |
| break; |
| case DVC_ZMARGIN: |
| rc = 0; /* unsupported */ |
| /* |
| rc = CopyTabletData(lpOutput,&gSysDevice.ZMARGIN, |
| sizeof(INT)); |
| */ |
| break; |
| case DVC_X: |
| rc = CopyTabletData(lpOutput,&gSysDevice.X, |
| sizeof(AXIS)); |
| break; |
| case DVC_Y: |
| rc = CopyTabletData(lpOutput,&gSysDevice.Y, |
| sizeof(AXIS)); |
| break; |
| case DVC_Z: |
| rc = 0; /* unsupported */ |
| /* |
| rc = CopyTabletData(lpOutput,&gSysDevice.Z, |
| sizeof(AXIS)); |
| */ |
| break; |
| case DVC_NPRESSURE: |
| rc = CopyTabletData(lpOutput,&gSysDevice.NPRESSURE, |
| sizeof(AXIS)); |
| break; |
| case DVC_TPRESSURE: |
| rc = 0; /* unsupported */ |
| /* |
| rc = CopyTabletData(lpOutput,&gSysDevice.TPRESSURE, |
| sizeof(AXIS)); |
| */ |
| break; |
| case DVC_ORIENTATION: |
| rc = CopyTabletData(lpOutput,gSysDevice.ORIENTATION, |
| sizeof(AXIS)*3); |
| break; |
| case DVC_ROTATION: |
| rc = 0; /* unsupported */ |
| /* |
| rc = CopyTabletData(lpOutput,&gSysDevice.ROTATION, |
| sizeof(AXIS)*3); |
| */ |
| break; |
| case DVC_PNPID: |
| rc = CopyTabletData(lpOutput,gSysDevice.PNPID, |
| (strlenW(gSysDevice.PNPID)+1)*sizeof(WCHAR)); |
| break; |
| default: |
| FIXME("WTI_DEVICES unhandled index %i\n",nIndex); |
| rc = 0; |
| } |
| break; |
| default: |
| FIXME("Unhandled Category %i\n",wCategory); |
| } |
| return rc; |
| } |
| |
| #else /* SONAME_LIBXI */ |
| |
| /*********************************************************************** |
| * AttachEventQueueToTablet (X11DRV.@) |
| */ |
| int CDECL X11DRV_AttachEventQueueToTablet(HWND hOwner) |
| { |
| return 0; |
| } |
| |
| /*********************************************************************** |
| * GetCurrentPacket (X11DRV.@) |
| */ |
| int CDECL X11DRV_GetCurrentPacket(LPWTPACKET packet) |
| { |
| return 0; |
| } |
| |
| /*********************************************************************** |
| * LoadTabletInfo (X11DRV.@) |
| */ |
| BOOL CDECL X11DRV_LoadTabletInfo(HWND hwnddefault) |
| { |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * WTInfoW (X11DRV.@) |
| */ |
| UINT CDECL X11DRV_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) |
| { |
| return 0; |
| } |
| |
| #endif /* SONAME_LIBXI */ |