| /* |
| * 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 "config.h" |
| #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, PktRate: %x, " |
| "%x%s, %x%s, %x%s, " |
| "BtnDnMask: %x, BtnUpMask: %x, " |
| "InOrgX: %i, InOrgY: %i, InOrgZ: %i, " |
| "InExtX: %i, InExtY: %i, InExtZ: %i, " |
| "OutOrgX: %i, OutOrgY: %i, OutOrgZ: %i, " |
| "OutExtX: %i, OutExtY: %i, OutExtZ: %i, " |
| "SensX: %i, SensY: %i, SensZ: %i, " |
| "SysMode: %i, " |
| "SysOrgX: %i, SysOrgY: %i, " |
| "SysExtX: %i, SysExtY: %i, " |
| "SysSensX: %i, SysSensY: %i\n", |
| wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase, |
| lc.lcDevice, lc.lcPktRate, lc.lcPktData, DUMPBITS(lc.lcPktData), |
| lc.lcPktMode, DUMPBITS(lc.lcPktMode), lc.lcMoveMask, |
| DUMPBITS(lc.lcMoveMask), lc.lcBtnDnMask, lc.lcBtnUpMask, |
| lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ, lc.lcInExtX, lc.lcInExtY, |
| lc.lcInExtZ, lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ, lc.lcOutExtX, |
| lc.lcOutExtY, lc.lcOutExtZ, lc.lcSensX, lc.lcSensY, lc.lcSensZ, lc.lcSysMode, |
| lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY, 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) |
| { |
| TRACE("Initializing the tablet to hwnd %p\n",hwndDefault); |
| |
| if (pLoadTabletInfo && pLoadTabletInfo(hwndDefault)) |
| { |
| loaded = TI_OK; |
| } |
| else |
| { |
| loaded = TI_FAIL; |
| ERR("LoadTabletInfo(%p) failed\n", hwndDefault); |
| } |
| } |
| |
| 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 ((In - InOrg) * abs(OutExt) / abs(InExt)) + OutOrg; |
| else |
| return ((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 */ |
| |
| /* 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) |
| packet->pkY = abs(ptr->context.lcOutExtY + packet->pkY); |
| |
| 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.2021) |
| */ |
| 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.61) |
| */ |
| 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; |
| } |