wine-wine/dlls/wintab32/context.c

1135 lines
32 KiB
C

/*
* Tablet Context
*
* Copyright 2002 Patrik Stridvall
* 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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "windef.h"
#include "winerror.h"
#include "winbase.h"
#include "winuser.h"
#include "winnls.h"
#include "wintab.h"
#include "wintab_internal.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
/*
* Documentation found at
* http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html
*/
static LPOPENCONTEXT gOpenContexts;
static HCTX gTopContext = (HCTX)0xc00;
static void LOGCONTEXTAtoW(const LOGCONTEXTA *in, LOGCONTEXTW *out)
{
MultiByteToWideChar(CP_ACP, 0, in->lcName, -1, out->lcName, LCNAMELEN);
out->lcName[LCNAMELEN - 1] = 0;
/* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTA) - FIELD_OFFSET(LOGCONTEXTA, lcOptions));
}
static void LOGCONTEXTWtoA(const LOGCONTEXTW *in, LOGCONTEXTA *out)
{
WideCharToMultiByte(CP_ACP, 0, in->lcName, LCNAMELEN, out->lcName, LCNAMELEN, NULL, NULL);
out->lcName[LCNAMELEN - 1] = 0;
/* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTW) - FIELD_OFFSET(LOGCONTEXTW, lcOptions));
}
static BOOL is_logcontext_category(UINT wCategory)
{
return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT || wCategory == WTI_DDCTXS;
}
static BOOL is_string_field(UINT wCategory, UINT nIndex)
{
if (wCategory == WTI_INTERFACE && nIndex == IFC_WINTABID)
return TRUE;
if (is_logcontext_category(wCategory) && nIndex == CTX_NAME)
return TRUE;
if ((wCategory >= WTI_CURSORS && wCategory <= WTI_CURSORS + 9) &&
(nIndex == CSR_NAME || nIndex == CSR_BTNNAMES))
return TRUE;
if (wCategory == WTI_DEVICES && (nIndex == DVC_NAME || nIndex == DVC_PNPID))
return TRUE;
return FALSE;
}
static const char* DUMPBITS(int x)
{
char buf[200];
buf[0] = 0;
if (x&PK_CONTEXT) strcat(buf,"PK_CONTEXT ");
if (x&PK_STATUS) strcat(buf, "PK_STATUS ");
if (x&PK_TIME) strcat(buf, "PK_TIME ");
if (x&PK_CHANGED) strcat(buf, "PK_CHANGED ");
if (x&PK_SERIAL_NUMBER) strcat(buf, "PK_SERIAL_NUMBER ");
if (x&PK_CURSOR) strcat(buf, "PK_CURSOR ");
if (x&PK_BUTTONS) strcat(buf, "PK_BUTTONS ");
if (x&PK_X) strcat(buf, "PK_X ");
if (x&PK_Y) strcat(buf, "PK_Y ");
if (x&PK_Z) strcat(buf, "PK_Z ");
if (x&PK_NORMAL_PRESSURE) strcat(buf, "PK_NORMAL_PRESSURE ");
if (x&PK_TANGENT_PRESSURE) strcat(buf, "PK_TANGENT_PRESSURE ");
if (x&PK_ORIENTATION) strcat(buf, "PK_ORIENTATION ");
if (x&PK_ROTATION) strcat(buf, "PK_ROTATION ");
return wine_dbg_sprintf("{%s}",buf);
}
static inline void DUMPPACKET(WTPACKET packet)
{
TRACE("pkContext: %p pkStatus: 0x%x pkTime : 0x%x pkChanged: 0x%x pkSerialNumber: 0x%x pkCursor : %i pkButtons: %x pkX: %i pkY: %i pkZ: %i pkNormalPressure: %i pkTangentPressure: %i pkOrientation: (%i,%i,%i) pkRotation: (%i,%i,%i)\n",
packet.pkContext, packet.pkStatus, packet.pkTime, packet.pkChanged, packet.pkSerialNumber,
packet.pkCursor, packet.pkButtons, packet.pkX, packet.pkY, packet.pkZ,
packet.pkNormalPressure, packet.pkTangentPressure,
packet.pkOrientation.orAzimuth, packet.pkOrientation.orAltitude, packet.pkOrientation.orTwist,
packet.pkRotation.roPitch, packet.pkRotation.roRoll, packet.pkRotation.roYaw);
}
static inline void DUMPCONTEXT(LOGCONTEXTW lc)
{
TRACE("Name: %s, Options: %x, Status: %x, Locks: %x, MsgBase: %x, Device: %x\n",
wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase, lc.lcDevice);
TRACE("PktRate %x\n", lc.lcPktRate);
TRACE("PktData 0x%04x %s\n", lc.lcPktData, DUMPBITS(lc.lcPktData));
TRACE("PktMode 0x%04x %s\n", lc.lcPktMode, DUMPBITS(lc.lcPktMode));
TRACE("MovMask 0x%04x %s\n", lc.lcMoveMask, DUMPBITS(lc.lcMoveMask));
TRACE("BtnDnMask: %x, BtnUpMask: %x\n", lc.lcBtnDnMask, lc.lcBtnUpMask);
TRACE("InOrgX: %i, InOrgY: %i, InOrgZ: %i\n", lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ);
TRACE("InExtX: %i, InExtY: %i, InExtZ: %i\n", lc.lcInExtX, lc.lcInExtY, lc.lcInExtZ);
TRACE("OutOrgX: %i, OutOrgY: %i, OutOrgZ: %i\n", lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ);
TRACE("OutExtX: %i, OutExtY: %i, OutExtZ: %i\n", lc.lcOutExtX, lc.lcOutExtY, lc.lcOutExtZ);
TRACE("SensX: %i, SensY: %i, SensZ: %i\n", lc.lcSensX, lc.lcSensY, lc.lcSensZ);
TRACE("SysMode: %i\n", lc.lcSysMode);
TRACE("SysOrgX: %i, SysOrgY: %i\n", lc.lcSysOrgX, lc.lcSysOrgY);
TRACE("SysExtX: %i, SysExtY: %i\n", lc.lcSysExtX, lc.lcSysExtY);
TRACE("SysSensX: %i, SysSensY: %i\n", lc.lcSysSensX, lc.lcSysSensY);
}
/* Find an open context given the handle */
static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
{
LPOPENCONTEXT ptr = gOpenContexts;
while (ptr)
{
if (ptr->handle == hCtx) return ptr;
ptr = ptr->next;
}
return NULL;
}
static inline BOOL LoadTablet(void)
{
static enum {TI_START = 0, TI_OK, TI_FAIL} loaded = TI_START;
if (loaded == TI_START)
{
if (pLoadTabletInfo && pLoadTabletInfo(hwndDefault))
{
TRACE("Initialized the tablet to hwnd %p\n", hwndDefault);
loaded = TI_OK;
}
else
{
TRACE("Failed to initialize the tablet to hwnd %p\n", hwndDefault);
loaded = TI_FAIL;
}
}
return loaded == TI_OK;
}
int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
LPARAM lParam, BOOL send_always)
{
if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
{
TRACE("Posting message %x to %p\n",msg, newcontext->hwndOwner);
return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
}
return 0;
}
static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt)
{
if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
return MulDiv(In - InOrg, abs(OutExt), abs(InExt)) + OutOrg;
else
return MulDiv(abs(InExt) - (In - InOrg), abs(OutExt), abs(InExt)) + OutOrg;
}
LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
{
LPOPENCONTEXT ptr=NULL;
EnterCriticalSection(&csTablet);
ptr = gOpenContexts;
while (ptr)
{
TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
if (ptr->hwndOwner == hwnd)
{
int tgt;
if (!ptr->enabled)
{
ptr = ptr->next;
continue;
}
tgt = ptr->PacketsQueued;
packet->pkContext = ptr->handle;
/* translate packet data to the context */
packet->pkChanged = packet->pkChanged & ptr->context.lcPktData;
/* Scale as per documentation */
packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
ptr->context.lcInExtY, ptr->context.lcOutOrgY,
ptr->context.lcOutExtY);
packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
ptr->context.lcInExtX, ptr->context.lcOutOrgX,
ptr->context.lcOutExtX);
/* flip the Y axis */
if (ptr->context.lcOutExtY > 0)
packet->pkY = ptr->context.lcOutExtY - packet->pkY;
else if (ptr->context.lcOutExtY < 0)
{
int y = ptr->context.lcOutExtY + packet->pkY;
packet->pkY = abs(y);
}
DUMPPACKET(*packet);
if (tgt == ptr->QueueSize)
{
TRACE("Queue Overflow %p\n",ptr->handle);
ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
}
else
{
TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
ptr->PacketQueue[tgt] = *packet;
ptr->PacketsQueued++;
if (ptr->ActiveCursor != packet->pkCursor)
{
ptr->ActiveCursor = packet->pkCursor;
if (ptr->context.lcOptions & CXO_CSRMESSAGES)
TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
(WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
FALSE);
}
}
break;
}
ptr = ptr->next;
}
LeaveCriticalSection(&csTablet);
TRACE("Done (%p)\n",ptr);
return ptr;
}
/*
* Flushes all packets from the queue.
*/
static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
{
context->PacketsQueued = 0;
}
static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
{
memcpy(target,src,size);
return(size);
}
static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
LPWTPACKET *pkt)
{
int loop;
int index = -1;
for (loop = 0; loop < context->PacketsQueued; loop++)
if (context->PacketQueue[loop].pkSerialNumber == wSerial)
{
index = loop;
*pkt = &context->PacketQueue[loop];
break;
}
TRACE("%i .. %i\n",context->PacketsQueued,index);
return index;
}
static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
LPWTPACKET wtp)
{
LPBYTE ptr;
ptr = lpPkt;
TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
if (context->context.lcPktData & PK_CONTEXT)
ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
if (context->context.lcPktData & PK_STATUS)
ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
if (context->context.lcPktData & PK_TIME)
ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
if (context->context.lcPktData & PK_CHANGED)
ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
if (context->context.lcPktData & PK_SERIAL_NUMBER)
ptr+=CopyTabletData(ptr,&wtp->pkSerialNumber,sizeof(UINT));
if (context->context.lcPktData & PK_CURSOR)
ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
if (context->context.lcPktData & PK_BUTTONS)
ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
if (context->context.lcPktData & PK_X)
ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
if (context->context.lcPktData & PK_Y)
ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
if (context->context.lcPktData & PK_Z)
ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
if (context->context.lcPktData & PK_NORMAL_PRESSURE)
ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
if (context->context.lcPktData & PK_TANGENT_PRESSURE)
ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
if (context->context.lcPktData & PK_ORIENTATION)
ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
if (context->context.lcPktData & PK_ROTATION)
ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
/*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
return ptr;
}
static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
{
int rc = 0;
if (context->context.lcPktData & PK_CONTEXT)
rc +=sizeof(HCTX);
if (context->context.lcPktData & PK_STATUS)
rc +=sizeof(UINT);
if (context->context.lcPktData & PK_TIME)
rc += sizeof(LONG);
if (context->context.lcPktData & PK_CHANGED)
rc += sizeof(WTPKT);
if (context->context.lcPktData & PK_SERIAL_NUMBER)
rc += sizeof(UINT);
if (context->context.lcPktData & PK_CURSOR)
rc += sizeof(UINT);
if (context->context.lcPktData & PK_BUTTONS)
rc += sizeof(DWORD);
if (context->context.lcPktData & PK_X)
rc += sizeof(DWORD);
if (context->context.lcPktData & PK_Y)
rc += sizeof(DWORD);
if (context->context.lcPktData & PK_Z)
rc += sizeof(DWORD);
if (context->context.lcPktData & PK_NORMAL_PRESSURE)
rc += sizeof(UINT);
if (context->context.lcPktData & PK_TANGENT_PRESSURE)
rc += sizeof(UINT);
if (context->context.lcPktData & PK_ORIENTATION)
rc += sizeof(ORIENTATION);
if (context->context.lcPktData & PK_ROTATION)
rc += sizeof(ROTATION);
rc *= n;
memset(lpPkt,0,rc);
}
static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
{
UINT result;
if (!LoadTablet()) return 0;
TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
/*
* Handle system extents here, as we can use user32.dll code to set them.
*/
if(wCategory == WTI_DEFSYSCTX)
{
switch(nIndex)
{
case CTX_SYSEXTX:
if(lpOutput != NULL)
*(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
return sizeof(LONG);
case CTX_SYSEXTY:
if(lpOutput != NULL)
*(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
return sizeof(LONG);
/* No action, delegate to X11Drv */
}
}
if (is_logcontext_category(wCategory) && nIndex == 0)
{
if (lpOutput)
{
LOGCONTEXTW buf;
pWTInfoW(wCategory, nIndex, &buf);
/* Handle system extents here, as we can use user32.dll code to set them */
if(wCategory == WTI_DEFSYSCTX)
{
buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
}
if (bUnicode)
memcpy(lpOutput, &buf, sizeof(buf));
else
LOGCONTEXTWtoA(&buf, lpOutput);
}
result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
}
else if (is_string_field(wCategory, nIndex) && !bUnicode)
{
int size = pWTInfoW(wCategory, nIndex, NULL);
WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
pWTInfoW(wCategory, nIndex, buf);
result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
HeapFree(GetProcessHeap(), 0, buf);
}
else
result = pWTInfoW(wCategory, nIndex, lpOutput);
TRACE("returns %d\n", result);
return result;
}
/***********************************************************************
* WTInfoA (WINTAB32.20)
*/
UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
{
return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
}
/***********************************************************************
* WTInfoW (WINTAB32.1020)
*/
UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
{
return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
}
/***********************************************************************
* WTOpenW (WINTAB32.1021)
*/
HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
{
LPOPENCONTEXT newcontext;
if (!LoadTablet()) return 0;
TRACE("hWnd=%p, lpLogCtx=%p, fEnable=%u\n", hWnd, lpLogCtx, fEnable);
DUMPCONTEXT(*lpLogCtx);
newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
newcontext->context = *lpLogCtx;
newcontext->hwndOwner = hWnd;
newcontext->ActiveCursor = -1;
newcontext->QueueSize = 10;
newcontext->PacketsQueued = 0;
newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
EnterCriticalSection(&csTablet);
newcontext->handle = gTopContext++;
newcontext->next = gOpenContexts;
gOpenContexts = newcontext;
LeaveCriticalSection(&csTablet);
pAttachEventQueueToTablet(hWnd);
TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
newcontext->context.lcStatus, TRUE);
if (fEnable)
{
newcontext->enabled = TRUE;
/* TODO: Add to top of overlap order */
newcontext->context.lcStatus = CXS_ONTOP;
}
else
{
newcontext->enabled = FALSE;
newcontext->context.lcStatus = CXS_DISABLED;
}
TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
(WPARAM)newcontext->handle,
newcontext->context.lcStatus, TRUE);
return newcontext->handle;
}
/***********************************************************************
* WTOpenA (WINTAB32.21)
*/
HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
{
LOGCONTEXTW logCtxW;
LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
return WTOpenW(hWnd, &logCtxW, fEnable);
}
/***********************************************************************
* WTClose (WINTAB32.22)
*/
BOOL WINAPI WTClose(HCTX hCtx)
{
LPOPENCONTEXT context,ptr;
TRACE("(%p)\n", hCtx);
EnterCriticalSection(&csTablet);
ptr = context = gOpenContexts;
while (context && (context->handle != hCtx))
{
ptr = context;
context = context->next;
}
if (!context)
{
LeaveCriticalSection(&csTablet);
return TRUE;
}
if (context == gOpenContexts)
gOpenContexts = context->next;
else
ptr->next = context->next;
LeaveCriticalSection(&csTablet);
TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
context->context.lcStatus,TRUE);
HeapFree(GetProcessHeap(),0,context->PacketQueue);
HeapFree(GetProcessHeap(),0,context);
return TRUE;
}
/***********************************************************************
* WTPacketsGet (WINTAB32.23)
*/
int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
{
int limit;
LPOPENCONTEXT context;
LPVOID ptr = lpPkts;
TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
if (!hCtx)
return 0;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return 0;
}
if (lpPkts != NULL)
TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
if (context->PacketsQueued == 0)
{
LeaveCriticalSection(&csTablet);
return 0;
}
limit = min(cMaxPkts,context->PacketsQueued);
if(ptr != NULL)
{
int i = 0;
for(i = 0; i < limit; i++)
ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
}
if (limit < context->PacketsQueued)
{
memmove(context->PacketQueue, &context->PacketQueue[limit],
(context->PacketsQueued - (limit))*sizeof(WTPACKET));
}
context->PacketsQueued -= limit;
LeaveCriticalSection(&csTablet);
TRACE("Copied %i packets\n",limit);
return limit;
}
/***********************************************************************
* WTPacket (WINTAB32.24)
*/
BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
{
int rc = 0;
LPOPENCONTEXT context;
LPWTPACKET wtp = NULL;
TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
if (!hCtx)
return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
rc = TABLET_FindPacket(context ,wSerial, &wtp);
if (rc >= 0)
{
if (lpPkt)
TABLET_CopyPacketData(context ,lpPkt, wtp);
if ((rc+1) < context->QueueSize)
{
memmove(context->PacketQueue, &context->PacketQueue[rc+1],
(context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
}
context->PacketsQueued -= (rc+1);
}
LeaveCriticalSection(&csTablet);
TRACE("Returning %i\n",rc+1);
return rc+1;
}
/***********************************************************************
* WTEnable (WINTAB32.40)
*/
BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
{
LPOPENCONTEXT context;
TRACE("hCtx=%p, fEnable=%u\n", hCtx, fEnable);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
/* if we want to enable and it is not enabled then */
if(fEnable && !context->enabled)
{
context->enabled = TRUE;
/* TODO: Add to top of overlap order */
context->context.lcStatus = CXS_ONTOP;
TABLET_PostTabletMessage(context,
_WT_CTXOVERLAP(context->context.lcMsgBase),
(WPARAM)context->handle,
context->context.lcStatus, TRUE);
}
/* if we want to disable and it is not disabled then */
else if (!fEnable && context->enabled)
{
context->enabled = FALSE;
/* TODO: Remove from overlap order?? needs a test */
context->context.lcStatus = CXS_DISABLED;
TABLET_FlushQueue(context);
TABLET_PostTabletMessage(context,
_WT_CTXOVERLAP(context->context.lcMsgBase),
(WPARAM)context->handle,
context->context.lcStatus, TRUE);
}
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTOverlap (WINTAB32.41)
*
* Move context to top or bottom of overlap order
*/
BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
{
LPOPENCONTEXT context;
TRACE("hCtx=%p, fToTop=%u\n", hCtx, fToTop);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
/* if we want to send to top and it's not already there */
if (fToTop && context->context.lcStatus != CXS_ONTOP)
{
/* TODO: Move context to top of overlap order */
FIXME("Not moving context to top of overlap order\n");
context->context.lcStatus = CXS_ONTOP;
TABLET_PostTabletMessage(context,
_WT_CTXOVERLAP(context->context.lcMsgBase),
(WPARAM)context->handle,
context->context.lcStatus, TRUE);
}
else if (!fToTop)
{
/* TODO: Move context to bottom of overlap order */
FIXME("Not moving context to bottom of overlap order\n");
context->context.lcStatus = CXS_OBSCURED;
TABLET_PostTabletMessage(context,
_WT_CTXOVERLAP(context->context.lcMsgBase),
(WPARAM)context->handle,
context->context.lcStatus, TRUE);
}
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTConfig (WINTAB32.60)
*/
BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
{
FIXME("(%p, %p): stub\n", hCtx, hWnd);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* WTGetA (WINTAB32.61)
*/
BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
{
LPOPENCONTEXT context;
TRACE("(%p, %p)\n", hCtx, lpLogCtx);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
LOGCONTEXTWtoA(&context->context, lpLogCtx);
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTGetW (WINTAB32.1061)
*/
BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
{
LPOPENCONTEXT context;
TRACE("(%p, %p)\n", hCtx, lpLogCtx);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTSetA (WINTAB32.62)
*/
BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
{
LPOPENCONTEXT context;
TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
if (!hCtx || !lpLogCtx) return FALSE;
/* TODO: if cur process not owner of hCtx only modify
* attribs not locked by owner */
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
LOGCONTEXTAtoW(lpLogCtx, &context->context);
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTSetW (WINTAB32.1062)
*/
BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
{
LPOPENCONTEXT context;
TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
if (!hCtx || !lpLogCtx) return FALSE;
/* TODO: if cur process not hCtx owner only modify
* attribs not locked by owner */
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
memmove(&context->context, lpLogCtx, sizeof(LOGCONTEXTW));
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTExtGet (WINTAB32.63)
*/
BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
{
FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* WTExtSet (WINTAB32.64)
*/
BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
{
FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* WTSave (WINTAB32.65)
*/
BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
{
FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/***********************************************************************
* WTRestore (WINTAB32.66)
*/
HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
{
FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return 0;
}
/***********************************************************************
* WTPacketsPeek (WINTAB32.80)
*/
int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
{
int limit;
LPOPENCONTEXT context;
LPVOID ptr = lpPkts;
TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
if (!hCtx || !lpPkts) return 0;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context || context->PacketsQueued == 0)
{
LeaveCriticalSection(&csTablet);
return 0;
}
for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
LeaveCriticalSection(&csTablet);
TRACE("Copied %i packets\n",limit);
return limit;
}
/***********************************************************************
* WTDataGet (WINTAB32.81)
*/
int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
{
LPOPENCONTEXT context;
LPVOID ptr = lpPkts;
INT bgn = 0;
INT end = 0;
INT num = 0;
TRACE("(%p, %u, %u, %d, %p, %p)\n",
hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
if (!hCtx) return 0;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context || context->PacketsQueued == 0)
{
LeaveCriticalSection(&csTablet);
return 0;
}
while (bgn < context->PacketsQueued &&
context->PacketQueue[bgn].pkSerialNumber != wBegin)
bgn++;
end = bgn;
while (end < context->PacketsQueued &&
context->PacketQueue[end].pkSerialNumber != wEnd)
end++;
if ((bgn == end) && (end == context->PacketsQueued))
{
LeaveCriticalSection(&csTablet);
return 0;
}
for (num = bgn; num <= end; num++)
ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
/* remove read packets */
if ((end+1) < context->PacketsQueued)
memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
(context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
context->PacketsQueued -= ((end-bgn)+1);
*lpNPkts = ((end-bgn)+1);
LeaveCriticalSection(&csTablet);
TRACE("Copied %i packets\n",*lpNPkts);
return (end - bgn)+1;
}
/***********************************************************************
* WTDataPeek (WINTAB32.82)
*/
int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
{
LPOPENCONTEXT context;
LPVOID ptr = lpPkts;
INT bgn = 0;
INT end = 0;
INT num = 0;
TRACE("(%p, %u, %u, %d, %p, %p)\n",
hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
if (!hCtx || !lpPkts) return 0;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context || context->PacketsQueued == 0)
{
LeaveCriticalSection(&csTablet);
return 0;
}
while (bgn < context->PacketsQueued &&
context->PacketQueue[bgn].pkSerialNumber != wBegin)
bgn++;
end = bgn;
while (end < context->PacketsQueued &&
context->PacketQueue[end].pkSerialNumber != wEnd)
end++;
if (bgn == context->PacketsQueued || end == context->PacketsQueued)
{
TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
LeaveCriticalSection(&csTablet);
return 0;
}
for (num = bgn; num <= end; num++)
ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
*lpNPkts = ((end-bgn)+1);
LeaveCriticalSection(&csTablet);
TRACE("Copied %i packets\n",*lpNPkts);
return (end - bgn)+1;
}
/***********************************************************************
* WTQueuePacketsEx (WINTAB32.200)
*/
BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
{
LPOPENCONTEXT context;
TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (context && context->PacketsQueued)
{
*lpOld = context->PacketQueue[0].pkSerialNumber;
*lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
}
else
{
TRACE("No packets\n");
LeaveCriticalSection(&csTablet);
return FALSE;
}
LeaveCriticalSection(&csTablet);
return TRUE;
}
/***********************************************************************
* WTQueueSizeGet (WINTAB32.84)
*/
int WINAPI WTQueueSizeGet(HCTX hCtx)
{
LPOPENCONTEXT context;
int queueSize = 0;
TRACE("(%p)\n", hCtx);
if (!hCtx) return 0;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (context)
queueSize = context->QueueSize;
LeaveCriticalSection(&csTablet);
return queueSize;
}
/***********************************************************************
* WTQueueSizeSet (WINTAB32.85)
*/
BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
{
LPOPENCONTEXT context;
TRACE("(%p, %d)\n", hCtx, nPkts);
if (!hCtx) return FALSE;
EnterCriticalSection(&csTablet);
context = TABLET_FindOpenContext(hCtx);
if (!context)
{
LeaveCriticalSection(&csTablet);
return FALSE;
}
context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
context->PacketQueue, sizeof(WTPACKET)*nPkts);
context->QueueSize = nPkts;
LeaveCriticalSection(&csTablet);
return nPkts;
}