server: Support unbound console input device.
[wine.git] / dlls / wintab32 / context.c
blob2da0462193411c9a9b95bd07e3b92d12a01d0e98
1 /*
2 * Tablet Context
4 * Copyright 2002 Patrik Stridvall
5 * Copyright 2003 CodeWeavers, Aric Stewart
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.
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.
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
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winerror.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winnls.h"
32 #include "wintab.h"
33 #include "wintab_internal.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(wintab32);
40 * Documentation found at
41 * http://www.csl.sony.co.jp/projects/ar/restricted/wintabl.html
44 static LPOPENCONTEXT gOpenContexts;
45 static HCTX gTopContext = (HCTX)0xc00;
47 static void LOGCONTEXTAtoW(const LOGCONTEXTA *in, LOGCONTEXTW *out)
49 MultiByteToWideChar(CP_ACP, 0, in->lcName, -1, out->lcName, LCNAMELEN);
50 out->lcName[LCNAMELEN - 1] = 0;
51 /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
52 memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTA) - FIELD_OFFSET(LOGCONTEXTA, lcOptions));
55 static void LOGCONTEXTWtoA(const LOGCONTEXTW *in, LOGCONTEXTA *out)
57 WideCharToMultiByte(CP_ACP, 0, in->lcName, LCNAMELEN, out->lcName, LCNAMELEN, NULL, NULL);
58 out->lcName[LCNAMELEN - 1] = 0;
59 /* we use the fact that the fields after lcName are the same in LOGCONTEXTA and W */
60 memcpy(&out->lcOptions, &in->lcOptions, sizeof(LOGCONTEXTW) - FIELD_OFFSET(LOGCONTEXTW, lcOptions));
63 static BOOL is_logcontext_category(UINT wCategory)
65 return wCategory == WTI_DEFSYSCTX || wCategory == WTI_DEFCONTEXT || wCategory == WTI_DDCTXS;
68 static BOOL is_string_field(UINT wCategory, UINT nIndex)
70 if (wCategory == WTI_INTERFACE && nIndex == IFC_WINTABID)
71 return TRUE;
72 if (is_logcontext_category(wCategory) && nIndex == CTX_NAME)
73 return TRUE;
74 if ((wCategory >= WTI_CURSORS && wCategory <= WTI_CURSORS + 9) &&
75 (nIndex == CSR_NAME || nIndex == CSR_BTNNAMES))
76 return TRUE;
77 if (wCategory == WTI_DEVICES && (nIndex == DVC_NAME || nIndex == DVC_PNPID))
78 return TRUE;
79 return FALSE;
82 static const char* DUMPBITS(int x)
84 char buf[200];
85 buf[0] = 0;
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 return wine_dbg_sprintf("{%s}",buf);
103 static inline void DUMPPACKET(WTPACKET packet)
105 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",
106 packet.pkContext, packet.pkStatus, packet.pkTime, packet.pkChanged, packet.pkSerialNumber,
107 packet.pkCursor, packet.pkButtons, packet.pkX, packet.pkY, packet.pkZ,
108 packet.pkNormalPressure, packet.pkTangentPressure,
109 packet.pkOrientation.orAzimuth, packet.pkOrientation.orAltitude, packet.pkOrientation.orTwist,
110 packet.pkRotation.roPitch, packet.pkRotation.roRoll, packet.pkRotation.roYaw);
113 static inline void DUMPCONTEXT(LOGCONTEXTW lc)
115 TRACE("Name: %s, Options: %x, Status: %x, Locks: %x, MsgBase: %x, Device: %x\n",
116 wine_dbgstr_w(lc.lcName), lc.lcOptions, lc.lcStatus, lc.lcLocks, lc.lcMsgBase, lc.lcDevice);
117 TRACE("PktRate %x\n", lc.lcPktRate);
118 TRACE("PktData 0x%04x %s\n", lc.lcPktData, DUMPBITS(lc.lcPktData));
119 TRACE("PktMode 0x%04x %s\n", lc.lcPktMode, DUMPBITS(lc.lcPktMode));
120 TRACE("MovMask 0x%04x %s\n", lc.lcMoveMask, DUMPBITS(lc.lcMoveMask));
121 TRACE("BtnDnMask: %x, BtnUpMask: %x\n", lc.lcBtnDnMask, lc.lcBtnUpMask);
122 TRACE("InOrgX: %i, InOrgY: %i, InOrgZ: %i\n", lc.lcInOrgX, lc.lcInOrgY, lc.lcInOrgZ);
123 TRACE("InExtX: %i, InExtY: %i, InExtZ: %i\n", lc.lcInExtX, lc.lcInExtY, lc.lcInExtZ);
124 TRACE("OutOrgX: %i, OutOrgY: %i, OutOrgZ: %i\n", lc.lcOutOrgX, lc.lcOutOrgY, lc.lcOutOrgZ);
125 TRACE("OutExtX: %i, OutExtY: %i, OutExtZ: %i\n", lc.lcOutExtX, lc.lcOutExtY, lc.lcOutExtZ);
126 TRACE("SensX: %i, SensY: %i, SensZ: %i\n", lc.lcSensX, lc.lcSensY, lc.lcSensZ);
127 TRACE("SysMode: %i\n", lc.lcSysMode);
128 TRACE("SysOrgX: %i, SysOrgY: %i\n", lc.lcSysOrgX, lc.lcSysOrgY);
129 TRACE("SysExtX: %i, SysExtY: %i\n", lc.lcSysExtX, lc.lcSysExtY);
130 TRACE("SysSensX: %i, SysSensY: %i\n", lc.lcSysSensX, lc.lcSysSensY);
134 /* Find an open context given the handle */
135 static LPOPENCONTEXT TABLET_FindOpenContext(HCTX hCtx)
137 LPOPENCONTEXT ptr = gOpenContexts;
138 while (ptr)
140 if (ptr->handle == hCtx) return ptr;
141 ptr = ptr->next;
143 return NULL;
146 static inline BOOL LoadTablet(void)
148 static enum {TI_START = 0, TI_OK, TI_FAIL} loaded = TI_START;
150 if (loaded == TI_START)
152 if (pLoadTabletInfo && pLoadTabletInfo(hwndDefault))
154 TRACE("Initialized the tablet to hwnd %p\n", hwndDefault);
155 loaded = TI_OK;
157 else
159 TRACE("Failed to initialize the tablet to hwnd %p\n", hwndDefault);
160 loaded = TI_FAIL;
164 return loaded == TI_OK;
167 int TABLET_PostTabletMessage(LPOPENCONTEXT newcontext, UINT msg, WPARAM wParam,
168 LPARAM lParam, BOOL send_always)
170 if ((send_always) || (newcontext->context.lcOptions & CXO_MESSAGES))
172 TRACE("Posting message %x to %p\n",msg, newcontext->hwndOwner);
173 return PostMessageA(newcontext->hwndOwner, msg, wParam, lParam);
175 return 0;
178 static inline DWORD ScaleForContext(DWORD In, LONG InOrg, LONG InExt, LONG OutOrg, LONG OutExt)
180 if (((InExt > 0 )&&(OutExt > 0)) || ((InExt<0) && (OutExt < 0)))
181 return MulDiv(In - InOrg, abs(OutExt), abs(InExt)) + OutOrg;
182 else
183 return MulDiv(abs(InExt) - (In - InOrg), abs(OutExt), abs(InExt)) + OutOrg;
186 LPOPENCONTEXT AddPacketToContextQueue(LPWTPACKET packet, HWND hwnd)
188 LPOPENCONTEXT ptr=NULL;
190 EnterCriticalSection(&csTablet);
192 ptr = gOpenContexts;
193 while (ptr)
195 TRACE("Trying Queue %p (%p %p)\n", ptr->handle, hwnd, ptr->hwndOwner);
197 if (ptr->hwndOwner == hwnd)
199 int tgt;
200 if (!ptr->enabled)
202 ptr = ptr->next;
203 continue;
206 tgt = ptr->PacketsQueued;
208 packet->pkContext = ptr->handle;
210 /* translate packet data to the context */
211 packet->pkChanged = packet->pkChanged & ptr->context.lcPktData;
213 /* Scale as per documentation */
214 packet->pkY = ScaleForContext(packet->pkY, ptr->context.lcInOrgY,
215 ptr->context.lcInExtY, ptr->context.lcOutOrgY,
216 ptr->context.lcOutExtY);
218 packet->pkX = ScaleForContext(packet->pkX, ptr->context.lcInOrgX,
219 ptr->context.lcInExtX, ptr->context.lcOutOrgX,
220 ptr->context.lcOutExtX);
222 /* flip the Y axis */
223 if (ptr->context.lcOutExtY > 0)
224 packet->pkY = ptr->context.lcOutExtY - packet->pkY;
225 else if (ptr->context.lcOutExtY < 0)
227 int y = ptr->context.lcOutExtY + packet->pkY;
228 packet->pkY = abs(y);
231 DUMPPACKET(*packet);
233 if (tgt == ptr->QueueSize)
235 TRACE("Queue Overflow %p\n",ptr->handle);
236 ptr->PacketQueue[tgt-1].pkStatus |= TPS_QUEUE_ERR;
238 else
240 TRACE("Placed in queue %p index %i\n",ptr->handle,tgt);
241 ptr->PacketQueue[tgt] = *packet;
242 ptr->PacketsQueued++;
244 if (ptr->ActiveCursor != packet->pkCursor)
246 ptr->ActiveCursor = packet->pkCursor;
247 if (ptr->context.lcOptions & CXO_CSRMESSAGES)
248 TABLET_PostTabletMessage(ptr, _WT_CSRCHANGE(ptr->context.lcMsgBase),
249 (WPARAM)packet->pkSerialNumber, (LPARAM)ptr->handle,
250 FALSE);
253 break;
255 ptr = ptr->next;
257 LeaveCriticalSection(&csTablet);
258 TRACE("Done (%p)\n",ptr);
259 return ptr;
263 * Flushes all packets from the queue.
265 static inline void TABLET_FlushQueue(LPOPENCONTEXT context)
267 context->PacketsQueued = 0;
270 static inline int CopyTabletData(LPVOID target, LPVOID src, INT size)
272 memcpy(target,src,size);
273 return(size);
276 static INT TABLET_FindPacket(LPOPENCONTEXT context, UINT wSerial,
277 LPWTPACKET *pkt)
279 int loop;
280 int index = -1;
281 for (loop = 0; loop < context->PacketsQueued; loop++)
282 if (context->PacketQueue[loop].pkSerialNumber == wSerial)
284 index = loop;
285 *pkt = &context->PacketQueue[loop];
286 break;
289 TRACE("%i .. %i\n",context->PacketsQueued,index);
291 return index;
295 static LPVOID TABLET_CopyPacketData(LPOPENCONTEXT context, LPVOID lpPkt,
296 LPWTPACKET wtp)
298 LPBYTE ptr;
300 ptr = lpPkt;
301 TRACE("Packet Bits %s\n",DUMPBITS(context->context.lcPktData));
303 if (context->context.lcPktData & PK_CONTEXT)
304 ptr+=CopyTabletData(ptr,&wtp->pkContext,sizeof(HCTX));
305 if (context->context.lcPktData & PK_STATUS)
306 ptr+=CopyTabletData(ptr,&wtp->pkStatus,sizeof(UINT));
307 if (context->context.lcPktData & PK_TIME)
308 ptr+=CopyTabletData(ptr,&wtp->pkTime,sizeof(LONG));
309 if (context->context.lcPktData & PK_CHANGED)
310 ptr+=CopyTabletData(ptr,&wtp->pkChanged,sizeof(WTPKT));
311 if (context->context.lcPktData & PK_SERIAL_NUMBER)
312 ptr+=CopyTabletData(ptr,&wtp->pkSerialNumber,sizeof(UINT));
313 if (context->context.lcPktData & PK_CURSOR)
314 ptr+=CopyTabletData(ptr,&wtp->pkCursor,sizeof(UINT));
315 if (context->context.lcPktData & PK_BUTTONS)
316 ptr+=CopyTabletData(ptr,&wtp->pkButtons,sizeof(DWORD));
317 if (context->context.lcPktData & PK_X)
318 ptr+=CopyTabletData(ptr,&wtp->pkX,sizeof(DWORD));
319 if (context->context.lcPktData & PK_Y)
320 ptr+=CopyTabletData(ptr,&wtp->pkY,sizeof(DWORD));
321 if (context->context.lcPktData & PK_Z)
322 ptr+=CopyTabletData(ptr,&wtp->pkZ,sizeof(DWORD));
323 if (context->context.lcPktData & PK_NORMAL_PRESSURE)
324 ptr+=CopyTabletData(ptr,&wtp->pkNormalPressure,sizeof(UINT));
325 if (context->context.lcPktData & PK_TANGENT_PRESSURE)
326 ptr+=CopyTabletData(ptr,&wtp->pkTangentPressure,sizeof(UINT));
327 if (context->context.lcPktData & PK_ORIENTATION)
328 ptr+=CopyTabletData(ptr,&wtp->pkOrientation,sizeof(ORIENTATION));
329 if (context->context.lcPktData & PK_ROTATION)
330 ptr+=CopyTabletData(ptr,&wtp->pkRotation,sizeof(ROTATION));
332 /*TRACE("Copied %i bytes\n",(INT)ptr - (INT)lpPkt); */
333 return ptr;
336 static VOID TABLET_BlankPacketData(LPOPENCONTEXT context, LPVOID lpPkt, INT n)
338 int rc = 0;
340 if (context->context.lcPktData & PK_CONTEXT)
341 rc +=sizeof(HCTX);
342 if (context->context.lcPktData & PK_STATUS)
343 rc +=sizeof(UINT);
344 if (context->context.lcPktData & PK_TIME)
345 rc += sizeof(LONG);
346 if (context->context.lcPktData & PK_CHANGED)
347 rc += sizeof(WTPKT);
348 if (context->context.lcPktData & PK_SERIAL_NUMBER)
349 rc += sizeof(UINT);
350 if (context->context.lcPktData & PK_CURSOR)
351 rc += sizeof(UINT);
352 if (context->context.lcPktData & PK_BUTTONS)
353 rc += sizeof(DWORD);
354 if (context->context.lcPktData & PK_X)
355 rc += sizeof(DWORD);
356 if (context->context.lcPktData & PK_Y)
357 rc += sizeof(DWORD);
358 if (context->context.lcPktData & PK_Z)
359 rc += sizeof(DWORD);
360 if (context->context.lcPktData & PK_NORMAL_PRESSURE)
361 rc += sizeof(UINT);
362 if (context->context.lcPktData & PK_TANGENT_PRESSURE)
363 rc += sizeof(UINT);
364 if (context->context.lcPktData & PK_ORIENTATION)
365 rc += sizeof(ORIENTATION);
366 if (context->context.lcPktData & PK_ROTATION)
367 rc += sizeof(ROTATION);
369 rc *= n;
370 memset(lpPkt,0,rc);
374 static UINT WTInfoT(UINT wCategory, UINT nIndex, LPVOID lpOutput, BOOL bUnicode)
376 UINT result;
378 if (!LoadTablet()) return 0;
380 TRACE("(%d, %d, %p, %d)\n", wCategory, nIndex, lpOutput, bUnicode);
383 * Handle system extents here, as we can use user32.dll code to set them.
385 if(wCategory == WTI_DEFSYSCTX)
387 switch(nIndex)
389 case CTX_SYSEXTX:
390 if(lpOutput != NULL)
391 *(LONG*)lpOutput = GetSystemMetrics(SM_CXSCREEN);
392 return sizeof(LONG);
393 case CTX_SYSEXTY:
394 if(lpOutput != NULL)
395 *(LONG*)lpOutput = GetSystemMetrics(SM_CYSCREEN);
396 return sizeof(LONG);
397 /* No action, delegate to X11Drv */
401 if (is_logcontext_category(wCategory) && nIndex == 0)
403 if (lpOutput)
405 LOGCONTEXTW buf;
406 pWTInfoW(wCategory, nIndex, &buf);
408 /* Handle system extents here, as we can use user32.dll code to set them */
409 if(wCategory == WTI_DEFSYSCTX)
411 buf.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
412 buf.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
415 if (bUnicode)
416 memcpy(lpOutput, &buf, sizeof(buf));
417 else
418 LOGCONTEXTWtoA(&buf, lpOutput);
421 result = bUnicode ? sizeof(LOGCONTEXTW) : sizeof(LOGCONTEXTA);
423 else if (is_string_field(wCategory, nIndex) && !bUnicode)
425 int size = pWTInfoW(wCategory, nIndex, NULL);
426 WCHAR *buf = HeapAlloc(GetProcessHeap(), 0, size);
427 pWTInfoW(wCategory, nIndex, buf);
428 result = WideCharToMultiByte(CP_ACP, 0, buf, size/sizeof(WCHAR), lpOutput, lpOutput ? 2*size : 0, NULL, NULL);
429 HeapFree(GetProcessHeap(), 0, buf);
431 else
432 result = pWTInfoW(wCategory, nIndex, lpOutput);
434 TRACE("returns %d\n", result);
435 return result;
438 /***********************************************************************
439 * WTInfoA (WINTAB32.20)
441 UINT WINAPI WTInfoA(UINT wCategory, UINT nIndex, LPVOID lpOutput)
443 return WTInfoT(wCategory, nIndex, lpOutput, FALSE);
447 /***********************************************************************
448 * WTInfoW (WINTAB32.1020)
450 UINT WINAPI WTInfoW(UINT wCategory, UINT nIndex, LPVOID lpOutput)
452 return WTInfoT(wCategory, nIndex, lpOutput, TRUE);
455 /***********************************************************************
456 * WTOpenW (WINTAB32.1021)
458 HCTX WINAPI WTOpenW(HWND hWnd, LPLOGCONTEXTW lpLogCtx, BOOL fEnable)
460 LPOPENCONTEXT newcontext;
462 if (!LoadTablet()) return 0;
464 TRACE("hWnd=%p, lpLogCtx=%p, fEnable=%u\n", hWnd, lpLogCtx, fEnable);
465 DUMPCONTEXT(*lpLogCtx);
467 newcontext = HeapAlloc(GetProcessHeap(), 0 , sizeof(OPENCONTEXT));
468 newcontext->context = *lpLogCtx;
469 newcontext->hwndOwner = hWnd;
470 newcontext->ActiveCursor = -1;
471 newcontext->QueueSize = 10;
472 newcontext->PacketsQueued = 0;
473 newcontext->PacketQueue=HeapAlloc(GetProcessHeap(),0,sizeof(WTPACKET)*10);
475 EnterCriticalSection(&csTablet);
476 newcontext->handle = gTopContext++;
477 newcontext->next = gOpenContexts;
478 gOpenContexts = newcontext;
479 LeaveCriticalSection(&csTablet);
481 pAttachEventQueueToTablet(hWnd);
483 TABLET_PostTabletMessage(newcontext, _WT_CTXOPEN(newcontext->context.lcMsgBase), (WPARAM)newcontext->handle,
484 newcontext->context.lcStatus, TRUE);
486 if (fEnable)
488 newcontext->enabled = TRUE;
489 /* TODO: Add to top of overlap order */
490 newcontext->context.lcStatus = CXS_ONTOP;
492 else
494 newcontext->enabled = FALSE;
495 newcontext->context.lcStatus = CXS_DISABLED;
498 TABLET_PostTabletMessage(newcontext, _WT_CTXOVERLAP(newcontext->context.lcMsgBase),
499 (WPARAM)newcontext->handle,
500 newcontext->context.lcStatus, TRUE);
502 return newcontext->handle;
505 /***********************************************************************
506 * WTOpenA (WINTAB32.21)
508 HCTX WINAPI WTOpenA(HWND hWnd, LPLOGCONTEXTA lpLogCtx, BOOL fEnable)
510 LOGCONTEXTW logCtxW;
512 LOGCONTEXTAtoW(lpLogCtx, &logCtxW);
513 return WTOpenW(hWnd, &logCtxW, fEnable);
516 /***********************************************************************
517 * WTClose (WINTAB32.22)
519 BOOL WINAPI WTClose(HCTX hCtx)
521 LPOPENCONTEXT context,ptr;
523 TRACE("(%p)\n", hCtx);
525 EnterCriticalSection(&csTablet);
527 ptr = context = gOpenContexts;
529 while (context && (context->handle != hCtx))
531 ptr = context;
532 context = context->next;
534 if (!context)
536 LeaveCriticalSection(&csTablet);
537 return TRUE;
540 if (context == gOpenContexts)
541 gOpenContexts = context->next;
542 else
543 ptr->next = context->next;
545 LeaveCriticalSection(&csTablet);
547 TABLET_PostTabletMessage(context, _WT_CTXCLOSE(context->context.lcMsgBase), (WPARAM)context->handle,
548 context->context.lcStatus,TRUE);
550 HeapFree(GetProcessHeap(),0,context->PacketQueue);
551 HeapFree(GetProcessHeap(),0,context);
553 return TRUE;
556 /***********************************************************************
557 * WTPacketsGet (WINTAB32.23)
559 int WINAPI WTPacketsGet(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
561 int limit;
562 LPOPENCONTEXT context;
563 LPVOID ptr = lpPkts;
565 TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
567 if (!hCtx)
568 return 0;
570 EnterCriticalSection(&csTablet);
572 context = TABLET_FindOpenContext(hCtx);
573 if (!context)
575 LeaveCriticalSection(&csTablet);
576 return 0;
579 if (lpPkts != NULL)
580 TABLET_BlankPacketData(context,lpPkts,cMaxPkts);
582 if (context->PacketsQueued == 0)
584 LeaveCriticalSection(&csTablet);
585 return 0;
588 limit = min(cMaxPkts,context->PacketsQueued);
590 if(ptr != NULL)
592 int i = 0;
593 for(i = 0; i < limit; i++)
594 ptr=TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[i]);
598 if (limit < context->PacketsQueued)
600 memmove(context->PacketQueue, &context->PacketQueue[limit],
601 (context->PacketsQueued - (limit))*sizeof(WTPACKET));
603 context->PacketsQueued -= limit;
604 LeaveCriticalSection(&csTablet);
606 TRACE("Copied %i packets\n",limit);
608 return limit;
611 /***********************************************************************
612 * WTPacket (WINTAB32.24)
614 BOOL WINAPI WTPacket(HCTX hCtx, UINT wSerial, LPVOID lpPkt)
616 int rc = 0;
617 LPOPENCONTEXT context;
618 LPWTPACKET wtp = NULL;
620 TRACE("(%p, %d, %p)\n", hCtx, wSerial, lpPkt);
622 if (!hCtx)
623 return FALSE;
625 EnterCriticalSection(&csTablet);
627 context = TABLET_FindOpenContext(hCtx);
628 if (!context)
630 LeaveCriticalSection(&csTablet);
631 return FALSE;
634 rc = TABLET_FindPacket(context ,wSerial, &wtp);
636 if (rc >= 0)
638 if (lpPkt)
639 TABLET_CopyPacketData(context ,lpPkt, wtp);
641 if ((rc+1) < context->QueueSize)
643 memmove(context->PacketQueue, &context->PacketQueue[rc+1],
644 (context->PacketsQueued - (rc+1))*sizeof(WTPACKET));
646 context->PacketsQueued -= (rc+1);
648 LeaveCriticalSection(&csTablet);
650 TRACE("Returning %i\n",rc+1);
651 return rc+1;
654 /***********************************************************************
655 * WTEnable (WINTAB32.40)
657 BOOL WINAPI WTEnable(HCTX hCtx, BOOL fEnable)
659 LPOPENCONTEXT context;
661 TRACE("hCtx=%p, fEnable=%u\n", hCtx, fEnable);
663 if (!hCtx) return FALSE;
665 EnterCriticalSection(&csTablet);
666 context = TABLET_FindOpenContext(hCtx);
667 if (!context)
669 LeaveCriticalSection(&csTablet);
670 return FALSE;
673 /* if we want to enable and it is not enabled then */
674 if(fEnable && !context->enabled)
676 context->enabled = TRUE;
677 /* TODO: Add to top of overlap order */
678 context->context.lcStatus = CXS_ONTOP;
679 TABLET_PostTabletMessage(context,
680 _WT_CTXOVERLAP(context->context.lcMsgBase),
681 (WPARAM)context->handle,
682 context->context.lcStatus, TRUE);
684 /* if we want to disable and it is not disabled then */
685 else if (!fEnable && context->enabled)
687 context->enabled = FALSE;
688 /* TODO: Remove from overlap order?? needs a test */
689 context->context.lcStatus = CXS_DISABLED;
690 TABLET_FlushQueue(context);
691 TABLET_PostTabletMessage(context,
692 _WT_CTXOVERLAP(context->context.lcMsgBase),
693 (WPARAM)context->handle,
694 context->context.lcStatus, TRUE);
696 LeaveCriticalSection(&csTablet);
698 return TRUE;
701 /***********************************************************************
702 * WTOverlap (WINTAB32.41)
704 * Move context to top or bottom of overlap order
706 BOOL WINAPI WTOverlap(HCTX hCtx, BOOL fToTop)
708 LPOPENCONTEXT context;
710 TRACE("hCtx=%p, fToTop=%u\n", hCtx, fToTop);
712 if (!hCtx) return FALSE;
714 EnterCriticalSection(&csTablet);
715 context = TABLET_FindOpenContext(hCtx);
716 if (!context)
718 LeaveCriticalSection(&csTablet);
719 return FALSE;
722 /* if we want to send to top and it's not already there */
723 if (fToTop && context->context.lcStatus != CXS_ONTOP)
725 /* TODO: Move context to top of overlap order */
726 FIXME("Not moving context to top of overlap order\n");
727 context->context.lcStatus = CXS_ONTOP;
728 TABLET_PostTabletMessage(context,
729 _WT_CTXOVERLAP(context->context.lcMsgBase),
730 (WPARAM)context->handle,
731 context->context.lcStatus, TRUE);
733 else if (!fToTop)
735 /* TODO: Move context to bottom of overlap order */
736 FIXME("Not moving context to bottom of overlap order\n");
737 context->context.lcStatus = CXS_OBSCURED;
738 TABLET_PostTabletMessage(context,
739 _WT_CTXOVERLAP(context->context.lcMsgBase),
740 (WPARAM)context->handle,
741 context->context.lcStatus, TRUE);
743 LeaveCriticalSection(&csTablet);
745 return TRUE;
748 /***********************************************************************
749 * WTConfig (WINTAB32.60)
751 BOOL WINAPI WTConfig(HCTX hCtx, HWND hWnd)
753 FIXME("(%p, %p): stub\n", hCtx, hWnd);
755 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
757 return FALSE;
760 /***********************************************************************
761 * WTGetA (WINTAB32.61)
763 BOOL WINAPI WTGetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
765 LPOPENCONTEXT context;
767 TRACE("(%p, %p)\n", hCtx, lpLogCtx);
769 if (!hCtx) return FALSE;
771 EnterCriticalSection(&csTablet);
772 context = TABLET_FindOpenContext(hCtx);
773 if (!context)
775 LeaveCriticalSection(&csTablet);
776 return FALSE;
779 LOGCONTEXTWtoA(&context->context, lpLogCtx);
780 LeaveCriticalSection(&csTablet);
782 return TRUE;
785 /***********************************************************************
786 * WTGetW (WINTAB32.1061)
788 BOOL WINAPI WTGetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
790 LPOPENCONTEXT context;
792 TRACE("(%p, %p)\n", hCtx, lpLogCtx);
794 if (!hCtx) return FALSE;
796 EnterCriticalSection(&csTablet);
797 context = TABLET_FindOpenContext(hCtx);
798 if (!context)
800 LeaveCriticalSection(&csTablet);
801 return FALSE;
804 memmove(lpLogCtx,&context->context,sizeof(LOGCONTEXTW));
805 LeaveCriticalSection(&csTablet);
807 return TRUE;
810 /***********************************************************************
811 * WTSetA (WINTAB32.62)
813 BOOL WINAPI WTSetA(HCTX hCtx, LPLOGCONTEXTA lpLogCtx)
815 LPOPENCONTEXT context;
817 TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
819 if (!hCtx || !lpLogCtx) return FALSE;
821 /* TODO: if cur process not owner of hCtx only modify
822 * attribs not locked by owner */
824 EnterCriticalSection(&csTablet);
825 context = TABLET_FindOpenContext(hCtx);
826 if (!context)
828 LeaveCriticalSection(&csTablet);
829 return FALSE;
832 LOGCONTEXTAtoW(lpLogCtx, &context->context);
833 LeaveCriticalSection(&csTablet);
835 return TRUE;
838 /***********************************************************************
839 * WTSetW (WINTAB32.1062)
841 BOOL WINAPI WTSetW(HCTX hCtx, LPLOGCONTEXTW lpLogCtx)
843 LPOPENCONTEXT context;
845 TRACE("hCtx=%p, lpLogCtx=%p\n", hCtx, lpLogCtx);
847 if (!hCtx || !lpLogCtx) return FALSE;
849 /* TODO: if cur process not hCtx owner only modify
850 * attribs not locked by owner */
852 EnterCriticalSection(&csTablet);
853 context = TABLET_FindOpenContext(hCtx);
854 if (!context)
856 LeaveCriticalSection(&csTablet);
857 return FALSE;
860 memmove(&context->context, lpLogCtx, sizeof(LOGCONTEXTW));
861 LeaveCriticalSection(&csTablet);
863 return TRUE;
866 /***********************************************************************
867 * WTExtGet (WINTAB32.63)
869 BOOL WINAPI WTExtGet(HCTX hCtx, UINT wExt, LPVOID lpData)
871 FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
873 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
875 return FALSE;
878 /***********************************************************************
879 * WTExtSet (WINTAB32.64)
881 BOOL WINAPI WTExtSet(HCTX hCtx, UINT wExt, LPVOID lpData)
883 FIXME("(%p, %u, %p): stub\n", hCtx, wExt, lpData);
885 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
887 return FALSE;
890 /***********************************************************************
891 * WTSave (WINTAB32.65)
893 BOOL WINAPI WTSave(HCTX hCtx, LPVOID lpSaveInfo)
895 FIXME("(%p, %p): stub\n", hCtx, lpSaveInfo);
897 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
899 return FALSE;
902 /***********************************************************************
903 * WTRestore (WINTAB32.66)
905 HCTX WINAPI WTRestore(HWND hWnd, LPVOID lpSaveInfo, BOOL fEnable)
907 FIXME("(%p, %p, %u): stub\n", hWnd, lpSaveInfo, fEnable);
909 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
911 return 0;
914 /***********************************************************************
915 * WTPacketsPeek (WINTAB32.80)
917 int WINAPI WTPacketsPeek(HCTX hCtx, int cMaxPkts, LPVOID lpPkts)
919 int limit;
920 LPOPENCONTEXT context;
921 LPVOID ptr = lpPkts;
923 TRACE("(%p, %d, %p)\n", hCtx, cMaxPkts, lpPkts);
925 if (!hCtx || !lpPkts) return 0;
927 EnterCriticalSection(&csTablet);
929 context = TABLET_FindOpenContext(hCtx);
931 if (!context || context->PacketsQueued == 0)
933 LeaveCriticalSection(&csTablet);
934 return 0;
937 for (limit = 0; limit < cMaxPkts && limit < context->PacketsQueued; limit++)
938 ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[limit]);
940 LeaveCriticalSection(&csTablet);
941 TRACE("Copied %i packets\n",limit);
942 return limit;
945 /***********************************************************************
946 * WTDataGet (WINTAB32.81)
948 int WINAPI WTDataGet(HCTX hCtx, UINT wBegin, UINT wEnd,
949 int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
951 LPOPENCONTEXT context;
952 LPVOID ptr = lpPkts;
953 INT bgn = 0;
954 INT end = 0;
955 INT num = 0;
957 TRACE("(%p, %u, %u, %d, %p, %p)\n",
958 hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
960 if (!hCtx) return 0;
962 EnterCriticalSection(&csTablet);
964 context = TABLET_FindOpenContext(hCtx);
966 if (!context || context->PacketsQueued == 0)
968 LeaveCriticalSection(&csTablet);
969 return 0;
972 while (bgn < context->PacketsQueued &&
973 context->PacketQueue[bgn].pkSerialNumber != wBegin)
974 bgn++;
976 end = bgn;
977 while (end < context->PacketsQueued &&
978 context->PacketQueue[end].pkSerialNumber != wEnd)
979 end++;
981 if ((bgn == end) && (end == context->PacketsQueued))
983 LeaveCriticalSection(&csTablet);
984 return 0;
987 for (num = bgn; num <= end; num++)
988 ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
990 /* remove read packets */
991 if ((end+1) < context->PacketsQueued)
992 memmove( &context->PacketQueue[bgn], &context->PacketQueue[end+1],
993 (context->PacketsQueued - (end+1)) * sizeof (WTPACKET));
995 context->PacketsQueued -= ((end-bgn)+1);
996 *lpNPkts = ((end-bgn)+1);
998 LeaveCriticalSection(&csTablet);
999 TRACE("Copied %i packets\n",*lpNPkts);
1000 return (end - bgn)+1;
1003 /***********************************************************************
1004 * WTDataPeek (WINTAB32.82)
1006 int WINAPI WTDataPeek(HCTX hCtx, UINT wBegin, UINT wEnd,
1007 int cMaxPkts, LPVOID lpPkts, LPINT lpNPkts)
1009 LPOPENCONTEXT context;
1010 LPVOID ptr = lpPkts;
1011 INT bgn = 0;
1012 INT end = 0;
1013 INT num = 0;
1015 TRACE("(%p, %u, %u, %d, %p, %p)\n",
1016 hCtx, wBegin, wEnd, cMaxPkts, lpPkts, lpNPkts);
1018 if (!hCtx || !lpPkts) return 0;
1020 EnterCriticalSection(&csTablet);
1022 context = TABLET_FindOpenContext(hCtx);
1024 if (!context || context->PacketsQueued == 0)
1026 LeaveCriticalSection(&csTablet);
1027 return 0;
1030 while (bgn < context->PacketsQueued &&
1031 context->PacketQueue[bgn].pkSerialNumber != wBegin)
1032 bgn++;
1034 end = bgn;
1035 while (end < context->PacketsQueued &&
1036 context->PacketQueue[end].pkSerialNumber != wEnd)
1037 end++;
1039 if (bgn == context->PacketsQueued || end == context->PacketsQueued)
1041 TRACE("%i %i %i\n", bgn, end, context->PacketsQueued);
1042 LeaveCriticalSection(&csTablet);
1043 return 0;
1046 for (num = bgn; num <= end; num++)
1047 ptr = TABLET_CopyPacketData(context ,ptr, &context->PacketQueue[num]);
1049 *lpNPkts = ((end-bgn)+1);
1050 LeaveCriticalSection(&csTablet);
1052 TRACE("Copied %i packets\n",*lpNPkts);
1053 return (end - bgn)+1;
1056 /***********************************************************************
1057 * WTQueuePacketsEx (WINTAB32.200)
1059 BOOL WINAPI WTQueuePacketsEx(HCTX hCtx, UINT *lpOld, UINT *lpNew)
1061 LPOPENCONTEXT context;
1063 TRACE("(%p, %p, %p)\n", hCtx, lpOld, lpNew);
1065 if (!hCtx) return FALSE;
1067 EnterCriticalSection(&csTablet);
1069 context = TABLET_FindOpenContext(hCtx);
1071 if (context && context->PacketsQueued)
1073 *lpOld = context->PacketQueue[0].pkSerialNumber;
1074 *lpNew = context->PacketQueue[context->PacketsQueued-1].pkSerialNumber;
1076 else
1078 TRACE("No packets\n");
1079 LeaveCriticalSection(&csTablet);
1080 return FALSE;
1082 LeaveCriticalSection(&csTablet);
1084 return TRUE;
1087 /***********************************************************************
1088 * WTQueueSizeGet (WINTAB32.84)
1090 int WINAPI WTQueueSizeGet(HCTX hCtx)
1092 LPOPENCONTEXT context;
1093 int queueSize = 0;
1095 TRACE("(%p)\n", hCtx);
1097 if (!hCtx) return 0;
1099 EnterCriticalSection(&csTablet);
1100 context = TABLET_FindOpenContext(hCtx);
1101 if (context)
1102 queueSize = context->QueueSize;
1103 LeaveCriticalSection(&csTablet);
1104 return queueSize;
1107 /***********************************************************************
1108 * WTQueueSizeSet (WINTAB32.85)
1110 BOOL WINAPI WTQueueSizeSet(HCTX hCtx, int nPkts)
1112 LPOPENCONTEXT context;
1114 TRACE("(%p, %d)\n", hCtx, nPkts);
1116 if (!hCtx) return FALSE;
1118 EnterCriticalSection(&csTablet);
1120 context = TABLET_FindOpenContext(hCtx);
1121 if (!context)
1123 LeaveCriticalSection(&csTablet);
1124 return FALSE;
1127 context->PacketQueue = HeapReAlloc(GetProcessHeap(), 0,
1128 context->PacketQueue, sizeof(WTPACKET)*nPkts);
1130 context->QueueSize = nPkts;
1131 LeaveCriticalSection(&csTablet);
1133 return nPkts;