Revert shell32 version to Win2K SP4 level.
[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 + 1 == ptr->QueueSize)
207             {
208                 TRACE("Queue Overflow %p\n",ptr->handle);
209                 packet->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,
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     if (gLoaded == FALSE)
347          LoadTablet();
348
349     return pWTInfoA( wCategory, nIndex, lpOutput );
350 }
351
352 /***********************************************************************
353  *              WTInfoW (WINTAB32.1020)
354  */
355 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
356 {
357     FIXME("(%u, %u, %p): stub\n", wCategory, nIndex, lpOutput);
358
359     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
360
361     return 0;
362 }
363
364 /***********************************************************************
365  *              WTOpenA (WINTAB32.21)
366  */
367 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
368 {
369     LPOPENCONTEXT newcontext;
370
371     TRACE("(%p, %p, %u)\n", hWnd, lpLogCtx, fEnable);
372     DUMPCONTEXT(*lpLogCtx);
373
374     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
375     memcpy(&(newcontext->context),lpLogCtx,sizeof(LOGCONTEXTA));
376     newcontext->hwndOwner = hWnd;
377     newcontext->enabled = fEnable;
378     newcontext->ActiveCursor = -1;
379     newcontext->QueueSize = 10;
380     newcontext->PacketsQueued = 0;
381     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
382
383     EnterCriticalSection(&csTablet);
384     newcontext->handle = gTopContext++;
385     newcontext->next = gOpenContexts;
386     gOpenContexts = newcontext;
387     LeaveCriticalSection(&csTablet);
388
389     pAttachEventQueueToTablet(hWnd);
390
391     TABLET_PostTabletMessage(newcontext, WT_CTXOPEN, (WPARAM)newcontext->handle,
392                       newcontext->context.lcStatus, TRUE);
393
394     newcontext->context.lcStatus = CXS_ONTOP;
395
396     TABLET_PostTabletMessage(newcontext, WT_CTXOVERLAP,
397                             (WPARAM)newcontext->handle,
398                             newcontext->context.lcStatus, TRUE);
399
400     return newcontext->handle;
401 }
402
403 /***********************************************************************
404  *              WTOpenW (WINTAB32.1021)
405  */
406 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
407 {
408     FIXME("(%p, %p, %u): stub\n", hWnd, lpLogCtx, fEnable);
409
410     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
411
412     return NULL;
413 }
414
415 /***********************************************************************
416  *              WTClose (WINTAB32.22)
417  */
418 BOOL WINAPI WTClose(HCTX hCtx)
419 {
420     LPOPENCONTEXT context,ptr;
421
422     TRACE("(%p)\n", hCtx);
423
424     EnterCriticalSection(&csTablet);
425
426     ptr = context = gOpenContexts;
427
428     while (context && (context->handle != hCtx))
429     {
430         ptr = context;
431         context = context->next;
432     }
433     if (!context)
434     {
435         LeaveCriticalSection(&csTablet);
436         return TRUE;
437     }
438
439     if (context == gOpenContexts)
440         gOpenContexts = context->next;
441     else
442         ptr->next = context->next;
443
444     LeaveCriticalSection(&csTablet);
445
446     TABLET_PostTabletMessage(context, WT_CTXCLOSE, (WPARAM)context->handle,
447                       context->context.lcStatus,TRUE);
448
449     HeapFree(GetProcessHeap(),0,context->PacketQueue);
450     HeapFree(GetProcessHeap(),0,context);
451
452     return TRUE;
453 }
454
455 /***********************************************************************
456  *              WTPacketsGet (WINTAB32.23)
457  */
458 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
459 {
460     int limit;
461     LPOPENCONTEXT context;
462     LPVOID ptr = lpPkts;
463
464     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
465
466     if (!hCtx)
467         return 0;
468
469     EnterCriticalSection(&csTablet);
470
471     context = TABLET_FindOpenContext(hCtx);
472
473     if (lpPkts != NULL)
474         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
475
476     if (context->PacketsQueued == 0)
477     {
478         LeaveCriticalSection(&csTablet);
479         return 0;
480     }
481
482     limit = min(cMaxPkts,context->PacketsQueued);
483
484     if(ptr != NULL)
485     {
486         int i = 0;
487         for(i = 0; i < limit; i++)
488             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
489     }
490
491
492     if (limit < context->PacketsQueued)
493     {
494         memmove(context->PacketQueue, &context->PacketQueue[limit],
495             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
496     }
497     context->PacketsQueued -= limit;
498     LeaveCriticalSection(&csTablet);
499
500     TRACE("Copied %i packets\n",limit);
501
502     return limit;
503 }
504
505 /***********************************************************************
506  *              WTPacket (WINTAB32.24)
507  */
508 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
509 {
510     int rc = 0;
511     LPOPENCONTEXT context;
512     LPWTPACKET    wtp;
513
514     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
515
516     if (!hCtx)
517         return 0;
518
519     EnterCriticalSection(&csTablet);
520
521     context = TABLET_FindOpenContext(hCtx);
522
523     rc = TABLET_FindPacket(context ,wSerial, &wtp);
524
525     if (rc >= 0)
526     {
527         if (lpPkt)
528            TABLET_CopyPacketData(context ,lpPkt, wtp);
529
530         if ((rc+1) < context->QueueSize)
531         {
532             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
533                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
534         }
535         context->PacketsQueued -= (rc+1);
536     }
537     LeaveCriticalSection(&csTablet);
538
539     TRACE("Returning %i\n",rc+1);
540     return rc+1;
541 }
542
543 /***********************************************************************
544  *              WTEnable (WINTAB32.40)
545  */
546 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
547 {
548     LPOPENCONTEXT context;
549
550     TRACE("(%p, %u)\n", hCtx, fEnable);
551
552     if (!hCtx) return 0;
553
554     EnterCriticalSection(&csTablet);
555     context = TABLET_FindOpenContext(hCtx);
556     context->enabled = fEnable;
557     LeaveCriticalSection(&csTablet);
558
559     return TRUE;
560 }
561
562 /***********************************************************************
563  *              WTOverlap (WINTAB32.41)
564  */
565 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
566 {
567     FIXME("(%p, %u): stub\n", hCtx, fToTop);
568
569     return TRUE;
570 }
571
572 /***********************************************************************
573  *              WTConfig (WINTAB32.61)
574  */
575 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
576 {
577     FIXME("(%p, %p): stub\n", hCtx, hWnd);
578
579     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
580
581     return FALSE;
582 }
583
584 /***********************************************************************
585  *              WTGetA (WINTAB32.61)
586  */
587 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
588 {
589     LPOPENCONTEXT context;
590
591     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
592
593     if (!hCtx) return 0;
594
595     EnterCriticalSection(&csTablet);
596     context = TABLET_FindOpenContext(hCtx);
597     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTA));
598     LeaveCriticalSection(&csTablet);
599
600     return TRUE;
601 }
602
603 /***********************************************************************
604  *              WTGetW (WINTAB32.1061)
605  */
606 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
607 {
608     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
609
610     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
611
612     return FALSE;
613 }
614
615 /***********************************************************************
616  *              WTSetA (WINTAB32.62)
617  */
618 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
619 {
620     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
621
622     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
623
624     return FALSE;
625 }
626
627 /***********************************************************************
628  *              WTSetW (WINTAB32.1062)
629  */
630 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
631 {
632     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
633
634     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
635
636     return FALSE;
637 }
638
639 /***********************************************************************
640  *              WTExtGet (WINTAB32.63)
641  */
642 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
643 {
644     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
645
646     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
647
648     return FALSE;
649 }
650
651 /***********************************************************************
652  *              WTExtSet (WINTAB32.64)
653  */
654 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
655 {
656     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
657
658     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
659
660     return FALSE;
661 }
662
663 /***********************************************************************
664  *              WTSave (WINTAB32.65)
665  */
666 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
667 {
668     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
669
670     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
671
672     return FALSE;
673 }
674
675 /***********************************************************************
676  *              WTRestore (WINTAB32.66)
677  */
678 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
679 {
680     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
681
682     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
683
684     return 0;
685 }
686
687 /***********************************************************************
688  *              WTPacketsPeek (WINTAB32.80)
689  */
690 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
691 {
692     int limit;
693     LPOPENCONTEXT context;
694     LPVOID ptr = lpPkts;
695
696     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
697
698     if (!hCtx || !lpPkts) return 0;
699
700     EnterCriticalSection(&csTablet);
701
702     context = TABLET_FindOpenContext(hCtx);
703
704     if (context->PacketsQueued == 0)
705     {
706         LeaveCriticalSection(&csTablet);
707         return 0;
708     }
709
710     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
711         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
712
713     LeaveCriticalSection(&csTablet);
714     TRACE("Copied %i packets\n",limit);
715     return limit;
716 }
717
718 /***********************************************************************
719  *              WTDataGet (WINTAB32.81)
720  */
721 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
722                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
723 {
724     LPOPENCONTEXT context;
725     LPVOID ptr = lpPkts;
726     INT bgn = 0;
727     INT end = 0;
728     INT num = 0;
729
730     TRACE("(%p, %u, %u, %d, %p, %p)\n",
731           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
732
733     if (!hCtx) return 0;
734
735     EnterCriticalSection(&csTablet);
736
737     context = TABLET_FindOpenContext(hCtx);
738
739     if (context->PacketsQueued == 0)
740     {
741         LeaveCriticalSection(&csTablet);
742         return 0;
743     }
744
745     while (bgn < context->PacketsQueued &&
746            context->PacketQueue[bgn].pkSerialNumber != wBegin)
747         bgn++;
748
749     end = bgn;
750     while (end < context->PacketsQueued &&
751            context->PacketQueue[end].pkSerialNumber != wEnd)
752         end++;
753
754     if ((bgn == end) && (end == context->PacketsQueued))
755     {
756         LeaveCriticalSection(&csTablet);
757         return 0;
758     }
759
760     for (num = bgn; num <= end; num++)
761         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
762
763     /* remove read packets */
764     if ((end+1) < context->PacketsQueued)
765         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
766                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
767
768     context->PacketsQueued -= ((end-bgn)+1);
769     *lpNPkts = ((end-bgn)+1);
770
771     LeaveCriticalSection(&csTablet);
772     TRACE("Copied %i packets\n",*lpNPkts);
773     return (end - bgn)+1;
774 }
775
776 /***********************************************************************
777  *              WTDataPeek (WINTAB32.82)
778  */
779 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
780                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
781 {
782     LPOPENCONTEXT context;
783     LPVOID ptr = lpPkts;
784     INT bgn = 0;
785     INT end = 0;
786     INT num = 0;
787
788     TRACE("(%p, %u, %u, %d, %p, %p)\n",
789           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
790
791     if (!hCtx || !lpPkts) return 0;
792
793     EnterCriticalSection(&csTablet);
794
795     context = TABLET_FindOpenContext(hCtx);
796
797     if (context->PacketsQueued == 0)
798     {
799         LeaveCriticalSection(&csTablet);
800         return 0;
801     }
802
803     while (bgn < context->PacketsQueued &&
804            context->PacketQueue[bgn].pkSerialNumber != wBegin)
805         bgn++;
806
807     end = bgn;
808     while (end < context->PacketsQueued &&
809            context->PacketQueue[end].pkSerialNumber != wEnd)
810         end++;
811
812     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
813     {
814         TRACE("%i %i %i \n", bgn, end, context->PacketsQueued);
815         LeaveCriticalSection(&csTablet);
816         return 0;
817     }
818
819     for (num = bgn; num <= end; num++)
820         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
821
822     *lpNPkts = ((end-bgn)+1);
823     LeaveCriticalSection(&csTablet);
824
825     TRACE("Copied %i packets\n",*lpNPkts);
826     return (end - bgn)+1;
827 }
828
829 /***********************************************************************
830  *              WTQueuePacketsEx (WINTAB32.200)
831  */
832 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
833 {
834     LPOPENCONTEXT context;
835
836     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
837
838     if (!hCtx) return 0;
839
840     EnterCriticalSection(&csTablet);
841
842     context = TABLET_FindOpenContext(hCtx);
843
844     if (context->PacketsQueued)
845     {
846         *lpOld = context->PacketQueue[0].pkSerialNumber;
847         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
848     }
849     else
850     {
851         TRACE("No packets\n");
852         LeaveCriticalSection(&csTablet);
853         return FALSE;
854     }
855     LeaveCriticalSection(&csTablet);
856
857     return TRUE;
858 }
859
860 /***********************************************************************
861  *              WTQueueSizeGet (WINTAB32.84)
862  */
863 int WINAPI WTQueueSizeGet(HCTX hCtx)
864 {
865     LPOPENCONTEXT context;
866     TRACE("(%p)\n", hCtx);
867
868     if (!hCtx) return 0;
869
870     EnterCriticalSection(&csTablet);
871     context = TABLET_FindOpenContext(hCtx);
872     LeaveCriticalSection(&csTablet);
873     return context->QueueSize;
874 }
875
876 /***********************************************************************
877  *              WTQueueSizeSet (WINTAB32.85)
878  */
879 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
880 {
881     LPOPENCONTEXT context;
882
883     TRACE("(%p, %d)\n", hCtx, nPkts);
884
885     if (!hCtx) return 0;
886
887     EnterCriticalSection(&csTablet);
888
889     context = TABLET_FindOpenContext(hCtx);
890
891     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
892                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
893
894     context->QueueSize = nPkts;
895     LeaveCriticalSection(&csTablet);
896
897     return nPkts;
898 }