msi/tests: Reduce buffer to size of string written.
[wine] / dlls / wintab32 / context.c
1 /*
2  * Tablet Context
3  *
4  * Copyright 2002 Patrik Stridvall
5  * Copyright 2003 CodeWeavers, Aric Stewart
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26
27 #include "windef.h"
28 #include "winerror.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "winnls.h"
32
33 #include "wintab.h"
34 #include "wintab_internal.h"
35
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
39
40 /*
41  * Documentation found at
42  * http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html
43  */
44
45 static BOOL gLoaded;
46 static LPOPENCONTEXT gOpenContexts;
47 static HCTX gTopContext = (HCTX)0xc00;
48
49 static void LOGCONTEXTAtoW(const LOGCONTEXTA *in, LOGCONTEXTW *out)
50 {
51     MultiByteToWideChar(CP_ACP, 0, in->lcName, -1, out->lcName, LCNAMELEN);
52     out->lcName[LCNAMELEN - 1] = 0;
53     /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
54     memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTA) - FIELD_OFFSET(LOGCONTEXTA, lcOptions));
55 }
56
57 static void LOGCONTEXTWtoA(const LOGCONTEXTW *in, LOGCONTEXTA *out)
58 {
59     WideCharToMultiByte(CP_ACP, 0, in->lcName, LCNAMELEN, out->lcName, LCNAMELEN, NULL, NULL);
60     out->lcName[LCNAMELEN - 1] = 0;
61     /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
62     memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTW) - FIELD_OFFSET(LOGCONTEXTW, lcOptions));
63 }
64
65 static BOOL is_logcontext_category(UINT wCategory)
66 {
67     return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT || wCategory == WTI_DDCTXS;
68 }
69
70 static BOOL is_string_field(UINT wCategory, UINT nIndex)
71 {
72     if (wCategory == WTI_INTERFACE && nIndex == IFC_WINTABID)
73         return TRUE;
74     if (is_logcontext_category(wCategory) && nIndex == CTX_NAME)
75         return TRUE;
76     if ((wCategory >= WTI_CURSORS && wCategory <= WTI_CURSORS + 9) &&
77             (nIndex == CSR_NAME || nIndex == CSR_BTNNAMES))
78         return TRUE;
79     if (wCategory == WTI_DEVICES && (nIndex == DVC_NAME || nIndex == DVC_PNPID))
80         return TRUE;
81     return FALSE;
82 }
83
84 static const char* DUMPBITS(int x)
85 {
86     char buf[200];
87     buf[0] = 0;
88     if (x&PK_CONTEXT) strcat(buf,"PK_CONTEXT ");
89     if (x&PK_STATUS) strcat(buf, "PK_STATUS ");
90     if (x&PK_TIME) strcat(buf, "PK_TIME ");
91     if (x&PK_CHANGED) strcat(buf, "PK_CHANGED ");
92     if (x&PK_SERIAL_NUMBER) strcat(buf, "PK_SERIAL_NUMBER ");
93     if (x&PK_CURSOR) strcat(buf, "PK_CURSOR ");
94     if (x&PK_BUTTONS) strcat(buf, "PK_BUTTONS ");
95     if (x&PK_X) strcat(buf, "PK_X ");
96     if (x&PK_Y) strcat(buf, "PK_Y ");
97     if (x&PK_Z) strcat(buf, "PK_Z ");
98     if (x&PK_NORMAL_PRESSURE) strcat(buf, "PK_NORMAL_PRESSURE ");
99     if (x&PK_TANGENT_PRESSURE) strcat(buf, "PK_TANGENT_PRESSURE ");
100     if (x&PK_ORIENTATION) strcat(buf, "PK_ORIENTATION ");
101     if (x&PK_ROTATION) strcat(buf, "PK_ROTATION ");
102     return wine_dbg_sprintf("{%s}",buf);
103 }
104
105 static inline void DUMPPACKET(WTPACKET packet)
106 {
107     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",
108           packet.pkContext, packet.pkStatus, packet.pkTime, packet.pkChanged, packet.pkSerialNumber,
109           packet.pkCursor, packet.pkButtons, packet.pkX, packet.pkY, packet.pkZ,
110           packet.pkNormalPressure, packet.pkTangentPressure,
111           packet.pkOrientation.orAzimuth, packet.pkOrientation.orAltitude, packet.pkOrientation.orTwist,
112           packet.pkRotation.roPitch, packet.pkRotation.roRoll, packet.pkRotation.roYaw);
113 }
114
115 static inline void DUMPCONTEXT(LOGCONTEXTW lc)
116 {
117     TRACE("context: %s, %x, %x, %x, %x, %x, %x, %x%s, %x%s, %x%s, %x, %x, %i, %i, %i, %i ,%i, %i, %i, %i, %i,%i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i %i %i\n",
118           wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase,
119           lc.lcDevice, lc.lcPktRate, lc.lcPktData, DUMPBITS(lc.lcPktData),
120           lc.lcPktMode, DUMPBITS(lc.lcPktMode), lc.lcMoveMask,
121           DUMPBITS(lc.lcMoveMask), lc.lcBtnDnMask, lc.lcBtnUpMask,
122           lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ, lc.lcInExtX, lc.lcInExtY,
123           lc.lcInExtZ, lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ, lc.lcOutExtX,
124           lc.lcOutExtY, lc.lcOutExtZ, lc.lcSensX, lc.lcSensY, lc.lcSensZ, lc.lcSysMode,
125           lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY, lc.lcSysSensX,
126           lc.lcSysSensY);
127 }
128
129
130 /* Find an open context given the handle */
131 static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
132 {
133     LPOPENCONTEXT ptr = gOpenContexts;
134     while (ptr)
135     {
136         if (ptr->handle == hCtx) return ptr;
137         ptr = ptr->next;
138     }
139     return NULL;
140 }
141
142 static void LoadTablet(void)
143 {
144     TRACE("Initializing the tablet to hwnd %p\n",hwndDefault);
145     gLoaded= TRUE;
146     pLoadTabletInfo(hwndDefault);
147 }
148
149 int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
150                              LPARAM lParam, BOOL send_always)
151 {
152     if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
153     {
154         TRACE("Posting message %x to %p\n",msg, newcontext->hwndOwner);
155         return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
156     }
157     return 0;
158 }
159
160 static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt)
161 {
162     if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
163         return ((In - InOrg) * abs(OutExt) / abs(InExt)) + OutOrg;
164     else
165         return ((abs(InExt) - (In - InOrg))*abs(OutExt) / abs(InExt)) + OutOrg;
166 }
167
168 LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
169 {
170     LPOPENCONTEXT ptr=NULL;
171
172     EnterCriticalSection(&csTablet);
173
174     ptr = gOpenContexts;
175     while (ptr)
176     {
177         TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
178
179         if (ptr->hwndOwner == hwnd)
180         {
181             int tgt;
182             if (!ptr->enabled)
183             {
184                 ptr = ptr->next;
185                 continue;
186             }
187
188             tgt = ptr->PacketsQueued;
189
190             packet->pkContext = ptr->handle;
191
192             /* translate packet data to the context */
193
194             /* Scale  as per documentation */
195             packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
196                                 ptr->context.lcInExtY, ptr->context.lcOutOrgY,
197                                 ptr->context.lcOutExtY);
198
199             packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
200                                 ptr->context.lcInExtX, ptr->context.lcOutOrgX,
201                                 ptr->context.lcOutExtX);
202
203             /* flip the Y axis */
204             if (ptr->context.lcOutExtY > 0)
205                 packet->pkY = ptr->context.lcOutExtY - packet->pkY;
206
207             DUMPPACKET(*packet);
208
209             if (tgt == ptr->QueueSize)
210             {
211                 TRACE("Queue Overflow %p\n",ptr->handle);
212                 ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
213             }
214             else
215             {
216                 TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
217                 ptr->PacketQueue[tgt] = *packet;
218                 ptr->PacketsQueued++;
219
220                 if (ptr->ActiveCursor != packet->pkCursor)
221                 {
222                     ptr->ActiveCursor = packet->pkCursor;
223                     if (ptr->context.lcOptions & CXO_CSRMESSAGES)
224                         TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
225                           (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
226                             FALSE);
227                 }
228             }
229             break;
230          }
231         ptr = ptr->next;
232     }
233     LeaveCriticalSection(&csTablet);
234     TRACE("Done (%p)\n",ptr);
235     return ptr;
236 }
237
238 /*
239  * Flushes all packets from the queue.
240  */
241 static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
242 {
243     context->PacketsQueued = 0;
244 }
245
246 static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
247 {
248     memcpy(target,src,size);
249     return(size);
250 }
251
252 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
253                                 LPWTPACKET *pkt)
254 {
255     int loop;
256     int index  = -1;
257     for (loop = 0; loop < context->PacketsQueued; loop++)
258         if (context->PacketQueue[loop].pkSerialNumber == wSerial)
259         {
260             index = loop;
261             *pkt = &context->PacketQueue[loop];
262             break;
263         }
264
265     TRACE("%i .. %i\n",context->PacketsQueued,index);
266
267     return index;
268 }
269
270
271 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
272                                     LPWTPACKET wtp)
273 {
274     LPBYTE ptr;
275
276     ptr = lpPkt;
277     TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
278
279     if (context->context.lcPktData & PK_CONTEXT)
280         ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
281     if (context->context.lcPktData & PK_STATUS)
282         ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
283     if (context->context.lcPktData & PK_TIME)
284         ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
285     if (context->context.lcPktData & PK_CHANGED)
286         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
287     if (context->context.lcPktData & PK_SERIAL_NUMBER)
288         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(UINT));
289     if (context->context.lcPktData & PK_CURSOR)
290         ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
291     if (context->context.lcPktData & PK_BUTTONS)
292         ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
293     if (context->context.lcPktData & PK_X)
294         ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
295     if (context->context.lcPktData & PK_Y)
296         ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
297     if (context->context.lcPktData & PK_Z)
298         ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
299     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
300         ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
301     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
302         ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
303     if (context->context.lcPktData & PK_ORIENTATION)
304         ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
305     if (context->context.lcPktData & PK_ROTATION)
306         ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
307
308     /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
309     return ptr;
310 }
311
312 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
313 {
314     int rc = 0;
315
316     if (context->context.lcPktData & PK_CONTEXT)
317         rc +=sizeof(HCTX);
318     if (context->context.lcPktData & PK_STATUS)
319         rc +=sizeof(UINT);
320     if (context->context.lcPktData & PK_TIME)
321         rc += sizeof(LONG);
322     if (context->context.lcPktData & PK_CHANGED)
323         rc += sizeof(WTPKT);
324     if (context->context.lcPktData & PK_SERIAL_NUMBER)
325         rc += sizeof(UINT);
326     if (context->context.lcPktData & PK_CURSOR)
327         rc += sizeof(UINT);
328     if (context->context.lcPktData & PK_BUTTONS)
329         rc += sizeof(DWORD);
330     if (context->context.lcPktData & PK_X)
331         rc += sizeof(DWORD);
332     if (context->context.lcPktData & PK_Y)
333         rc += sizeof(DWORD);
334     if (context->context.lcPktData & PK_Z)
335         rc += sizeof(DWORD);
336     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
337         rc += sizeof(UINT);
338     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
339         rc += sizeof(UINT);
340     if (context->context.lcPktData & PK_ORIENTATION)
341         rc += sizeof(ORIENTATION);
342     if (context->context.lcPktData & PK_ROTATION)
343         rc += sizeof(ROTATION);
344
345     rc *= n;
346     memset(lpPkt,0,rc);
347 }
348
349
350 UINT WINAPI WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
351 {
352     UINT result;
353
354     TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
355     if (gLoaded == FALSE)
356          LoadTablet();
357
358     /*
359      *  Handle system extents here, as we can use user32.dll code to set them.
360      */
361     if(wCategory == WTI_DEFSYSCTX)
362     {
363         switch(nIndex)
364         {
365             case CTX_SYSEXTX:
366                 if(lpOutput != NULL)
367                     *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
368                 return sizeof(LONG);
369             case CTX_SYSEXTY:
370                 if(lpOutput != NULL)
371                     *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
372                 return sizeof(LONG);
373            /* No action, delegate to X11Drv */
374         }
375     }
376
377     if (is_logcontext_category(wCategory) && nIndex == 0)
378     {
379         if (lpOutput)
380         {
381             LOGCONTEXTW buf;
382             pWTInfoW(wCategory, nIndex, &buf);
383
384             /*  Handle system extents here, as we can use user32.dll code to set them */
385             if(wCategory == WTI_DEFSYSCTX && nIndex == 0)
386             {
387                 buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
388                 buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
389             }
390
391             if (bUnicode)
392                 memcpy(lpOutput, &buf, sizeof(buf));
393             else
394                 LOGCONTEXTWtoA(&buf, lpOutput);
395         }
396
397         result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
398     }
399     else if (is_string_field(wCategory, nIndex) && !bUnicode)
400     {
401         int size = pWTInfoW(wCategory, nIndex, NULL);
402         WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
403         pWTInfoW(wCategory, nIndex, buf);
404         result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
405         HeapFree(GetProcessHeap(), 0, buf);
406     }
407     else
408         result =  pWTInfoW(wCategory, nIndex, lpOutput);
409
410     TRACE("returns %d\n", result);
411     return result;
412 }
413
414 /***********************************************************************
415  *              WTInfoA (WINTAB32.20)
416  */
417 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
418 {
419     return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
420 }
421
422
423 /***********************************************************************
424  *              WTInfoW (WINTAB32.1020)
425  */
426 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
427 {
428     return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
429 }
430
431 /***********************************************************************
432  *              WTOpenW (WINTAB32.2021)
433  */
434 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
435 {
436     LPOPENCONTEXT newcontext;
437
438     TRACE("hWnd=%p, lpLogCtx=%p, fEnable=%u\n", hWnd, lpLogCtx, fEnable);
439     DUMPCONTEXT(*lpLogCtx);
440
441     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
442     newcontext->context = *lpLogCtx;
443     newcontext->hwndOwner = hWnd;
444     newcontext->ActiveCursor = -1;
445     newcontext->QueueSize = 10;
446     newcontext->PacketsQueued = 0;
447     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
448
449     EnterCriticalSection(&csTablet);
450     newcontext->handle = gTopContext++;
451     newcontext->next = gOpenContexts;
452     gOpenContexts = newcontext;
453     LeaveCriticalSection(&csTablet);
454
455     pAttachEventQueueToTablet(hWnd);
456
457     TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
458                       newcontext->context.lcStatus, TRUE);
459
460     if (fEnable)
461     {
462         newcontext->enabled = TRUE;
463         /* TODO: Add to top of overlap order */
464         newcontext->context.lcStatus = CXS_ONTOP;
465     }
466     else
467     {
468         newcontext->enabled = FALSE;
469         newcontext->context.lcStatus = CXS_DISABLED;
470     }
471
472     TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
473                             (WPARAM)newcontext->handle,
474                             newcontext->context.lcStatus, TRUE);
475
476     return newcontext->handle;
477 }
478
479 /***********************************************************************
480  *              WTOpenA (WINTAB32.21)
481  */
482 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
483 {
484     LOGCONTEXTW logCtxW;
485
486     LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
487     return WTOpenW(hWnd, &logCtxW, fEnable);
488 }
489
490 /***********************************************************************
491  *              WTClose (WINTAB32.22)
492  */
493 BOOL WINAPI WTClose(HCTX hCtx)
494 {
495     LPOPENCONTEXT context,ptr;
496
497     TRACE("(%p)\n", hCtx);
498
499     EnterCriticalSection(&csTablet);
500
501     ptr = context = gOpenContexts;
502
503     while (context && (context->handle != hCtx))
504     {
505         ptr = context;
506         context = context->next;
507     }
508     if (!context)
509     {
510         LeaveCriticalSection(&csTablet);
511         return TRUE;
512     }
513
514     if (context == gOpenContexts)
515         gOpenContexts = context->next;
516     else
517         ptr->next = context->next;
518
519     LeaveCriticalSection(&csTablet);
520
521     TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
522                       context->context.lcStatus,TRUE);
523
524     HeapFree(GetProcessHeap(),0,context->PacketQueue);
525     HeapFree(GetProcessHeap(),0,context);
526
527     return TRUE;
528 }
529
530 /***********************************************************************
531  *              WTPacketsGet (WINTAB32.23)
532  */
533 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
534 {
535     int limit;
536     LPOPENCONTEXT context;
537     LPVOID ptr = lpPkts;
538
539     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
540
541     if (!hCtx)
542         return 0;
543
544     EnterCriticalSection(&csTablet);
545
546     context = TABLET_FindOpenContext(hCtx);
547
548     if (lpPkts != NULL)
549         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
550
551     if (context->PacketsQueued == 0)
552     {
553         LeaveCriticalSection(&csTablet);
554         return 0;
555     }
556
557     limit = min(cMaxPkts,context->PacketsQueued);
558
559     if(ptr != NULL)
560     {
561         int i = 0;
562         for(i = 0; i < limit; i++)
563             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
564     }
565
566
567     if (limit < context->PacketsQueued)
568     {
569         memmove(context->PacketQueue, &context->PacketQueue[limit],
570             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
571     }
572     context->PacketsQueued -= limit;
573     LeaveCriticalSection(&csTablet);
574
575     TRACE("Copied %i packets\n",limit);
576
577     return limit;
578 }
579
580 /***********************************************************************
581  *              WTPacket (WINTAB32.24)
582  */
583 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
584 {
585     int rc = 0;
586     LPOPENCONTEXT context;
587     LPWTPACKET wtp = NULL;
588
589     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
590
591     if (!hCtx)
592         return 0;
593
594     EnterCriticalSection(&csTablet);
595
596     context = TABLET_FindOpenContext(hCtx);
597
598     rc = TABLET_FindPacket(context ,wSerial, &wtp);
599
600     if (rc >= 0)
601     {
602         if (lpPkt)
603            TABLET_CopyPacketData(context ,lpPkt, wtp);
604
605         if ((rc+1) < context->QueueSize)
606         {
607             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
608                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
609         }
610         context->PacketsQueued -= (rc+1);
611     }
612     LeaveCriticalSection(&csTablet);
613
614     TRACE("Returning %i\n",rc+1);
615     return rc+1;
616 }
617
618 /***********************************************************************
619  *              WTEnable (WINTAB32.40)
620  */
621 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
622 {
623     LPOPENCONTEXT context;
624
625     TRACE("hCtx=%p, fEnable=%u\n", hCtx, fEnable);
626
627     if (!hCtx) return FALSE;
628
629     EnterCriticalSection(&csTablet);
630     context = TABLET_FindOpenContext(hCtx);
631     /* if we want to enable and it is not enabled then */
632     if(fEnable && !context->enabled)
633     {
634         context->enabled = TRUE;
635         /* TODO: Add to top of overlap order */
636         context->context.lcStatus = CXS_ONTOP;
637     }
638     /* if we want to disable and it is not disabled then */
639     else if (!fEnable && context->enabled)
640     {
641         context->enabled = FALSE;
642         /* TODO: Remove from overlap order?? needs a test */
643         context->context.lcStatus = CXS_DISABLED;
644         TABLET_FlushQueue(context);
645     }
646     LeaveCriticalSection(&csTablet);
647
648     return TRUE;
649 }
650
651 /***********************************************************************
652  *              WTOverlap (WINTAB32.41)
653  *
654  *              Move context to top or bottom of overlap order
655  */
656 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
657 {
658     LPOPENCONTEXT context;
659
660     TRACE("hCtx=%p, fToTop=%u\n", hCtx, fToTop);
661
662     if (!hCtx) return FALSE;
663
664     EnterCriticalSection(&csTablet);
665     context = TABLET_FindOpenContext(hCtx);
666     if (fToTop)
667     {
668         /* TODO: Move context to top of overlap order */
669         FIXME("Not moving context to top of overlap order\n");
670         context->context.lcStatus = CXS_ONTOP;
671     }
672     else
673     {
674         /* TODO: Move context to bottom of overlap order */
675         FIXME("Not moving context to bottom of overlap order\n");
676         context->context.lcStatus = CXS_OBSCURED;
677     }
678     LeaveCriticalSection(&csTablet);
679
680     return TRUE;
681 }
682
683 /***********************************************************************
684  *              WTConfig (WINTAB32.61)
685  */
686 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
687 {
688     FIXME("(%p, %p): stub\n", hCtx, hWnd);
689
690     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
691
692     return FALSE;
693 }
694
695 /***********************************************************************
696  *              WTGetA (WINTAB32.61)
697  */
698 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
699 {
700     LPOPENCONTEXT context;
701
702     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
703
704     if (!hCtx) return 0;
705
706     EnterCriticalSection(&csTablet);
707     context = TABLET_FindOpenContext(hCtx);
708     LOGCONTEXTWtoA(&context->context, lpLogCtx);
709     LeaveCriticalSection(&csTablet);
710
711     return TRUE;
712 }
713
714 /***********************************************************************
715  *              WTGetW (WINTAB32.1061)
716  */
717 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
718 {
719     LPOPENCONTEXT context;
720
721     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
722
723     if (!hCtx) return 0;
724
725     EnterCriticalSection(&csTablet);
726     context = TABLET_FindOpenContext(hCtx);
727     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
728     LeaveCriticalSection(&csTablet);
729
730     return TRUE;
731 }
732
733 /***********************************************************************
734  *              WTSetA (WINTAB32.62)
735  */
736 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
737 {
738     LPOPENCONTEXT context;
739
740     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
741
742     if (!hCtx || !lpLogCtx) return FALSE;
743
744     /* TODO: if cur process not owner of hCtx only modify
745      * attribs not locked by owner */
746
747     EnterCriticalSection(&csTablet);
748     context = TABLET_FindOpenContext(hCtx);
749     LOGCONTEXTAtoW(lpLogCtx, &context->context);
750     LeaveCriticalSection(&csTablet);
751
752     return TRUE;
753 }
754
755 /***********************************************************************
756  *              WTSetW (WINTAB32.1062)
757  */
758 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
759 {
760     LPOPENCONTEXT context;
761
762     TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
763
764     if (!hCtx || !lpLogCtx) return FALSE;
765
766     /* TODO: if cur process not hCtx owner only modify
767      * attribs not locked by owner */
768
769     EnterCriticalSection(&csTablet);
770     context = TABLET_FindOpenContext(hCtx);
771     memmove(&context->context, lpLogCtx, sizeof(LOGCONTEXTW));
772     LeaveCriticalSection(&csTablet);
773
774     return TRUE;
775 }
776
777 /***********************************************************************
778  *              WTExtGet (WINTAB32.63)
779  */
780 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
781 {
782     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
783
784     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
785
786     return FALSE;
787 }
788
789 /***********************************************************************
790  *              WTExtSet (WINTAB32.64)
791  */
792 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
793 {
794     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
795
796     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
797
798     return FALSE;
799 }
800
801 /***********************************************************************
802  *              WTSave (WINTAB32.65)
803  */
804 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
805 {
806     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
807
808     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
809
810     return FALSE;
811 }
812
813 /***********************************************************************
814  *              WTRestore (WINTAB32.66)
815  */
816 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
817 {
818     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
819
820     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
821
822     return 0;
823 }
824
825 /***********************************************************************
826  *              WTPacketsPeek (WINTAB32.80)
827  */
828 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
829 {
830     int limit;
831     LPOPENCONTEXT context;
832     LPVOID ptr = lpPkts;
833
834     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
835
836     if (!hCtx || !lpPkts) return 0;
837
838     EnterCriticalSection(&csTablet);
839
840     context = TABLET_FindOpenContext(hCtx);
841
842     if (context->PacketsQueued == 0)
843     {
844         LeaveCriticalSection(&csTablet);
845         return 0;
846     }
847
848     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
849         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
850
851     LeaveCriticalSection(&csTablet);
852     TRACE("Copied %i packets\n",limit);
853     return limit;
854 }
855
856 /***********************************************************************
857  *              WTDataGet (WINTAB32.81)
858  */
859 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
860                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
861 {
862     LPOPENCONTEXT context;
863     LPVOID ptr = lpPkts;
864     INT bgn = 0;
865     INT end = 0;
866     INT num = 0;
867
868     TRACE("(%p, %u, %u, %d, %p, %p)\n",
869           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
870
871     if (!hCtx) return 0;
872
873     EnterCriticalSection(&csTablet);
874
875     context = TABLET_FindOpenContext(hCtx);
876
877     if (context->PacketsQueued == 0)
878     {
879         LeaveCriticalSection(&csTablet);
880         return 0;
881     }
882
883     while (bgn < context->PacketsQueued &&
884            context->PacketQueue[bgn].pkSerialNumber != wBegin)
885         bgn++;
886
887     end = bgn;
888     while (end < context->PacketsQueued &&
889            context->PacketQueue[end].pkSerialNumber != wEnd)
890         end++;
891
892     if ((bgn == end) && (end == context->PacketsQueued))
893     {
894         LeaveCriticalSection(&csTablet);
895         return 0;
896     }
897
898     for (num = bgn; num <= end; num++)
899         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
900
901     /* remove read packets */
902     if ((end+1) < context->PacketsQueued)
903         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
904                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
905
906     context->PacketsQueued -= ((end-bgn)+1);
907     *lpNPkts = ((end-bgn)+1);
908
909     LeaveCriticalSection(&csTablet);
910     TRACE("Copied %i packets\n",*lpNPkts);
911     return (end - bgn)+1;
912 }
913
914 /***********************************************************************
915  *              WTDataPeek (WINTAB32.82)
916  */
917 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
918                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
919 {
920     LPOPENCONTEXT context;
921     LPVOID ptr = lpPkts;
922     INT bgn = 0;
923     INT end = 0;
924     INT num = 0;
925
926     TRACE("(%p, %u, %u, %d, %p, %p)\n",
927           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
928
929     if (!hCtx || !lpPkts) return 0;
930
931     EnterCriticalSection(&csTablet);
932
933     context = TABLET_FindOpenContext(hCtx);
934
935     if (context->PacketsQueued == 0)
936     {
937         LeaveCriticalSection(&csTablet);
938         return 0;
939     }
940
941     while (bgn < context->PacketsQueued &&
942            context->PacketQueue[bgn].pkSerialNumber != wBegin)
943         bgn++;
944
945     end = bgn;
946     while (end < context->PacketsQueued &&
947            context->PacketQueue[end].pkSerialNumber != wEnd)
948         end++;
949
950     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
951     {
952         TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
953         LeaveCriticalSection(&csTablet);
954         return 0;
955     }
956
957     for (num = bgn; num <= end; num++)
958         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
959
960     *lpNPkts = ((end-bgn)+1);
961     LeaveCriticalSection(&csTablet);
962
963     TRACE("Copied %i packets\n",*lpNPkts);
964     return (end - bgn)+1;
965 }
966
967 /***********************************************************************
968  *              WTQueuePacketsEx (WINTAB32.200)
969  */
970 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
971 {
972     LPOPENCONTEXT context;
973
974     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
975
976     if (!hCtx) return 0;
977
978     EnterCriticalSection(&csTablet);
979
980     context = TABLET_FindOpenContext(hCtx);
981
982     if (context->PacketsQueued)
983     {
984         *lpOld = context->PacketQueue[0].pkSerialNumber;
985         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
986     }
987     else
988     {
989         TRACE("No packets\n");
990         LeaveCriticalSection(&csTablet);
991         return FALSE;
992     }
993     LeaveCriticalSection(&csTablet);
994
995     return TRUE;
996 }
997
998 /***********************************************************************
999  *              WTQueueSizeGet (WINTAB32.84)
1000  */
1001 int WINAPI WTQueueSizeGet(HCTX hCtx)
1002 {
1003     LPOPENCONTEXT context;
1004     TRACE("(%p)\n", hCtx);
1005
1006     if (!hCtx) return 0;
1007
1008     EnterCriticalSection(&csTablet);
1009     context = TABLET_FindOpenContext(hCtx);
1010     LeaveCriticalSection(&csTablet);
1011     return context->QueueSize;
1012 }
1013
1014 /***********************************************************************
1015  *              WTQueueSizeSet (WINTAB32.85)
1016  */
1017 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
1018 {
1019     LPOPENCONTEXT context;
1020
1021     TRACE("(%p, %d)\n", hCtx, nPkts);
1022
1023     if (!hCtx) return 0;
1024
1025     EnterCriticalSection(&csTablet);
1026
1027     context = TABLET_FindOpenContext(hCtx);
1028
1029     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
1030                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
1031
1032     context->QueueSize = nPkts;
1033     LeaveCriticalSection(&csTablet);
1034
1035     return nPkts;
1036 }