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