gdiplus: Implement BMP encoding.
[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                 memcpy(&ptr->PacketQueue[tgt], packet, sizeof
218                         (WTPACKET));
219                 ptr->PacketsQueued++;
220
221                 if (ptr->ActiveCursor != packet->pkCursor)
222                 {
223                     ptr->ActiveCursor = packet->pkCursor;
224                     if (ptr->context.lcOptions & CXO_CSRMESSAGES)
225                         TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
226                           (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
227                             FALSE);
228                 }
229             }
230             break;
231          }
232         ptr = ptr->next;
233     }
234     LeaveCriticalSection(&csTablet);
235     TRACE("Done (%p)\n",ptr);
236     return ptr;
237 }
238
239 /*
240  * Flushes all packets from the queue.
241  */
242 static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
243 {
244     context->PacketsQueued = 0;
245 }
246
247 static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
248 {
249     memcpy(target,src,size);
250     return(size);
251 }
252
253 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
254                                 LPWTPACKET *pkt)
255 {
256     int loop;
257     int index  = -1;
258     for (loop = 0; loop < context->PacketsQueued; loop++)
259         if (context->PacketQueue[loop].pkSerialNumber == wSerial)
260         {
261             index = loop;
262             *pkt = &context->PacketQueue[loop];
263             break;
264         }
265
266     TRACE("%i .. %i\n",context->PacketsQueued,index);
267
268     return index;
269 }
270
271
272 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
273                                     LPWTPACKET wtp)
274 {
275     LPBYTE ptr;
276
277     ptr = lpPkt;
278     TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
279
280     if (context->context.lcPktData & PK_CONTEXT)
281         ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
282     if (context->context.lcPktData & PK_STATUS)
283         ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
284     if (context->context.lcPktData & PK_TIME)
285         ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
286     if (context->context.lcPktData & PK_CHANGED)
287         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
288     if (context->context.lcPktData & PK_SERIAL_NUMBER)
289         ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(UINT));
290     if (context->context.lcPktData & PK_CURSOR)
291         ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
292     if (context->context.lcPktData & PK_BUTTONS)
293         ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
294     if (context->context.lcPktData & PK_X)
295         ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
296     if (context->context.lcPktData & PK_Y)
297         ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
298     if (context->context.lcPktData & PK_Z)
299         ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
300     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
301         ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
302     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
303         ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
304     if (context->context.lcPktData & PK_ORIENTATION)
305         ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
306     if (context->context.lcPktData & PK_ROTATION)
307         ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
308
309     /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
310     return ptr;
311 }
312
313 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
314 {
315     int rc = 0;
316
317     if (context->context.lcPktData & PK_CONTEXT)
318         rc +=sizeof(HCTX);
319     if (context->context.lcPktData & PK_STATUS)
320         rc +=sizeof(UINT);
321     if (context->context.lcPktData & PK_TIME)
322         rc += sizeof(LONG);
323     if (context->context.lcPktData & PK_CHANGED)
324         rc += sizeof(WTPKT);
325     if (context->context.lcPktData & PK_SERIAL_NUMBER)
326         rc += sizeof(UINT);
327     if (context->context.lcPktData & PK_CURSOR)
328         rc += sizeof(UINT);
329     if (context->context.lcPktData & PK_BUTTONS)
330         rc += sizeof(DWORD);
331     if (context->context.lcPktData & PK_X)
332         rc += sizeof(DWORD);
333     if (context->context.lcPktData & PK_Y)
334         rc += sizeof(DWORD);
335     if (context->context.lcPktData & PK_Z)
336         rc += sizeof(DWORD);
337     if (context->context.lcPktData & PK_NORMAL_PRESSURE)
338         rc += sizeof(UINT);
339     if (context->context.lcPktData & PK_TANGENT_PRESSURE)
340         rc += sizeof(UINT);
341     if (context->context.lcPktData & PK_ORIENTATION)
342         rc += sizeof(ORIENTATION);
343     if (context->context.lcPktData & PK_ROTATION)
344         rc += sizeof(ROTATION);
345
346     rc *= n;
347     memset(lpPkt,0,rc);
348 }
349
350
351 UINT WINAPI WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
352 {
353     UINT result;
354
355     TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
356     if (gLoaded == FALSE)
357          LoadTablet();
358
359     /*
360      *  Handle system extents here, as we can use user32.dll code to set them.
361      */
362     if(wCategory == WTI_DEFSYSCTX)
363     {
364         switch(nIndex)
365         {
366             case CTX_SYSEXTX:
367                 if(lpOutput != NULL)
368                     *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
369                 return sizeof(LONG);
370             case CTX_SYSEXTY:
371                 if(lpOutput != NULL)
372                     *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
373                 return sizeof(LONG);
374            /* No action, delegate to X11Drv */
375         }
376     }
377
378     if (is_logcontext_category(wCategory) && nIndex == 0)
379     {
380         if (lpOutput)
381         {
382             LOGCONTEXTW buf;
383             pWTInfoW(wCategory, nIndex, &buf);
384
385             /*  Handle system extents here, as we can use user32.dll code to set them */
386             if(wCategory == WTI_DEFSYSCTX && nIndex == 0)
387             {
388                 buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
389                 buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
390             }
391
392             if (bUnicode)
393                 memcpy(lpOutput, &buf, sizeof(buf));
394             else
395                 LOGCONTEXTWtoA(&buf, lpOutput);
396         }
397
398         result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
399     }
400     else if (is_string_field(wCategory, nIndex) && !bUnicode)
401     {
402         int size = pWTInfoW(wCategory, nIndex, NULL);
403         WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
404         pWTInfoW(wCategory, nIndex, buf);
405         result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
406         HeapFree(GetProcessHeap(), 0, buf);
407     }
408     else
409         result =  pWTInfoW(wCategory, nIndex, lpOutput);
410
411     TRACE("returns %d\n", result);
412     return result;
413 }
414
415 /***********************************************************************
416  *              WTInfoA (WINTAB32.20)
417  */
418 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
419 {
420     return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
421 }
422
423
424 /***********************************************************************
425  *              WTInfoW (WINTAB32.1020)
426  */
427 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
428 {
429     return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
430 }
431
432 /***********************************************************************
433  *              WTOpenW (WINTAB32.2021)
434  */
435 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
436 {
437     LPOPENCONTEXT newcontext;
438
439     TRACE("(%p, %p, %u)\n", hWnd, lpLogCtx, fEnable);
440     DUMPCONTEXT(*lpLogCtx);
441
442     newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
443     memcpy(&(newcontext->context),lpLogCtx,sizeof(LOGCONTEXTW));
444     newcontext->hwndOwner = hWnd;
445     newcontext->enabled = fEnable;
446     newcontext->ActiveCursor = -1;
447     newcontext->QueueSize = 10;
448     newcontext->PacketsQueued = 0;
449     newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
450
451     EnterCriticalSection(&csTablet);
452     newcontext->handle = gTopContext++;
453     newcontext->next = gOpenContexts;
454     gOpenContexts = newcontext;
455     LeaveCriticalSection(&csTablet);
456
457     pAttachEventQueueToTablet(hWnd);
458
459     TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
460                       newcontext->context.lcStatus, TRUE);
461
462     newcontext->context.lcStatus = CXS_ONTOP;
463
464     TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
465                             (WPARAM)newcontext->handle,
466                             newcontext->context.lcStatus, TRUE);
467
468     return newcontext->handle;
469 }
470
471 /***********************************************************************
472  *              WTOpenA (WINTAB32.21)
473  */
474 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
475 {
476     LOGCONTEXTW logCtxW;
477
478     LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
479     return WTOpenW(hWnd, &logCtxW, fEnable);
480 }
481
482 /***********************************************************************
483  *              WTClose (WINTAB32.22)
484  */
485 BOOL WINAPI WTClose(HCTX hCtx)
486 {
487     LPOPENCONTEXT context,ptr;
488
489     TRACE("(%p)\n", hCtx);
490
491     EnterCriticalSection(&csTablet);
492
493     ptr = context = gOpenContexts;
494
495     while (context && (context->handle != hCtx))
496     {
497         ptr = context;
498         context = context->next;
499     }
500     if (!context)
501     {
502         LeaveCriticalSection(&csTablet);
503         return TRUE;
504     }
505
506     if (context == gOpenContexts)
507         gOpenContexts = context->next;
508     else
509         ptr->next = context->next;
510
511     LeaveCriticalSection(&csTablet);
512
513     TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
514                       context->context.lcStatus,TRUE);
515
516     HeapFree(GetProcessHeap(),0,context->PacketQueue);
517     HeapFree(GetProcessHeap(),0,context);
518
519     return TRUE;
520 }
521
522 /***********************************************************************
523  *              WTPacketsGet (WINTAB32.23)
524  */
525 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
526 {
527     int limit;
528     LPOPENCONTEXT context;
529     LPVOID ptr = lpPkts;
530
531     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
532
533     if (!hCtx)
534         return 0;
535
536     EnterCriticalSection(&csTablet);
537
538     context = TABLET_FindOpenContext(hCtx);
539
540     if (lpPkts != NULL)
541         TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
542
543     if (context->PacketsQueued == 0)
544     {
545         LeaveCriticalSection(&csTablet);
546         return 0;
547     }
548
549     limit = min(cMaxPkts,context->PacketsQueued);
550
551     if(ptr != NULL)
552     {
553         int i = 0;
554         for(i = 0; i < limit; i++)
555             ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
556     }
557
558
559     if (limit < context->PacketsQueued)
560     {
561         memmove(context->PacketQueue, &context->PacketQueue[limit],
562             (context->PacketsQueued - (limit))*sizeof(WTPACKET));
563     }
564     context->PacketsQueued -= limit;
565     LeaveCriticalSection(&csTablet);
566
567     TRACE("Copied %i packets\n",limit);
568
569     return limit;
570 }
571
572 /***********************************************************************
573  *              WTPacket (WINTAB32.24)
574  */
575 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
576 {
577     int rc = 0;
578     LPOPENCONTEXT context;
579     LPWTPACKET wtp = NULL;
580
581     TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
582
583     if (!hCtx)
584         return 0;
585
586     EnterCriticalSection(&csTablet);
587
588     context = TABLET_FindOpenContext(hCtx);
589
590     rc = TABLET_FindPacket(context ,wSerial, &wtp);
591
592     if (rc >= 0)
593     {
594         if (lpPkt)
595            TABLET_CopyPacketData(context ,lpPkt, wtp);
596
597         if ((rc+1) < context->QueueSize)
598         {
599             memmove(context->PacketQueue, &context->PacketQueue[rc+1],
600                 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
601         }
602         context->PacketsQueued -= (rc+1);
603     }
604     LeaveCriticalSection(&csTablet);
605
606     TRACE("Returning %i\n",rc+1);
607     return rc+1;
608 }
609
610 /***********************************************************************
611  *              WTEnable (WINTAB32.40)
612  */
613 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
614 {
615     LPOPENCONTEXT context;
616
617     TRACE("(%p, %u)\n", hCtx, fEnable);
618
619     if (!hCtx) return 0;
620
621     EnterCriticalSection(&csTablet);
622     context = TABLET_FindOpenContext(hCtx);
623     if(!fEnable)
624         TABLET_FlushQueue(context);
625     context->enabled = fEnable;
626     LeaveCriticalSection(&csTablet);
627
628     return TRUE;
629 }
630
631 /***********************************************************************
632  *              WTOverlap (WINTAB32.41)
633  */
634 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
635 {
636     FIXME("(%p, %u): stub\n", hCtx, fToTop);
637
638     return TRUE;
639 }
640
641 /***********************************************************************
642  *              WTConfig (WINTAB32.61)
643  */
644 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
645 {
646     FIXME("(%p, %p): stub\n", hCtx, hWnd);
647
648     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
649
650     return FALSE;
651 }
652
653 /***********************************************************************
654  *              WTGetA (WINTAB32.61)
655  */
656 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
657 {
658     LPOPENCONTEXT context;
659
660     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
661
662     if (!hCtx) return 0;
663
664     EnterCriticalSection(&csTablet);
665     context = TABLET_FindOpenContext(hCtx);
666     LOGCONTEXTWtoA(&context->context, lpLogCtx);
667     LeaveCriticalSection(&csTablet);
668
669     return TRUE;
670 }
671
672 /***********************************************************************
673  *              WTGetW (WINTAB32.1061)
674  */
675 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
676 {
677     LPOPENCONTEXT context;
678
679     TRACE("(%p, %p)\n", hCtx, lpLogCtx);
680
681     if (!hCtx) return 0;
682
683     EnterCriticalSection(&csTablet);
684     context = TABLET_FindOpenContext(hCtx);
685     memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
686     LeaveCriticalSection(&csTablet);
687
688     return TRUE;
689 }
690
691 /***********************************************************************
692  *              WTSetA (WINTAB32.62)
693  */
694 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
695 {
696     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
697
698     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
699
700     return FALSE;
701 }
702
703 /***********************************************************************
704  *              WTSetW (WINTAB32.1062)
705  */
706 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
707 {
708     FIXME("(%p, %p): stub\n", hCtx, lpLogCtx);
709
710     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
711
712     return FALSE;
713 }
714
715 /***********************************************************************
716  *              WTExtGet (WINTAB32.63)
717  */
718 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
719 {
720     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
721
722     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
723
724     return FALSE;
725 }
726
727 /***********************************************************************
728  *              WTExtSet (WINTAB32.64)
729  */
730 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
731 {
732     FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
733
734     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
735
736     return FALSE;
737 }
738
739 /***********************************************************************
740  *              WTSave (WINTAB32.65)
741  */
742 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
743 {
744     FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
745
746     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
747
748     return FALSE;
749 }
750
751 /***********************************************************************
752  *              WTRestore (WINTAB32.66)
753  */
754 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
755 {
756     FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
757
758     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
759
760     return 0;
761 }
762
763 /***********************************************************************
764  *              WTPacketsPeek (WINTAB32.80)
765  */
766 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
767 {
768     int limit;
769     LPOPENCONTEXT context;
770     LPVOID ptr = lpPkts;
771
772     TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
773
774     if (!hCtx || !lpPkts) return 0;
775
776     EnterCriticalSection(&csTablet);
777
778     context = TABLET_FindOpenContext(hCtx);
779
780     if (context->PacketsQueued == 0)
781     {
782         LeaveCriticalSection(&csTablet);
783         return 0;
784     }
785
786     for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
787         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
788
789     LeaveCriticalSection(&csTablet);
790     TRACE("Copied %i packets\n",limit);
791     return limit;
792 }
793
794 /***********************************************************************
795  *              WTDataGet (WINTAB32.81)
796  */
797 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
798                      int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
799 {
800     LPOPENCONTEXT context;
801     LPVOID ptr = lpPkts;
802     INT bgn = 0;
803     INT end = 0;
804     INT num = 0;
805
806     TRACE("(%p, %u, %u, %d, %p, %p)\n",
807           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
808
809     if (!hCtx) return 0;
810
811     EnterCriticalSection(&csTablet);
812
813     context = TABLET_FindOpenContext(hCtx);
814
815     if (context->PacketsQueued == 0)
816     {
817         LeaveCriticalSection(&csTablet);
818         return 0;
819     }
820
821     while (bgn < context->PacketsQueued &&
822            context->PacketQueue[bgn].pkSerialNumber != wBegin)
823         bgn++;
824
825     end = bgn;
826     while (end < context->PacketsQueued &&
827            context->PacketQueue[end].pkSerialNumber != wEnd)
828         end++;
829
830     if ((bgn == end) && (end == context->PacketsQueued))
831     {
832         LeaveCriticalSection(&csTablet);
833         return 0;
834     }
835
836     for (num = bgn; num <= end; num++)
837         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
838
839     /* remove read packets */
840     if ((end+1) < context->PacketsQueued)
841         memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
842                 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
843
844     context->PacketsQueued -= ((end-bgn)+1);
845     *lpNPkts = ((end-bgn)+1);
846
847     LeaveCriticalSection(&csTablet);
848     TRACE("Copied %i packets\n",*lpNPkts);
849     return (end - bgn)+1;
850 }
851
852 /***********************************************************************
853  *              WTDataPeek (WINTAB32.82)
854  */
855 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
856                       int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
857 {
858     LPOPENCONTEXT context;
859     LPVOID ptr = lpPkts;
860     INT bgn = 0;
861     INT end = 0;
862     INT num = 0;
863
864     TRACE("(%p, %u, %u, %d, %p, %p)\n",
865           hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
866
867     if (!hCtx || !lpPkts) return 0;
868
869     EnterCriticalSection(&csTablet);
870
871     context = TABLET_FindOpenContext(hCtx);
872
873     if (context->PacketsQueued == 0)
874     {
875         LeaveCriticalSection(&csTablet);
876         return 0;
877     }
878
879     while (bgn < context->PacketsQueued &&
880            context->PacketQueue[bgn].pkSerialNumber != wBegin)
881         bgn++;
882
883     end = bgn;
884     while (end < context->PacketsQueued &&
885            context->PacketQueue[end].pkSerialNumber != wEnd)
886         end++;
887
888     if (bgn == context->PacketsQueued ||  end == context->PacketsQueued)
889     {
890         TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
891         LeaveCriticalSection(&csTablet);
892         return 0;
893     }
894
895     for (num = bgn; num <= end; num++)
896         ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
897
898     *lpNPkts = ((end-bgn)+1);
899     LeaveCriticalSection(&csTablet);
900
901     TRACE("Copied %i packets\n",*lpNPkts);
902     return (end - bgn)+1;
903 }
904
905 /***********************************************************************
906  *              WTQueuePacketsEx (WINTAB32.200)
907  */
908 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
909 {
910     LPOPENCONTEXT context;
911
912     TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
913
914     if (!hCtx) return 0;
915
916     EnterCriticalSection(&csTablet);
917
918     context = TABLET_FindOpenContext(hCtx);
919
920     if (context->PacketsQueued)
921     {
922         *lpOld = context->PacketQueue[0].pkSerialNumber;
923         *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
924     }
925     else
926     {
927         TRACE("No packets\n");
928         LeaveCriticalSection(&csTablet);
929         return FALSE;
930     }
931     LeaveCriticalSection(&csTablet);
932
933     return TRUE;
934 }
935
936 /***********************************************************************
937  *              WTQueueSizeGet (WINTAB32.84)
938  */
939 int WINAPI WTQueueSizeGet(HCTX hCtx)
940 {
941     LPOPENCONTEXT context;
942     TRACE("(%p)\n", hCtx);
943
944     if (!hCtx) return 0;
945
946     EnterCriticalSection(&csTablet);
947     context = TABLET_FindOpenContext(hCtx);
948     LeaveCriticalSection(&csTablet);
949     return context->QueueSize;
950 }
951
952 /***********************************************************************
953  *              WTQueueSizeSet (WINTAB32.85)
954  */
955 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
956 {
957     LPOPENCONTEXT context;
958
959     TRACE("(%p, %d)\n", hCtx, nPkts);
960
961     if (!hCtx) return 0;
962
963     EnterCriticalSection(&csTablet);
964
965     context = TABLET_FindOpenContext(hCtx);
966
967     context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
968                         context->PacketQueue, sizeof(WTPACKET)*nPkts);
969
970     context->QueueSize = nPkts;
971     LeaveCriticalSection(&csTablet);
972
973     return nPkts;
974 }