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