- Correct overflow 1 message too early.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
32 #include "wintab.h"
33 #include "wintab_internal.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
38
39 /*
40  * Documentation found at
41  * http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html
42  */
43
44 static BOOL gLoaded;
45 static LPOPENCONTEXT gOpenContexts;
46 static HCTX gTopContext = (HCTX)0xc00;
47
48 static char* DUMPBITS(int x, char* buf)
49 {
50     strcpy(buf,"{");
51    if (x&PK_CONTEXT) strcat(buf,"PK_CONTEXT ");
52    if (x&PK_STATUS) strcat(buf, "PK_STATUS ");
53    if (x&PK_TIME) strcat(buf, "PK_TIME ");
54    if (x&PK_CHANGED) strcat(buf, "PK_CHANGED ");
55    if (x&PK_SERIAL_NUMBER) strcat(buf, "PK_SERIAL_NUMBER ");
56    if (x&PK_CURSOR) strcat(buf, "PK_CURSOR ");
57    if (x&PK_BUTTONS) strcat(buf, "PK_BUTTONS ");
58    if (x&PK_X) strcat(buf, "PK_X ");
59    if (x&PK_Y) strcat(buf, "PK_Y ");
60    if (x&PK_Z) strcat(buf, "PK_Z ");
61    if (x&PK_NORMAL_PRESSURE) strcat(buf, "PK_NORMAL_PRESSURE ");
62    if (x&PK_TANGENT_PRESSURE) strcat(buf, "PK_TANGENT_PRESSURE ");
63    if (x&PK_ORIENTATION) strcat(buf, "PK_ORIENTATION ");
64    if (x&PK_ROTATION) strcat(buf, "PK_ROTATION ");
65     strcat(buf, "}");
66     return buf;
67 }
68
69 static inline void DUMPPACKET(WTPACKET packet)
70 {
71     TRACE("pkContext: 0x%x pkStatus: 0x%x pkTime : 0x%x pkChanged: 0x%x pkSerialNumber: 0x%x pkCursor : %i pkButtons: %x pkX: %li pkY: %li pkZ: %li pkNormalPressure: %i pkTangentPressure: %i pkOrientation: (%i,%i,%i) pkRotation: (%i,%i,%i)\n"
72 ,(UINT)packet.pkContext,
73     (UINT)packet.pkStatus,
74     (UINT)packet.pkTime,
75     (UINT)packet.pkChanged,
76     packet.pkSerialNumber,
77     packet.pkCursor,
78     (UINT)packet.pkButtons,
79     packet.pkX,
80     packet.pkY,
81     packet.pkZ,
82     packet.pkNormalPressure,
83     packet.pkTangentPressure,
84     packet.pkOrientation.orAzimuth,
85         packet.pkOrientation.orAltitude, packet.pkOrientation.orTwist,
86     packet.pkRotation.roPitch,
87         packet.pkRotation.roRoll, packet.pkRotation.roYaw);
88 }
89
90 static inline void DUMPCONTEXT(LOGCONTEXTA lc)
91 {
92         CHAR mmsg[4000];
93         CHAR bits[100];
94         CHAR bits1[100];
95         CHAR bits2[100];
96
97         sprintf(mmsg,"%s, %x, %x, %x, %x, %x, %x, %x%s, %x%s, %x%s, %x, %x, %i, %i, %i, %li ,%li, %li, %li, %li, %li,%li, %li, %li, %li, %li, %li, %i, %i, %i, %i, %i %li %li\n",
98     debugstr_a(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase,
99 lc.lcDevice, lc.lcPktRate, (UINT)lc.lcPktData, DUMPBITS(lc.lcPktData,bits),
100 (UINT)lc.lcPktMode, DUMPBITS(lc.lcPktMode,bits1), (UINT)lc.lcMoveMask,
101 DUMPBITS(lc.lcMoveMask,bits2), (INT)lc.lcBtnDnMask, (INT)lc.lcBtnUpMask,
102 (INT)lc.lcInOrgX, (INT)lc.lcInOrgY, (INT)lc.lcInOrgZ, lc.lcInExtX, lc.lcInExtY,
103 lc.lcInExtZ, lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ, lc.lcOutExtX,
104 lc.lcOutExtY, lc.lcOutExtZ, lc.lcSensX, lc.lcSensY, lc.lcSensZ, lc.lcSysMode,
105 lc.lcSysOrgX, lc.lcSysOrgY, lc.lcSysExtX, lc.lcSysExtY, lc.lcSysSensX,
106 lc.lcSysSensY);
107         TRACE("context: %s",mmsg);
108 }
109
110
111 /* Find an open context given the handle */
112 static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
113 {
114     LPOPENCONTEXT ptr = gOpenContexts;
115     while (ptr)
116     {
117         if (ptr->handle == hCtx) return ptr;
118         ptr = ptr->next;
119     }
120     return NULL;
121 }
122
123 static void LoadTablet()
124 {
125     TRACE("Initilizing the tablet to hwnd %p\n",hwndDefault);
126     gLoaded= TRUE;
127     pLoadTabletInfo(hwndDefault);
128 }
129
130 int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
131                              LPARAM lParam, BOOL send_always)
132 {
133     if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
134     {
135         TRACE("Posting message %x to %x\n",msg, (UINT)newcontext->hwndOwner);
136         return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
137     }
138     return 0;
139 }
140
141 static inline DWORD ScaleForContext(DWORD In, DWORD InOrg, DWORD InExt, DWORD
142                                     OutOrg, DWORD OutExt)
143 {
144     if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
145         return ((In - InOrg) * abs(OutExt) / abs(InExt)) + OutOrg;
146     else
147         return ((abs(InExt) - (In - InOrg))*abs(OutExt) / abs(InExt)) + OutOrg;
148 }
149
150 LPOPENCONTEXT FindOpenContext(HWND hwnd)
151 {
152     LPOPENCONTEXT ptr;
153
154     EnterCriticalSection(&csTablet);
155     ptr = gOpenContexts;
156     while (ptr)
157     {
158         TRACE("Trying Context %p (%p %p)\n",ptr->handle,hwnd,ptr->hwndOwner);
159         if (ptr->hwndOwner == hwnd) break;
160     }
161     LeaveCriticalSection(&csTablet);
162     return ptr;
163 }
164
165 LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
166 {
167     LPOPENCONTEXT ptr=NULL;
168
169     EnterCriticalSection(&csTablet);
170
171     ptr = gOpenContexts;
172     while (ptr)
173     {
174         TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
175
176         if (ptr->hwndOwner == hwnd)
177         {
178             int tgt;
179             if (!ptr->enabled)
180             {
181                 ptr = ptr->next;
182                 continue;
183             }
184
185             tgt = ptr->PacketsQueued;
186
187             packet->pkContext = ptr->handle;
188
189             /* translate packet data to the context */
190
191             /* Scale  as per documentation */
192             packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
193                                 ptr->context.lcInExtY, ptr->context.lcOutOrgY,
194                                 ptr->context.lcOutExtY);
195
196             packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
197                                 ptr->context.lcInExtX, ptr->context.lcOutOrgX,
198                                 ptr->context.lcOutExtX);
199
200             /* flip the Y axis */
201             if (ptr->context.lcOutExtY > 0)
202                 packet->pkY = ptr->context.lcOutExtY - packet->pkY;
203
204             DUMPPACKET(*packet);
205
206             if (tgt == ptr->QueueSize)
207             {
208                 TRACE("Queue Overflow %p\n",ptr->handle);
209                 ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
210             }
211             else
212             {
213                 TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
214                 memcpy(&ptr->PacketQueue[tgt], packet, sizeof
215                         (WTPACKET));
216                 ptr->PacketsQueued++;
217
218                 if (ptr->ActiveCursor != packet->pkCursor)
219                 {
220                     ptr->ActiveCursor = packet->pkCursor;
221                     if (ptr->context.lcOptions & CXO_CSRMESSAGES)
222                         TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
223                           (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
224                             FALSE);
225                 }
226             }
227             break;
228          }
229         ptr = ptr->next;
230     }
231     LeaveCriticalSection(&csTablet);
232     TRACE("Done (%p)\n",ptr);
233     return ptr;
234 }
235
236 int static inline CopyTabletData(LPVOID target, LPVOID src, INT size)
237 {
238     memcpy(target,src,size);
239     return(size);
240 }
241
242 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
243                                 LPWTPACKET *pkt)
244 {
245     int loop;
246     int index  = -1;
247     for (loop = 0; loop < context->PacketsQueued; loop++)
248         if (context->PacketQueue[loop].pkSerialNumber == wSerial)
249         {
250             index = loop;
251             *pkt = &context->PacketQueue[loop];
252             break;
253         }
254
255     TRACE("%i .. %i\n",context->PacketsQueued,index);
256
257     return index;
258 }
259
260
261 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
262                                     LPWTPACKET wtp)
263 {
264     LPBYTE ptr;
265     CHAR bits[100];
266
267     ptr = lpPkt;
268     TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData,bits));
269
270     if (context->context.lcPktData & PK_CONTEXT)
271         ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
272     if (context->context.lcPktData & PK_STATUS)
273         ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
274     if (context->context.lcPktData & PK_TIME)
275         ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
276     if (context->context.lcPktData & PK_CHANGED)
277         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
278     if (context->context.lcPktData & PK_SERIAL_NUMBER)
279         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(UINT));
280     if (context->context.lcPktData & PK_CURSOR)
281         ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
282     if (context->context.lcPktData & PK_BUTTONS)
283         ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
284     if (context->context.lcPktData & PK_X)
285         ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
286     if (context->context.lcPktData & PK_Y)
287         ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
288     if (context->context.lcPktData & PK_Z)
289         ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
290     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
291         ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
292     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
293         ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
294     if (context->context.lcPktData & PK_ORIENTATION)
295         ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
296     if (context->context.lcPktData & PK_ROTATION)
297         ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
298
299     /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
300     return ptr;
301 }
302
303 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
304 {
305     int rc = 0;
306
307     if (context->context.lcPktData & PK_CONTEXT)
308         rc +=sizeof(HCTX);
309     if (context->context.lcPktData & PK_STATUS)
310         rc +=sizeof(UINT);
311     if (context->context.lcPktData & PK_TIME)
312         rc += sizeof(LONG);
313     if (context->context.lcPktData & PK_CHANGED)
314         rc += sizeof(WTPKT);
315     if (context->context.lcPktData & PK_SERIAL_NUMBER)
316         rc += sizeof(UINT);
317     if (context->context.lcPktData & PK_CURSOR)
318         rc += sizeof(UINT);
319     if (context->context.lcPktData & PK_BUTTONS)
320         rc += sizeof(DWORD);
321     if (context->context.lcPktData & PK_X)
322         rc += sizeof(DWORD);
323     if (context->context.lcPktData & PK_Y)
324         rc += sizeof(DWORD);
325     if (context->context.lcPktData & PK_Z)
326         rc += sizeof(DWORD);
327     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
328         rc += sizeof(UINT);
329     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
330         rc += sizeof(UINT);
331     if (context->context.lcPktData & PK_ORIENTATION)
332         rc += sizeof(ORIENTATION);
333     if (context->context.lcPktData & PK_ROTATION)
334         rc += sizeof(ROTATION);
335
336     rc *= n;
337     memset(lpPkt,0,rc);
338 }
339
340
341 /***********************************************************************
342  *              WTInfoA (WINTAB32.20)
343  */
344 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
345 {
346     UINT result;
347     if (gLoaded == FALSE)
348          LoadTablet();
349
350     /*
351      *  Handle system extents here, as we can use user32.dll code to set them.
352      */
353     if(wCategory == WTI_DEFSYSCTX)
354     {
355         switch(nIndex)
356         {
357             case CTX_SYSEXTX:
358                 if(lpOutput != NULL)
359                     *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
360                 return sizeof(LONG);
361             case CTX_SYSEXTY:
362                 if(lpOutput != NULL)
363                     *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
364                 return sizeof(LONG);
365            /* No action, delegate to X11Drv */
366         }
367     }
368
369     result =  pWTInfoA( wCategory, nIndex, lpOutput );
370
371     /*
372      *  Handle system extents here, as we can use user32.dll code to set them.
373      */
374     if(wCategory == WTI_DEFSYSCTX && nIndex == 0)
375     {
376         LPLOGCONTEXTA lpCtx = (LPLOGCONTEXTA)lpOutput;
377         lpCtx->lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
378         lpCtx->lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
379     }
380     return result;
381 }
382
383 /***********************************************************************
384  *              WTInfoW (WINTAB32.1020)
385  */
386 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
387 {
388     FIXME("(%u, %u, %p): stub\n", wCategory, nIndex, lpOutput);
389
390     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
391
392     return 0;
393 }
394
395 /***********************************************************************
396  *              WTOpenA (WINTAB32.21)
397  */
398 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
399 {
400     LPOPENCONTEXT newcontext;
401
402     TRACE("(%p, %p, %u)\n", hWnd, lpLogCtx, fEnable);
403     DUMPCONTEXT(*lpLogCtx);
404
405     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
406     memcpy(&(newcontext->context),lpLogCtx,sizeof(LOGCONTEXTA));
407     newcontext->hwndOwner = hWnd;
408     newcontext->enabled = fEnable;
409     newcontext->ActiveCursor = -1;
410     newcontext->QueueSize = 10;
411     newcontext->PacketsQueued = 0;
412     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
413
414     EnterCriticalSection(&csTablet);
415     newcontext->handle = gTopContext++;
416     newcontext->next = gOpenContexts;
417     gOpenContexts = newcontext;
418     LeaveCriticalSection(&csTablet);
419
420     pAttachEventQueueToTablet(hWnd);
421
422     TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
423                       newcontext->context.lcStatus, TRUE);
424
425     newcontext->context.lcStatus = CXS_ONTOP;
426
427     TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
428                             (WPARAM)newcontext->handle,
429                             newcontext->context.lcStatus, TRUE);
430
431     return newcontext->handle;
432 }
433
434 /***********************************************************************
435  *              WTOpenW (WINTAB32.1021)
436  */
437 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
438 {
439     FIXME("(%p, %p, %u): stub\n", hWnd, lpLogCtx, fEnable);
440
441     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
442
443     return NULL;
444 }
445
446 /***********************************************************************
447  *              WTClose (WINTAB32.22)
448  */
449 BOOL WINAPI WTClose(HCTX hCtx)
450 {
451     LPOPENCONTEXT context,ptr;
452
453     TRACE("(%p)\n", hCtx);
454
455     EnterCriticalSection(&csTablet);
456
457     ptr = context = gOpenContexts;
458
459     while (context && (context->handle != hCtx))
460     {
461         ptr = context;
462         context = context->next;
463     }
464     if (!context)
465     {
466         LeaveCriticalSection(&csTablet);
467         return TRUE;
468     }
469
470     if (context == gOpenContexts)
471         gOpenContexts = context->next;
472     else
473         ptr->next = context->next;
474
475     LeaveCriticalSection(&csTablet);
476
477     TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
478                       context->context.lcStatus,TRUE);
479
480     HeapFree(GetProcessHeap(),0,context->PacketQueue);
481     HeapFree(GetProcessHeap(),0,context);
482
483     return TRUE;
484 }
485
486 /***********************************************************************
487  *              WTPacketsGet (WINTAB32.23)
488  */
489 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
490 {
491     int limit;
492     LPOPENCONTEXT context;
493     LPVOID ptr = lpPkts;
494
495     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
496
497     if (!hCtx)
498         return 0;
499
500     EnterCriticalSection(&csTablet);
501
502     context = TABLET_FindOpenContext(hCtx);
503
504     if (lpPkts != NULL)
505         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
506
507     if (context->PacketsQueued == 0)
508     {
509         LeaveCriticalSection(&csTablet);
510         return 0;
511     }
512
513     limit = min(cMaxPkts,context->PacketsQueued);
514
515     if(ptr != NULL)
516     {
517         int i = 0;
518         for(i = 0; i < limit; i++)
519             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
520     }
521
522
523     if (limit < context->PacketsQueued)
524     {
525         memmove(context->PacketQueue, &context->PacketQueue[limit],
526             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
527     }
528     context->PacketsQueued -= limit;
529     LeaveCriticalSection(&csTablet);
530
531     TRACE("Copied %i packets\n",limit);
532
533     return limit;
534 }
535
536 /***********************************************************************
537  *              WTPacket (WINTAB32.24)
538  */
539 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
540 {
541     int rc = 0;
542     LPOPENCONTEXT context;
543     LPWTPACKET    wtp;
544
545     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
546
547     if (!hCtx)
548         return 0;
549
550     EnterCriticalSection(&csTablet);
551
552     context = TABLET_FindOpenContext(hCtx);
553
554     rc = TABLET_FindPacket(context ,wSerial, &wtp);
555
556     if (rc >= 0)
557     {
558         if (lpPkt)
559            TABLET_CopyPacketData(context ,lpPkt, wtp);
560
561         if ((rc+1) < context->QueueSize)
562         {
563             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
564                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
565         }
566         context->PacketsQueued -= (rc+1);
567     }
568     LeaveCriticalSection(&csTablet);
569
570     TRACE("Returning %i\n",rc+1);
571     return rc+1;
572 }
573
574 /***********************************************************************
575  *              WTEnable (WINTAB32.40)
576  */
577 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
578 {
579     LPOPENCONTEXT context;
580
581     TRACE("(%p, %u)\n", hCtx, fEnable);
582
583     if (!hCtx) return 0;
584
585     EnterCriticalSection(&csTablet);
586     context = TABLET_FindOpenContext(hCtx);
587     context->enabled = fEnable;
588     LeaveCriticalSection(&csTablet);
589
590     return TRUE;
591 }
592
593 /***********************************************************************
594  *              WTOverlap (WINTAB32.41)
595  */
596 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
597 {
598     FIXME("(%p, %u): stub\n", hCtx, fToTop);
599
600     return TRUE;
601 }
602
603 /***********************************************************************
604  *              WTConfig (WINTAB32.61)
605  */
606 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
607 {
608     FIXME("(%p, %p): stub\n", hCtx, hWnd);
609
610     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
611
612     return FALSE;
613 }
614
615 /***********************************************************************
616  *              WTGetA (WINTAB32.61)
617  */
618 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
619 {
620     LPOPENCONTEXT context;
621
622     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
623
624     if (!hCtx) return 0;
625
626     EnterCriticalSection(&csTablet);
627     context = TABLET_FindOpenContext(hCtx);
628     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTA));
629     LeaveCriticalSection(&csTablet);
630
631     return TRUE;
632 }
633
634 /***********************************************************************
635  *              WTGetW (WINTAB32.1061)
636  */
637 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
638 {
639     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
640
641     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
642
643     return FALSE;
644 }
645
646 /***********************************************************************
647  *              WTSetA (WINTAB32.62)
648  */
649 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
650 {
651     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
652
653     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
654
655     return FALSE;
656 }
657
658 /***********************************************************************
659  *              WTSetW (WINTAB32.1062)
660  */
661 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
662 {
663     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
664
665     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
666
667     return FALSE;
668 }
669
670 /***********************************************************************
671  *              WTExtGet (WINTAB32.63)
672  */
673 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
674 {
675     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
676
677     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
678
679     return FALSE;
680 }
681
682 /***********************************************************************
683  *              WTExtSet (WINTAB32.64)
684  */
685 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
686 {
687     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
688
689     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
690
691     return FALSE;
692 }
693
694 /***********************************************************************
695  *              WTSave (WINTAB32.65)
696  */
697 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
698 {
699     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
700
701     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
702
703     return FALSE;
704 }
705
706 /***********************************************************************
707  *              WTRestore (WINTAB32.66)
708  */
709 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
710 {
711     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
712
713     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
714
715     return 0;
716 }
717
718 /***********************************************************************
719  *              WTPacketsPeek (WINTAB32.80)
720  */
721 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
722 {
723     int limit;
724     LPOPENCONTEXT context;
725     LPVOID ptr = lpPkts;
726
727     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
728
729     if (!hCtx || !lpPkts) return 0;
730
731     EnterCriticalSection(&csTablet);
732
733     context = TABLET_FindOpenContext(hCtx);
734
735     if (context->PacketsQueued == 0)
736     {
737         LeaveCriticalSection(&csTablet);
738         return 0;
739     }
740
741     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
742         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
743
744     LeaveCriticalSection(&csTablet);
745     TRACE("Copied %i packets\n",limit);
746     return limit;
747 }
748
749 /***********************************************************************
750  *              WTDataGet (WINTAB32.81)
751  */
752 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
753                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
754 {
755     LPOPENCONTEXT context;
756     LPVOID ptr = lpPkts;
757     INT bgn = 0;
758     INT end = 0;
759     INT num = 0;
760
761     TRACE("(%p, %u, %u, %d, %p, %p)\n",
762           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
763
764     if (!hCtx) return 0;
765
766     EnterCriticalSection(&csTablet);
767
768     context = TABLET_FindOpenContext(hCtx);
769
770     if (context->PacketsQueued == 0)
771     {
772         LeaveCriticalSection(&csTablet);
773         return 0;
774     }
775
776     while (bgn < context->PacketsQueued &&
777            context->PacketQueue[bgn].pkSerialNumber != wBegin)
778         bgn++;
779
780     end = bgn;
781     while (end < context->PacketsQueued &&
782            context->PacketQueue[end].pkSerialNumber != wEnd)
783         end++;
784
785     if ((bgn == end) && (end == context->PacketsQueued))
786     {
787         LeaveCriticalSection(&csTablet);
788         return 0;
789     }
790
791     for (num = bgn; num <= end; num++)
792         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
793
794     /* remove read packets */
795     if ((end+1) < context->PacketsQueued)
796         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
797                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
798
799     context->PacketsQueued -= ((end-bgn)+1);
800     *lpNPkts = ((end-bgn)+1);
801
802     LeaveCriticalSection(&csTablet);
803     TRACE("Copied %i packets\n",*lpNPkts);
804     return (end - bgn)+1;
805 }
806
807 /***********************************************************************
808  *              WTDataPeek (WINTAB32.82)
809  */
810 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
811                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
812 {
813     LPOPENCONTEXT context;
814     LPVOID ptr = lpPkts;
815     INT bgn = 0;
816     INT end = 0;
817     INT num = 0;
818
819     TRACE("(%p, %u, %u, %d, %p, %p)\n",
820           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
821
822     if (!hCtx || !lpPkts) return 0;
823
824     EnterCriticalSection(&csTablet);
825
826     context = TABLET_FindOpenContext(hCtx);
827
828     if (context->PacketsQueued == 0)
829     {
830         LeaveCriticalSection(&csTablet);
831         return 0;
832     }
833
834     while (bgn < context->PacketsQueued &&
835            context->PacketQueue[bgn].pkSerialNumber != wBegin)
836         bgn++;
837
838     end = bgn;
839     while (end < context->PacketsQueued &&
840            context->PacketQueue[end].pkSerialNumber != wEnd)
841         end++;
842
843     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
844     {
845         TRACE("%i %i %i \n", bgn, end, context->PacketsQueued);
846         LeaveCriticalSection(&csTablet);
847         return 0;
848     }
849
850     for (num = bgn; num <= end; num++)
851         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
852
853     *lpNPkts = ((end-bgn)+1);
854     LeaveCriticalSection(&csTablet);
855
856     TRACE("Copied %i packets\n",*lpNPkts);
857     return (end - bgn)+1;
858 }
859
860 /***********************************************************************
861  *              WTQueuePacketsEx (WINTAB32.200)
862  */
863 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
864 {
865     LPOPENCONTEXT context;
866
867     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
868
869     if (!hCtx) return 0;
870
871     EnterCriticalSection(&csTablet);
872
873     context = TABLET_FindOpenContext(hCtx);
874
875     if (context->PacketsQueued)
876     {
877         *lpOld = context->PacketQueue[0].pkSerialNumber;
878         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
879     }
880     else
881     {
882         TRACE("No packets\n");
883         LeaveCriticalSection(&csTablet);
884         return FALSE;
885     }
886     LeaveCriticalSection(&csTablet);
887
888     return TRUE;
889 }
890
891 /***********************************************************************
892  *              WTQueueSizeGet (WINTAB32.84)
893  */
894 int WINAPI WTQueueSizeGet(HCTX hCtx)
895 {
896     LPOPENCONTEXT context;
897     TRACE("(%p)\n", hCtx);
898
899     if (!hCtx) return 0;
900
901     EnterCriticalSection(&csTablet);
902     context = TABLET_FindOpenContext(hCtx);
903     LeaveCriticalSection(&csTablet);
904     return context->QueueSize;
905 }
906
907 /***********************************************************************
908  *              WTQueueSizeSet (WINTAB32.85)
909  */
910 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
911 {
912     LPOPENCONTEXT context;
913
914     TRACE("(%p, %d)\n", hCtx, nPkts);
915
916     if (!hCtx) return 0;
917
918     EnterCriticalSection(&csTablet);
919
920     context = TABLET_FindOpenContext(hCtx);
921
922     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
923                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
924
925     context->QueueSize = nPkts;
926     LeaveCriticalSection(&csTablet);
927
928     return nPkts;
929 }