Fixes and support for TypeInfo alignment values.
[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 || !lpPkts) return 0;
467
468     EnterCriticalSection(&csTablet);
469
470     context = TABLET_FindOpenContext(hCtx);
471     TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
472
473     if (context->PacketsQueued == 0)
474     {
475         LeaveCriticalSection(&csTablet);
476         return 0;
477     }
478
479     for(limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
480         ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
481
482     if (limit < context->PacketsQueued)
483     {
484         memcpy(context->PacketQueue, &context->PacketQueue[limit],
485             (context->QueueSize - (limit))*sizeof(WTPACKET));
486     }
487     context->PacketsQueued -= limit;
488     LeaveCriticalSection(&csTablet);
489
490     TRACE("Copied %i packets\n",limit);
491
492     return limit;
493 }
494
495 /***********************************************************************
496  *              WTPacket (WINTAB32.24)
497  */
498 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
499 {
500     int rc = 0;
501     LPOPENCONTEXT context;
502     LPWTPACKET    wtp;
503
504     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
505
506     if (!hCtx) return 0;
507
508     EnterCriticalSection(&csTablet);
509
510     context = TABLET_FindOpenContext(hCtx);
511
512     rc = TABLET_FindPacket(context ,wSerial, &wtp);
513
514     if (rc >= 0)
515     {
516         if (lpPkt)
517            TABLET_CopyPacketData(context ,lpPkt, wtp);
518
519         if ((rc+1) < context->QueueSize)
520         {
521             memcpy(context->PacketQueue, &context->PacketQueue[rc+1],
522                 (context->QueueSize - (rc+1))*sizeof(WTPACKET));
523         }
524         context->PacketsQueued -= (rc+1);
525     }
526     LeaveCriticalSection(&csTablet);
527
528     TRACE("Returning %i\n",rc+1);
529     return rc+1;
530 }
531
532 /***********************************************************************
533  *              WTEnable (WINTAB32.40)
534  */
535 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
536 {
537     LPOPENCONTEXT context;
538
539     TRACE("(%p, %u)\n", hCtx, fEnable);
540
541     if (!hCtx) return 0;
542
543     EnterCriticalSection(&csTablet);
544     context = TABLET_FindOpenContext(hCtx);
545     context->enabled = fEnable;
546     LeaveCriticalSection(&csTablet);
547
548     return TRUE;
549 }
550
551 /***********************************************************************
552  *              WTOverlap (WINTAB32.41)
553  */
554 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
555 {
556     FIXME("(%p, %u): stub\n", hCtx, fToTop);
557
558     return TRUE;
559 }
560
561 /***********************************************************************
562  *              WTConfig (WINTAB32.61)
563  */
564 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
565 {
566     FIXME("(%p, %p): stub\n", hCtx, hWnd);
567
568     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
569
570     return FALSE;
571 }
572
573 /***********************************************************************
574  *              WTGetA (WINTAB32.61)
575  */
576 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
577 {
578     LPOPENCONTEXT context;
579
580     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
581
582     if (!hCtx) return 0;
583
584     EnterCriticalSection(&csTablet);
585     context = TABLET_FindOpenContext(hCtx);
586     memcpy(lpLogCtx,&context->context,sizeof(LOGCONTEXTA));
587     LeaveCriticalSection(&csTablet);
588
589     return TRUE;
590 }
591
592 /***********************************************************************
593  *              WTGetW (WINTAB32.1061)
594  */
595 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
596 {
597     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
598
599     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
600
601     return FALSE;
602 }
603
604 /***********************************************************************
605  *              WTSetA (WINTAB32.62)
606  */
607 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
608 {
609     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
610
611     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
612
613     return FALSE;
614 }
615
616 /***********************************************************************
617  *              WTSetW (WINTAB32.1062)
618  */
619 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
620 {
621     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
622
623     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
624
625     return FALSE;
626 }
627
628 /***********************************************************************
629  *              WTExtGet (WINTAB32.63)
630  */
631 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
632 {
633     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
634
635     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
636
637     return FALSE;
638 }
639
640 /***********************************************************************
641  *              WTExtSet (WINTAB32.64)
642  */
643 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
644 {
645     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
646
647     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
648
649     return FALSE;
650 }
651
652 /***********************************************************************
653  *              WTSave (WINTAB32.65)
654  */
655 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
656 {
657     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
658
659     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
660
661     return FALSE;
662 }
663
664 /***********************************************************************
665  *              WTRestore (WINTAB32.66)
666  */
667 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
668 {
669     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
670
671     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
672
673     return 0;
674 }
675
676 /***********************************************************************
677  *              WTPacketsPeek (WINTAB32.80)
678  */
679 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
680 {
681     int limit;
682     LPOPENCONTEXT context;
683     LPVOID ptr = lpPkts;
684
685     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
686
687     if (!hCtx || !lpPkts) return 0;
688
689     EnterCriticalSection(&csTablet);
690
691     context = TABLET_FindOpenContext(hCtx);
692
693     if (context->PacketsQueued == 0)
694     {
695         LeaveCriticalSection(&csTablet);
696         return 0;
697     }
698
699     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
700         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
701
702     LeaveCriticalSection(&csTablet);
703     TRACE("Copied %i packets\n",limit);
704     return limit;
705 }
706
707 /***********************************************************************
708  *              WTDataGet (WINTAB32.81)
709  */
710 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
711                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
712 {
713     LPOPENCONTEXT context;
714     LPVOID ptr = lpPkts;
715     UINT bgn = 0;
716     UINT end = 0;
717     UINT num = 0;
718
719     TRACE("(%p, %u, %u, %d, %p, %p)\n",
720           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
721
722     if (!hCtx) return 0;
723
724     EnterCriticalSection(&csTablet);
725
726     context = TABLET_FindOpenContext(hCtx);
727
728     if (context->PacketsQueued == 0)
729     {
730         LeaveCriticalSection(&csTablet);
731         return 0;
732     }
733
734     while (bgn < context->PacketsQueued &&
735            context->PacketQueue[bgn].pkSerialNumber != wBegin)
736         bgn++;
737
738     end = bgn;
739     while (end < context->PacketsQueued &&
740            context->PacketQueue[end].pkSerialNumber != wEnd)
741         end++;
742
743     if (bgn == end == context->PacketsQueued)
744     {
745         LeaveCriticalSection(&csTablet);
746         return 0;
747     }
748
749     for (num = bgn; num <= end; num++)
750         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[end]);
751
752     /* remove read packets */
753     if ((end+1) < context->PacketsQueued)
754         memcpy( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
755                 (context->PacketsQueued - ((end-bgn)+1)) * sizeof (WTPACKET));
756
757     context->PacketsQueued -= ((end-bgn)+1);
758     *lpNPkts = ((end-bgn)+1);
759
760     LeaveCriticalSection(&csTablet);
761     TRACE("Copied %i packets\n",*lpNPkts);
762     return (end - bgn)+1;
763 }
764
765 /***********************************************************************
766  *              WTDataPeek (WINTAB32.82)
767  */
768 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
769                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
770 {
771     LPOPENCONTEXT context;
772     LPVOID ptr = lpPkts;
773     UINT bgn = 0;
774     UINT end = 0;
775     UINT num = 0;
776
777     TRACE("(%p, %u, %u, %d, %p, %p)\n",
778           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
779
780     if (!hCtx) return 0;
781
782     EnterCriticalSection(&csTablet);
783
784     context = TABLET_FindOpenContext(hCtx);
785
786     if (context->PacketsQueued == 0)
787     {
788         LeaveCriticalSection(&csTablet);
789         return 0;
790     }
791
792     while (bgn < context->PacketsQueued &&
793            context->PacketQueue[bgn].pkSerialNumber != wBegin)
794         bgn++;
795
796     end = bgn;
797     while (end < context->PacketsQueued &&
798            context->PacketQueue[end].pkSerialNumber != wEnd)
799         end++;
800
801     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
802     {
803         TRACE("%i %i %i \n", bgn, end, context->PacketsQueued);
804         LeaveCriticalSection(&csTablet);
805         return 0;
806     }
807
808     for (num = bgn; num <= end; num++)
809         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[end]);
810
811     *lpNPkts = ((end-bgn)+1);
812     LeaveCriticalSection(&csTablet);
813
814     TRACE("Copied %i packets\n",*lpNPkts);
815     return (end - bgn)+1;
816 }
817
818 /***********************************************************************
819  *              WTQueuePacketsEx (WINTAB32.200)
820  */
821 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
822 {
823     LPOPENCONTEXT context;
824
825     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
826
827     if (!hCtx) return 0;
828
829     EnterCriticalSection(&csTablet);
830
831     context = TABLET_FindOpenContext(hCtx);
832
833     if (context->PacketsQueued)
834     {
835         *lpOld = context->PacketQueue[0].pkSerialNumber;
836         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
837     }
838     else
839     {
840         TRACE("No packets\n");
841         LeaveCriticalSection(&csTablet);
842         return FALSE;
843     }
844     LeaveCriticalSection(&csTablet);
845
846     return TRUE;
847 }
848
849 /***********************************************************************
850  *              WTQueueSizeGet (WINTAB32.84)
851  */
852 int WINAPI WTQueueSizeGet(HCTX hCtx)
853 {
854     LPOPENCONTEXT context;
855     TRACE("(%p)\n", hCtx);
856
857     if (!hCtx) return 0;
858
859     EnterCriticalSection(&csTablet);
860     context = TABLET_FindOpenContext(hCtx);
861     LeaveCriticalSection(&csTablet);
862     return context->QueueSize;
863 }
864
865 /***********************************************************************
866  *              WTQueueSizeSet (WINTAB32.85)
867  */
868 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
869 {
870     LPOPENCONTEXT context;
871
872     TRACE("(%p, %d)\n", hCtx, nPkts);
873
874     if (!hCtx) return 0;
875
876     EnterCriticalSection(&csTablet);
877
878     context = TABLET_FindOpenContext(hCtx);
879
880     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
881                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
882
883     context->QueueSize = nPkts;
884     LeaveCriticalSection(&csTablet);
885
886     return nPkts;
887 }