Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Splitting into smaller patches as per feedback.
This is the largest of the split patches, but unless "segfaults" or "doesn't compile" is acceptable patch behavior, I can't split it any further.
If it's any help, this file looks very similar to winex11.drv/wintab.c. --- dlls/winemac.drv/cocoa_wintab.h | 17 ++ dlls/winemac.drv/wintab.c | 410 +++++++++++++++++++++++++++++++- 2 files changed, 426 insertions(+), 1 deletion(-)
diff --git a/dlls/winemac.drv/cocoa_wintab.h b/dlls/winemac.drv/cocoa_wintab.h index 0fa20f6752c..1b9867c9d34 100644 --- a/dlls/winemac.drv/cocoa_wintab.h +++ b/dlls/winemac.drv/cocoa_wintab.h @@ -21,12 +21,29 @@ #ifndef __WINE_MACDRV_COCOA_WINTAB_H #define __WINE_MACDRV_COCOA_WINTAB_H
+#include <math.h> + #include "windef.h" #include "wintab.h"
/* Extents that shouldn't cause math problems */ #define TABLET_WIDTH 0x40000000 #define TABLET_HEIGHT 0x40000000 +/* Largest reportable pressure value */ +#define MAX_PRESSURE 0x7fff +/* Wacom's demo app teaches developers to assume 1/10th degree. + * Best stick to that. */ +#define ANGLE_SCALE 10 +/* Largest reportable angle (360 is included, due to rounding) */ +#define MAX_ANGLE (360 * ANGLE_SCALE) + +#define MAKE_ANGLE_DEG(degrees) ((degrees) * ANGLE_SCALE) +#define MAKE_ANGLE_RAD(radians) ((radians) * MAKE_ANGLE_DEG(180) / M_PI) + +/* Cursor indices */ +#define MACDRV_CURSOR_PEN 0 +#define MACDRV_CURSOR_ERASER 1 +#define MACDRV_CURSOR_CURSOR 2
/* Shared device context */ extern LOGCONTEXTW macdrv_tablet_ctx DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/wintab.c b/dlls/winemac.drv/wintab.c index fffae85f735..bd6d6b783e0 100644 --- a/dlls/winemac.drv/wintab.c +++ b/dlls/winemac.drv/wintab.c @@ -43,6 +43,29 @@ static size_t registered_hwnd_count = 0; static size_t registered_hwnd_cap = 0; static HWND* registered_hwnd = NULL;
+static const WCHAR CURSOR_NAME_PEN[] = {'P','r','e','s','s','u','r','e',' ','S','t','y','l','u','s',0}; +static const WCHAR CURSOR_NAME_ERASER[] = {'E','r','a','s','e','r',0}; +static const WCHAR CURSOR_NAME_CURSOR[] = {'P','u','c','k',0}; + +static const UINT CURSOR_COUNT = 3; +static const WCHAR* const CURSOR_NAMES[CURSOR_COUNT] = { + CURSOR_NAME_PEN, + CURSOR_NAME_ERASER, + CURSOR_NAME_CURSOR +}; + +static const UINT CURSOR_TYPES[CURSOR_COUNT] = { + CSR_TYPE_PEN, + CSR_TYPE_ERASER, + CSR_TYPE_MOUSE_2D +}; + +static const UINT CURSOR_CAPABILITIES[CURSOR_COUNT] = { + CRC_MULTIMODE | CRC_AGGREGATE, + CRC_MULTIMODE | CRC_AGGREGATE | CRC_INVERT, + CRC_AGGREGATE +}; + static const BYTE BUTTON_COUNT = 16;
BOOL CDECL macdrv_LoadTabletInfo(HWND tablet_hwnd) @@ -125,7 +148,392 @@ BOOL CDECL macdrv_LoadTabletInfo(HWND tablet_hwnd) UINT CDECL macdrv_WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput) { TRACE("(%u, %u, %p)\n", wCategory, nIndex, lpOutput); - FIXME("Unhandled Category %i\n", wCategory); + + if (IS_WTI_EXTENSIONS_TYPE(wCategory)) + { + FIXME("WTI_EXTENSIONS unimplemented"); + return 0; + } + else if (IS_WTI_CURSORS_TYPE(wCategory)) + { + INT cursor_idx = wCategory - WTI_CURSORS; + if (cursor_idx < 0) + cursor_idx += CURSOR_COUNT; + if (cursor_idx < 0 || cursor_idx >= CURSOR_COUNT) + return 0; + switch (nIndex) + { + case CSR_NAME: + return TABLET_CopyData(lpOutput, CURSOR_NAMES[cursor_idx], (strlenW(CURSOR_NAMES[cursor_idx]) + 1) * sizeof(WCHAR)); + case CSR_ACTIVE: + { + BOOL active = 1; + return TABLET_CopyData(lpOutput, &active, sizeof(active)); + } + case CSR_PKTDATA: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktData, sizeof(macdrv_tablet_ctx.lcPktData)); + case CSR_BUTTONS: + case CSR_BUTTONBITS: + return TABLET_CopyData(lpOutput, &BUTTON_COUNT, sizeof(BUTTON_COUNT)); + case CSR_BTNNAMES: + { + static const char* const fmt = "button %d"; + static char buffer[10]; + int out_size = 0; + PWCHAR out_char = lpOutput; + int button; + + /* Each button name is \0-terminated, with an extra \0 at the + * end. */ + for (button = 0; button < BUTTON_COUNT; button++) + { + int name_len; + + snprintf(buffer, sizeof(buffer), fmt, button); + name_len = strlen(buffer); + + out_size += name_len + 1; + if (out_char != NULL) + { + int c; + for(c = 0; c <= name_len; c++) + *(out_char++) = buffer[c]; + } + } + if (out_char != NULL) + *out_char = 0; + return (out_size + 1) * sizeof(WCHAR); + } + case CSR_BUTTONMAP: + case CSR_SYSBTNMAP: + { + PBYTE out_byte = lpOutput; + int b; + + if (out_byte != NULL) + { + /* Always use 1:1 mapping */ + for (b = 0; b < BUTTON_COUNT; b++) + out_byte[b] = b; + } + return BUTTON_COUNT * sizeof(BYTE); + } + case CSR_NPBUTTON: + case CSR_TPBUTTON: + { + BYTE button = 0; + return TABLET_CopyData(lpOutput, &button, sizeof(button)); + } + case CSR_NPBTNMARKS: + case CSR_TPBTNMARKS: + { + static const UINT marks[] = {0, 1}; + return TABLET_CopyData(lpOutput, &marks, sizeof(marks)); + } + case CSR_NPRESPONSE: + case CSR_TPRESPONSE: + { + static const int POINT_COUNT = 256; + PUINT out_uint = lpOutput; + int p; + + if (out_uint != NULL) + { + /* Linear response */ + for (p = 0; p < POINT_COUNT; p++) + out_uint[p] = MAX_PRESSURE * p / POINT_COUNT; + } + return POINT_COUNT * sizeof(UINT); + } + case CSR_PHYSID: + { + DWORD physid = 0xdeadbeef; + return TABLET_CopyData(lpOutput, &physid, sizeof(physid)); + } + case CSR_MODE: + { + UINT mode = (UINT)cursor_idx; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_MULTIMODE)) + return 0; + return TABLET_CopyData(lpOutput, &mode, sizeof(mode)); + } + case CSR_MINPKTDATA: + { + /* Should be safe to assume all tablets support these */ + UINT pktdata = PK_CONTEXT | PK_STATUS | PK_TIME | PK_CHANGED + | PK_SERIAL_NUMBER | PK_CURSOR | PK_BUTTONS | PK_X | PK_Y + | PK_NORMAL_PRESSURE; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_AGGREGATE)) + return 0; + return TABLET_CopyData(lpOutput, &pktdata, sizeof(pktdata)); + } + case CSR_MINBUTTONS: + { + UINT minbuttons = 1; + if (!(CURSOR_CAPABILITIES[cursor_idx] & CRC_AGGREGATE)) + return 0; + return TABLET_CopyData(lpOutput, &minbuttons, sizeof(minbuttons)); + } + case CSR_CAPABILITIES: + return TABLET_CopyData(lpOutput, CURSOR_CAPABILITIES + cursor_idx, sizeof(*CURSOR_CAPABILITIES)); + case CSR_TYPE: + return TABLET_CopyData(lpOutput, CURSOR_TYPES + cursor_idx, sizeof(*CURSOR_TYPES)); + default: + FIXME("WTI_CURSORS+%d unhandled index %i\n", cursor_idx, nIndex); + return 0; + } + } + + /* Non-indexed categories */ + switch (wCategory) + { + case 0: + /* Largest buffer necessary for any category. This is currently + * WTI_CURSORS :: CSR_NPRESPONSE (or CSR_TPRESPONSE). */ + return 256 * sizeof(UINT); + case WTI_INTERFACE: + switch (nIndex) + { + case IFC_WINTABID: + { + static const WCHAR name[] = {'M','a','c','d','r','v',' ','W','i','n','t','a','b',' ','1','.','1',0}; + return TABLET_CopyData(lpOutput, name, sizeof(name)); + } + case IFC_SPECVERSION: + { + static const WORD version = (0x01) | (0x01 << 8); + return TABLET_CopyData(lpOutput, &version, sizeof(version)); + } + case IFC_IMPLVERSION: + { + static const WORD version = (0x00) | (0x01 << 8); + return TABLET_CopyData(lpOutput, &version, sizeof(version)); + } + case IFC_NDEVICES: + { + static const UINT num = 1; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + case IFC_NCURSORS: + { + return TABLET_CopyData(lpOutput, &CURSOR_COUNT, sizeof(CURSOR_COUNT)); + } + case IFC_NCONTEXTS: + { + static const UINT num = 1; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + default: + FIXME("WTI_INTERFACE unhandled index %i\n", nIndex); + return 0; + } + break; + case WTI_DEFCONTEXT: + case WTI_DEFSYSCTX: + case WTI_DDCTXS: + case WTI_DDCTXS - 1: + case WTI_DSCTXS: + case WTI_DSCTXS - 1: + { + BOOL is_sys = (wCategory == WTI_DEFSYSCTX || wCategory == WTI_DSCTXS || wCategory == WTI_DSCTXS - 1); + LPLOGCONTEXTW active_ctx = (is_sys ? &macdrv_system_ctx : &macdrv_tablet_ctx); + switch (nIndex) + { + case 0: + return TABLET_CopyData(lpOutput, active_ctx, sizeof(*active_ctx)); + case CTX_NAME: + return TABLET_CopyData(lpOutput, active_ctx->lcName, (strlenW(active_ctx->lcName) + 1) * sizeof(WCHAR)); + case CTX_OPTIONS: + return TABLET_CopyData(lpOutput, &active_ctx->lcOptions, sizeof(active_ctx->lcOptions)); + case CTX_STATUS: + return TABLET_CopyData(lpOutput, &active_ctx->lcStatus, sizeof(active_ctx->lcStatus)); + case CTX_LOCKS: + return TABLET_CopyData(lpOutput, &active_ctx->lcLocks, sizeof(active_ctx->lcLocks)); + case CTX_MSGBASE: + return TABLET_CopyData(lpOutput, &active_ctx->lcMsgBase, sizeof(active_ctx->lcMsgBase)); + case CTX_DEVICE: + return TABLET_CopyData(lpOutput, &active_ctx->lcDevice, sizeof(active_ctx->lcDevice)); + case CTX_PKTRATE: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktRate, sizeof(active_ctx->lcPktRate)); + case CTX_PKTDATA: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktData, sizeof(active_ctx->lcPktData)); + case CTX_PKTMODE: + return TABLET_CopyData(lpOutput, &active_ctx->lcPktMode, sizeof(active_ctx->lcPktMode)); + case CTX_MOVEMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcMoveMask, sizeof(active_ctx->lcMoveMask)); + case CTX_BTNDNMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcBtnDnMask, sizeof(active_ctx->lcBtnDnMask)); + case CTX_BTNUPMASK: + return TABLET_CopyData(lpOutput, &active_ctx->lcBtnUpMask, sizeof(active_ctx->lcBtnUpMask)); + case CTX_INORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgX, sizeof(active_ctx->lcInOrgX)); + case CTX_INORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgY, sizeof(active_ctx->lcInOrgY)); + case CTX_INORGZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcInOrgZ, sizeof(active_ctx->lcInOrgZ)); + case CTX_INEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtX, sizeof(active_ctx->lcInExtX)); + case CTX_INEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtY, sizeof(active_ctx->lcInExtY)); + case CTX_INEXTZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcInExtZ, sizeof(active_ctx->lcInExtZ)); + case CTX_OUTORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgX, sizeof(active_ctx->lcOutOrgX)); + case CTX_OUTORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgY, sizeof(active_ctx->lcOutOrgY)); + case CTX_OUTORGZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutOrgZ, sizeof(active_ctx->lcOutOrgZ)); + case CTX_OUTEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtX, sizeof(active_ctx->lcOutExtX)); + case CTX_OUTEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtY, sizeof(active_ctx->lcOutExtY)); + case CTX_OUTEXTZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcOutExtZ, sizeof(active_ctx->lcOutExtZ)); + case CTX_SENSX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensX, sizeof(active_ctx->lcSensX)); + case CTX_SENSY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensY, sizeof(active_ctx->lcSensY)); + case CTX_SENSZ: + return TABLET_CopyData(lpOutput, &active_ctx->lcSensZ, sizeof(active_ctx->lcSensZ)); + case CTX_SYSMODE: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysMode, sizeof(active_ctx->lcSysMode)); + case CTX_SYSORGX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysOrgX, sizeof(active_ctx->lcSysOrgX)); + case CTX_SYSORGY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysOrgY, sizeof(active_ctx->lcSysOrgY)); + case CTX_SYSEXTX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysExtX, sizeof(active_ctx->lcSysExtX)); + case CTX_SYSEXTY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysExtY, sizeof(active_ctx->lcSysExtY)); + case CTX_SYSSENSX: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysSensX, sizeof(active_ctx->lcSysSensX)); + case CTX_SYSSENSY: + return TABLET_CopyData(lpOutput, &active_ctx->lcSysSensY, sizeof(active_ctx->lcSysSensY)); + default: + FIXME("WTI_DEFSYSCTX unhandled index %i\n", nIndex); + return 0; + } + } + case WTI_DEVICES: + case WTI_DEVICES - 1: + switch (nIndex) + { + case DVC_NAME: + { + static const WCHAR name[] = {'M','a','c','d','r','v',' ','T','a','b','l','e','t',0}; + return TABLET_CopyData(lpOutput, name, sizeof(name)); + } + case DVC_HARDWARE: + { + static const UINT hardware = HWC_HARDPROX; + return TABLET_CopyData(lpOutput, &hardware, sizeof(hardware)); + } + case DVC_NCSRTYPES: + { + static const UINT num = 0; + return TABLET_CopyData(lpOutput, &num, sizeof(num)); + } + case DVC_FIRSTCSR: + { + static const UINT first = 0; + return TABLET_CopyData(lpOutput, &first, sizeof(first)); + } + case DVC_PKTRATE: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktRate, sizeof(macdrv_tablet_ctx.lcPktRate)); + case DVC_PKTDATA: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktData, sizeof(macdrv_tablet_ctx.lcPktData)); + case DVC_PKTMODE: + return TABLET_CopyData(lpOutput, &macdrv_tablet_ctx.lcPktMode, sizeof(macdrv_tablet_ctx.lcPktMode)); + case DVC_CSRDATA: + { + static const WTPKT data = 0; + return TABLET_CopyData(lpOutput, &data, sizeof(data)); + } + case DVC_XMARGIN: + case DVC_YMARGIN: + case DVC_ZMARGIN: + { + static const INT margin = 0; + return TABLET_CopyData(lpOutput, &margin, sizeof(margin)); + } + case DVC_X: + case DVC_Y: + case DVC_Z: + { + UINT org = (nIndex == DVC_X ? macdrv_tablet_ctx.lcInOrgX : nIndex == DVC_Y ? macdrv_tablet_ctx.lcInOrgY : macdrv_tablet_ctx.lcInOrgZ); + UINT ext = (nIndex == DVC_X ? macdrv_tablet_ctx.lcInExtX : nIndex == DVC_Y ? macdrv_tablet_ctx.lcInExtY : macdrv_tablet_ctx.lcInExtZ); + AXIS ax = { + .axMin = org, + .axMax = org + ext - 1, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_NPRESSURE: + { + static const AXIS ax = { + .axMin = 0, + .axMax = MAX_PRESSURE, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_TPRESSURE: + { + static const AXIS ax = { + .axMin = -MAX_PRESSURE, + .axMax = MAX_PRESSURE, + .axUnits = TU_NONE, + .axResolution = 1 + }; + return TABLET_CopyData(lpOutput, &ax, sizeof(ax)); + } + case DVC_ORIENTATION: + { + static const AXIS axes[] = { + /*.orAzimuth = */ { + .axMin = 0, + .axMax = MAX_ANGLE, + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + }, + /*.orAltitude = */ { + .axMin = -MAKE_ANGLE_DEG(90), + .axMax = MAKE_ANGLE_DEG(90), + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + }, + /*.orTwist = */ { + .axMin = 0, + .axMax = MAX_ANGLE, + .axUnits = TU_CIRCLE, + .axResolution = CASTFIX32(MAX_ANGLE) + } + }; + return TABLET_CopyData(lpOutput, &axes, sizeof(axes)); + } + case DVC_ROTATION: + /* Unsupported */ + return 0; + case DVC_PNPID: + { + static const WCHAR pnpId[] = {'n','o','n','-','p','l','u','g','-','n','-','p','l','a','y',0}; + return TABLET_CopyData(lpOutput, pnpId, sizeof(pnpId)); + } + default: + FIXME("WTI_DEVICES unhandled index %i\n", nIndex); + return 0; + } + break; + default: + if (IS_WTI_DEVICES_TYPE(wCategory) || IS_WTI_DDCTXS_TYPE(wCategory) + || IS_WTI_DSCTXS_TYPE(wCategory)) + /* User error, there's only one device */ + return 0; + FIXME("Unhandled Category %i\n", wCategory); + } return 0; }