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