1 /*
2     EasyTab.h - Single-header multi-platform tablet library
3     https://github.com/ApoorvaJ/EasyTab
4 
5     ----------------------------------------------------------------------------
6     USAGE
7     ----------------------------------------------------------------------------
8     1) Add the following lines in exactly one of your cpp files to compile the
9        implementation.
10 
11            #define EASYTAB_IMPLEMENTATION
12            #include "easytab.h"
13 
14     2) Call EasyTab_Load() with correct parameters to initialize EasyTab. These
15        parameters vary per OS, so look at the function declarations or examples
16        below. Function returns EASYTAB_OK if initialization was successful.
17 
18     3) Call EasyTab_HandleEvent() in your message-handling code. The function
19        returns EASYTAB_OK if the message was a tablet message, and
20        EASYTAB_EVENT_NOT_HANDLED otherwise.
21 
22     4) Call EasyTab_Unload() in your shutdown code.
23 
24     5) Once initialized, you can query tablet state using the EasyTab pointer.
25        e.g.:
26 
27            EasyTab->PosX        // X position of the pen
28            EasyTab->PosY        // Y position of the pen
29            EasyTab->Pressure    // Pressure of the pen ranging from 0.0f to 1.0f
30 
31        For more info, have a look at the EasyTabInfo struct below.
32 
33 
34     * Add -lXi to compiler options to link XInput on Linux.
35 
36     ----------------------------------------------------------------------------
37     EXAMPLES
38     ----------------------------------------------------------------------------
39     1) Windows:
40 
41         int CALLBACK WinMain(...)
42         {
43             HWND Window;
44 
45             ...
46 
47             if (EasyTab_Load(Window) != EASYTAB_OK)                                  // Load
48             {
49                 OutputDebugStringA("Tablet init failed\n");
50             }
51 
52             ...
53 
54             // Once you've set up EasyTab loading, unloading and event handling,
55             // use the EasyTab variable at any point in your program to access
56             // the tablet state:
57             //    EasyTab->PosX
58             //    EasyTab->PosY
59             //    EasyTab->Pressure
60             // For more tablet information, look at the EasyTabInfo struct.
61 
62             ...
63 
64             EasyTab_Unload();                                                      // Unload
65         }
66 
67         LRESULT CALLBACK WindowProc(
68             HWND Window,
69             UINT Message,
70             WPARAM WParam,
71             LPARAM LParam)
72         {
73             if (EasyTab_HandleEvent(Window, Message, LParam, WParam) == EASYTAB_OK) // Event
74             {
75                 return true; // Tablet event handled
76             }
77 
78             switch (Message)
79             {
80                 ...
81             }
82         }
83 
84 
85     2) Linux:
86 
87         int main(...)
88         {
89             Display* Disp;
90             Window   Win;
91 
92             ...
93 
94             if (EasyTab_Load(Disp, Win) != EASYTAB_OK)                   // Load
95             {
96                 printf("Tablet init failed\n");
97             }
98 
99             ...
100 
101             while (XPending(Disp)) // Event loop
102             {
103                 XEvent Event;
104                 XNextEvent(XlibDisplay, &Event);
105 
106                 if (EasyTab_HandleEvent(&Event) == EASYTAB_OK)          // Event
107                 {
108                     continue; // Tablet event handled
109                 }
110 
111                 switch (Event.type)
112                 {
113                     ...
114                 }
115             }
116 
117             ...
118 
119             // Once you've set up EasyTab loading, unloading and event handling,
120             // use the EasyTab variable at any point in your program to access
121             // the tablet state:
122             //    EasyTab->PosX
123             //    EasyTab->PosY
124             //    EasyTab->Pressure
125             // For more tablet information, look at the EasyTabInfo struct.
126 
127             ...
128 
129             EasyTab_Unload();                                          // Unload
130         }
131 
132     ----------------------------------------------------------------------------
133     CREDITS
134     ----------------------------------------------------------------------------
135     Apoorva Joshi       apoorvaj.io
136     Sergio Gonzalez     s3rg.io
137 
138     This library is coded in the spirit of the stb libraries and follows the stb
139     guidelines.
140 
141     ----------------------------------------------------------------------------
142     LICENSE
143     ----------------------------------------------------------------------------
144     This software is in the public domain. Where that dedication is not
145     recognized, you are granted a perpetual, irrevocable license to copy,
146     distribute, and modify this file as you see fit.
147 */
148 
149 // TODO: Null checks and warnings for EasyTab
150 // TODO: Differentiate between stylus and eraser in the API
151 // TODO: Linux support for relative mode
152 // TODO: Documentation for relative mode
153 
154 // =============================================================================
155 // EasyTab header section
156 // =============================================================================
157 
158 #ifndef EASYTAB_H
159 #define EASYTAB_H
160 
161 #include <stdint.h>
162 #include <stdlib.h>
163 #include <string.h>
164 
165 #ifdef __DragonFly__
166 #include <X11/extensions/XInput.h>
167 #endif // __DragonFly__
168 
169 #ifdef _WIN32
170 #include <windows.h>
171 #endif // _WIN32
172 
173 #define MILTON_EASYTAB
174 
175 typedef enum
176 {
177     EASYTAB_OK = 0,
178 
179     EASYTAB_NEEDS_REINIT = 1,
180 
181     // Errors
182     EASYTAB_MEMORY_ERROR           = -1,
183     EASYTAB_X11_ERROR              = -2,
184     EASYTAB_DLL_LOAD_ERROR         = -3,
185     EASYTAB_WACOM_WIN32_ERROR      = -4,
186     EASYTAB_INVALID_FUNCTION_ERROR = -5,
187     #if defined MILTON_EASYTAB
188     EASYTAB_QUEUE_SIZE_ERROR       = -6,
189     #endif
190 
191     EASYTAB_EVENT_NOT_HANDLED = -16,
192 } EasyTabResult;
193 
194 #ifdef MILTON_EASYTAB
195 #define EASYTAB_PACKETQUEUE_SIZE    128
196 #define EASYTAB_TRUE                1
197 #define EASYTAB_FALSE               0
198 #define EASYTAB_BOOL                int
199 #define EASYTAB_ABS(val)  ( ((val) >= 0) ? val : -val )
200 #endif
201 
202 
203 typedef enum
204 {
205     EASYTAB_TRACKING_MODE_SYSTEM   = 0,
206     EASYTAB_TRACKING_MODE_RELATIVE = 1,
207 } EasyTabTrackingMode;
208 
209 #ifdef WIN32
210 // -----------------------------------------------------------------------------
211 // wintab.h
212 // -----------------------------------------------------------------------------
213 #if 1
214 
215     DECLARE_HANDLE(HMGR);
216     DECLARE_HANDLE(HCTX);
217 
218     typedef DWORD WTPKT;
219     typedef DWORD FIX32;
220 
221     // Messages
222     #if 1
223 
224         #define WT_DEFBASE          0x7FF0
225         #define WT_MAXOFFSET        0xF
226 
227         #define _WT_PACKET(b)       ((b)+0)
228         #define _WT_CTXOPEN(b)      ((b)+1)
229         #define _WT_CTXCLOSE(b)     ((b)+2)
230         #define _WT_CTXUPDATE(b)    ((b)+3)
231         #define _WT_CTXOVERLAP(b)   ((b)+4)
232         #define _WT_PROXIMITY(b)    ((b)+5)
233         #define _WT_INFOCHANGE(b)   ((b)+6)
234         #define _WT_CSRCHANGE(b)    ((b)+7) /* 1.1 */
235         #define _WT_PACKETEXT(b)    ((b)+8) /* 1.4 */
236         #define _WT_MAX(b)          ((b)+WT_MAXOFFSET)
237 
238         #define WT_PACKET           _WT_PACKET(WT_DEFBASE)
239         #define WT_CTXOPEN          _WT_CTXOPEN(WT_DEFBASE)
240         #define WT_CTXCLOSE         _WT_CTXCLOSE(WT_DEFBASE)
241         #define WT_CTXUPDATE        _WT_CTXUPDATE(WT_DEFBASE)
242         #define WT_CTXOVERLAP       _WT_CTXOVERLAP(WT_DEFBASE)
243         #define WT_PROXIMITY        _WT_PROXIMITY(WT_DEFBASE)
244         #define WT_INFOCHANGE       _WT_INFOCHANGE(WT_DEFBASE)
245         #define WT_CSRCHANGE        _WT_CSRCHANGE(WT_DEFBASE) /* 1.1 */
246         #define WT_PACKETEXT        _WT_PACKETEXT(WT_DEFBASE) /* 1.4 */
247         #define WT_MAX              _WT_MAX(WT_DEFBASE)
248 
249     #endif // Messages
250 
251     // Flags
252     #if 1
253 
254         #define CTX_NAME        1
255         #define CTX_OPTIONS     2
256         #define CTX_STATUS      3
257         #define CTX_LOCKS       4
258         #define CTX_MSGBASE     5
259         #define CTX_DEVICE      6
260         #define CTX_PKTRATE     7
261         #define CTX_PKTDATA     8
262         #define CTX_PKTMODE     9
263         #define CTX_MOVEMASK    10
264         #define CTX_BTNDNMASK   11
265         #define CTX_BTNUPMASK   12
266         #define CTX_INORGX      13
267         #define CTX_INORGY      14
268         #define CTX_INORGZ      15
269         #define CTX_INEXTX      16
270         #define CTX_INEXTY      17
271         #define CTX_INEXTZ      18
272         #define CTX_OUTORGX     19
273         #define CTX_OUTORGY     20
274         #define CTX_OUTORGZ     21
275         #define CTX_OUTEXTX     22
276         #define CTX_OUTEXTY     23
277         #define CTX_OUTEXTZ     24
278         #define CTX_SENSX       25
279         #define CTX_SENSY       26
280         #define CTX_SENSZ       27
281         #define CTX_SYSMODE     28
282         #define CTX_SYSORGX     29
283         #define CTX_SYSORGY     30
284         #define CTX_SYSEXTX     31
285         #define CTX_SYSEXTY     32
286         #define CTX_SYSSENSX    33
287         #define CTX_SYSSENSY    34
288         #define CTX_MAX         34
289 
290         // Context option values
291         #define CXO_SYSTEM      0x0001
292         #define CXO_PEN         0x0002
293         #define CXO_MESSAGES    0x0004
294         #define CXO_MARGIN      0x8000
295         #define CXO_MGNINSIDE   0x4000
296         #define CXO_CSRMESSAGES 0x0008 /* 1.1 */
297 
298         // Context status values
299         #define CXS_DISABLED  0x0001
300         #define CXS_OBSCURED  0x0002
301         #define CXS_ONTOP     0x0004
302 
303         #define DVC_NAME        1
304         #define DVC_HARDWARE    2
305         #define DVC_NCSRTYPES   3
306         #define DVC_FIRSTCSR    4
307         #define DVC_PKTRATE     5
308         #define DVC_PKTDATA     6
309         #define DVC_PKTMODE     7
310         #define DVC_CSRDATA     8
311         #define DVC_XMARGIN     9
312         #define DVC_YMARGIN     10
313         #define DVC_ZMARGIN     11
314         #define DVC_X           12
315         #define DVC_Y           13
316         #define DVC_Z           14
317         #define DVC_NPRESSURE   15
318         #define DVC_TPRESSURE   16
319         #define DVC_ORIENTATION 17
320         #define DVC_ROTATION    18 /* 1.1 */
321         #define DVC_PNPID       19 /* 1.1 */
322         #define DVC_MAX         19
323 
324         #define PK_CONTEXT           0x0001 // reporting context
325         #define PK_STATUS            0x0002 // status bits
326         #define PK_TIME              0x0004 // time stamp
327         #define PK_CHANGED           0x0008 // change bit vector
328         #define PK_SERIAL_NUMBER     0x0010 // packet serial number
329         #define PK_CURSOR            0x0020 // reporting cursor
330         #define PK_BUTTONS           0x0040 // button information
331         #define PK_X                 0x0080 // x axis
332         #define PK_Y                 0x0100 // y axis
333         #define PK_Z                 0x0200 // z axis
334         #define PK_NORMAL_PRESSURE   0x0400 // normal or tip pressure
335         #define PK_TANGENT_PRESSURE  0x0800 // tangential or barrel pressure
336         #define PK_ORIENTATION       0x1000 // orientation info: tilts
337         #define PK_ROTATION          0x2000 // rotation info; 1.1
338 
339         // constants for use with pktdef.h
340         #define PKEXT_ABSOLUTE  1
341         #define PKEXT_RELATIVE  2
342 
343         #define WTI_DEFCONTEXT  3
344         #define WTI_DEFSYSCTX   4
345         #define WTI_DEVICES     100
346         #define WTI_DDCTXS      400 /* 1.1 */
347         #define WTI_DSCTXS      500 /* 1.1 */
348 
349     #endif // Flags
350 
351     typedef struct tagAXIS {
352         LONG    axMin;
353         LONG    axMax;
354         UINT    axUnits;
355         FIX32   axResolution;
356     } AXIS, *PAXIS, NEAR *NPAXIS, FAR *LPAXIS;
357 
358     typedef struct tagORIENTATION {
359         int   orAzimuth;
360         int   orAltitude;
361         int   orTwist;
362 
363     } ORIENTATION;
364 
365     #define LCNAMELEN 40
366     typedef struct tagLOGCONTEXTA {
367         char    lcName[LCNAMELEN];
368         UINT    lcOptions;
369         UINT    lcStatus;
370         UINT    lcLocks;
371         UINT    lcMsgBase;
372         UINT    lcDevice;
373         UINT    lcPktRate;
374         WTPKT   lcPktData;
375         WTPKT   lcPktMode;
376         WTPKT   lcMoveMask;
377         DWORD   lcBtnDnMask;
378         DWORD   lcBtnUpMask;
379         LONG    lcInOrgX;
380         LONG    lcInOrgY;
381         LONG    lcInOrgZ;
382         LONG    lcInExtX;
383         LONG    lcInExtY;
384         LONG    lcInExtZ;
385         LONG    lcOutOrgX;
386         LONG    lcOutOrgY;
387         LONG    lcOutOrgZ;
388         LONG    lcOutExtX;
389         LONG    lcOutExtY;
390         LONG    lcOutExtZ;
391         FIX32   lcSensX;
392         FIX32   lcSensY;
393         FIX32   lcSensZ;
394         BOOL    lcSysMode;
395         int     lcSysOrgX;
396         int     lcSysOrgY;
397         int     lcSysExtX;
398         int     lcSysExtY;
399         FIX32   lcSysSensX;
400         FIX32   lcSysSensY;
401     } LOGCONTEXTA, *PLOGCONTEXTA, NEAR *NPLOGCONTEXTA, FAR *LPLOGCONTEXTA;
402 
403     typedef struct tagEXTENSIONBASE { /* 1.4 */
404         HCTX    nContext;
405         UINT    nStatus;
406         DWORD   nTime;
407         UINT    nSerialNumber;
408     } EXTENSIONBASE;
409 
410 #endif // wintab.h
411 // -----------------------------------------------------------------------------
412 
413 #define PACKETDATA PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION
414 #define PACKETMODE 0
415 
416 // -----------------------------------------------------------------------------
417 // pktdef.h
418 // -----------------------------------------------------------------------------
419 #if 1
420 
421     // TODO: Simplify this file if we have a fixed packet format.
422     //       The macros here are too ugly.
423 
424     #ifndef PACKETNAME
425     /* if no packet name prefix */
426     #define __PFX(x)    x
427     #define __IFX(x,y)  x ## y
428     #else
429     /* add prefixes and infixes to packet format names */
430     #define __PFX(x)        __PFX2(PACKETNAME,x)
431     #define __PFX2(p,x)     __PFX3(p,x)
432     #define __PFX3(p,x)     p ## x
433     #define __IFX(x,y)      __IFX2(x,PACKETNAME,y)
434     #define __IFX2(x,i,y)   __IFX3(x,i,y)
435     #define __IFX3(x,i,y)   x ## i ## y
436     #endif
437 
438     #define __SFX2(x,s)     __SFX3(x,s)
439     #define __SFX3(x,s)     x ## s
440 
441     #define __TAG   __IFX(tag,PACKET)
442     #define __TYPES __PFX(PACKET), * __IFX(P,PACKET), NEAR * __IFX(NP,PACKET), FAR * __IFX(LP,PACKET)
443 
444     #define __TAGE      __IFX(tag,PACKETEXT)
445     #define __TYPESE    __PFX(PACKETEXT), * __IFX(P,PACKETEXT), NEAR * __IFX(NP,PACKETEXT), FAR * __IFX(LP,PACKETEXT)
446 
447     #define __DATA      (__PFX(PACKETDATA))
448     #define __MODE      (__PFX(PACKETMODE))
449     #define __EXT(x)    __SFX2(__PFX(PACKET),x)
450 
451 
452     typedef struct __TAG {
453     #if (__DATA & PK_CONTEXT)
454         HCTX            pkContext;
455     #endif
456     #if (__DATA & PK_STATUS)
457         UINT            pkStatus;
458     #endif
459     #if (__DATA & PK_TIME)
460         DWORD           pkTime;
461     #endif
462     #if (__DATA & PK_CHANGED)
463         WTPKT           pkChanged;
464     #endif
465     #if (__DATA & PK_SERIAL_NUMBER)
466         UINT            pkSerialNumber;
467     #endif
468     #if (__DATA & PK_CURSOR)
469         UINT            pkCursor;
470     #endif
471     #if (__DATA & PK_BUTTONS)
472         DWORD           pkButtons;
473     #endif
474     #if (__DATA & PK_X)
475         LONG            pkX;
476     #endif
477     #if (__DATA & PK_Y)
478         LONG            pkY;
479     #endif
480     #if (__DATA & PK_Z)
481         LONG            pkZ;
482     #endif
483     #if (__DATA & PK_NORMAL_PRESSURE)
484     #if (__MODE & PK_NORMAL_PRESSURE)
485         /* relative */
486         int         pkNormalPressure;
487     #else
488         /* absolute */
489         UINT        pkNormalPressure;
490     #endif
491     #endif
492     #if (__DATA & PK_TANGENT_PRESSURE)
493     #if (__MODE & PK_TANGENT_PRESSURE)
494         /* relative */
495         int         pkTangentPressure;
496     #else
497         /* absolute */
498         UINT        pkTangentPressure;
499     #endif
500     #endif
501     #if (__DATA & PK_ORIENTATION)
502         ORIENTATION     pkOrientation;
503     #endif
504     #if (__DATA & PK_ROTATION)
505         ROTATION        pkRotation; /* 1.1 */
506     #endif
507 
508     #ifndef NOWTEXTENSIONS
509                                     /* extensions begin here. */
510     #if (__EXT(FKEYS) == PKEXT_RELATIVE) || (__EXT(FKEYS) == PKEXT_ABSOLUTE)
511         UINT            pkFKeys;
512     #endif
513     #if (__EXT(TILT) == PKEXT_RELATIVE) || (__EXT(TILT) == PKEXT_ABSOLUTE)
514         TILT            pkTilt;
515     #endif
516     #endif
517 
518     } __TYPES;
519 
520     #ifndef NOWTEXTENSIONS
521     typedef struct __TAGE {
522         EXTENSIONBASE   pkBase;
523 
524     #if (__EXT(EXPKEYS) == PKEXT_RELATIVE) || (__EXT(EXPKEYS) == PKEXT_ABSOLUTE)
525         EXPKEYSDATA pkExpKeys; /* 1.4 */
526     #endif
527     #if (__EXT(TOUCHSTRIP) == PKEXT_RELATIVE) || (__EXT(TOUCHSTRIP) == PKEXT_ABSOLUTE)
528         SLIDERDATA  pkTouchStrip; /* 1.4 */
529     #endif
530     #if (__EXT(TOUCHRING) == PKEXT_RELATIVE) || (__EXT(TOUCHRING) == PKEXT_ABSOLUTE)
531         SLIDERDATA  pkTouchRing; /* 1.4 */
532     #endif
533 
534     } __TYPESE;
535     #endif
536 
537     #undef PACKETNAME
538     #undef __TAG
539     #undef __TAGE
540     #undef __TAG2
541     #undef __TYPES
542     #undef __TYPESE
543     #undef __TYPES2
544     #undef __DATA
545     #undef __MODE
546     #undef __PFX
547     #undef __PFX2
548     #undef __PFX3
549     #undef __IFX
550     #undef __IFX2
551     #undef __IFX3
552     #undef __SFX2
553     #undef __SFX3
554 
555 #endif // pktdef.h
556 // -----------------------------------------------------------------------------
557 
558 typedef UINT (WINAPI * WTINFOA) (UINT, UINT, LPVOID);
559 typedef HCTX (WINAPI * WTOPENA) (HWND, LPLOGCONTEXTA, BOOL);
560 typedef BOOL (WINAPI * WTGETA) (HCTX, LPLOGCONTEXTA);
561 typedef BOOL (WINAPI * WTSETA) (HCTX, LPLOGCONTEXTA);
562 typedef BOOL (WINAPI * WTCLOSE) (HCTX);
563 typedef BOOL (WINAPI * WTENABLE) (HCTX, BOOL);
564 typedef BOOL (WINAPI * WTPACKET) (HCTX, UINT, LPVOID);
565 typedef BOOL (WINAPI * WTOVERLAP) (HCTX, BOOL);
566 typedef BOOL (WINAPI * WTSAVE) (HCTX, LPVOID);
567 typedef BOOL (WINAPI * WTCONFIG) (HCTX, HWND);
568 typedef HCTX (WINAPI * WTRESTORE) (HWND, LPVOID, BOOL);
569 typedef BOOL (WINAPI * WTEXTSET) (HCTX, UINT, LPVOID);
570 typedef BOOL (WINAPI * WTEXTGET) (HCTX, UINT, LPVOID);
571 typedef BOOL (WINAPI * WTQUEUESIZESET) (HCTX, int);
572 typedef int  (WINAPI * WTDATAPEEK) (HCTX, UINT, UINT, int, LPVOID, LPINT);
573 typedef int  (WINAPI * WTPACKETSGET) (HCTX, int, LPVOID);
574 typedef HMGR (WINAPI * WTMGROPEN) (HWND, UINT);
575 typedef BOOL (WINAPI * WTMGRCLOSE) (HMGR);
576 typedef HCTX (WINAPI * WTMGRDEFCONTEXT) (HMGR, BOOL);
577 typedef HCTX (WINAPI * WTMGRDEFCONTEXTEX) (HMGR, UINT, BOOL);
578 #ifdef MILTON_EASYTAB
579 typedef int  (WINAPI * WTQUEUESIZEGET) (HCTX);
580 #endif
581 
582 #endif // WIN32
583 
584 // -----------------------------------------------------------------------------
585 // Enums
586 // -----------------------------------------------------------------------------
587 
588 /*
589     Use this enum in conjunction with EasyTab->Buttons to check for tablet button
590     presses.
591     e.g. To check for lower pen button press, use:
592 
593     if (EasyTab->Buttons & EasyTab_Buttons_Pen_Lower)
594     {
595         // Lower button is pressed
596     }
597 */
598 enum EasyTab_Buttons_
599 {
600     EasyTab_Buttons_Pen_Touch = 1 << 0, // Pen is touching tablet
601     EasyTab_Buttons_Pen_Lower = 1 << 1, // Lower pen button is pressed
602     EasyTab_Buttons_Pen_Upper = 1 << 2, // Upper pen button is pressed
603 };
604 
605 
606 // Spherical coordinate system used by Wintab to store the orientation of the pen.
607 typedef struct
608 {
609     int32_t Azimuth;
610     int32_t Altitude;
611     int32_t Twist;
612 } EasyTab_Orientation;
613 
614 // -----------------------------------------------------------------------------
615 // Structs
616 // -----------------------------------------------------------------------------
617 typedef struct EasyTab_s
618 {
619 #ifdef MILTON_EASYTAB
620     int32_t PosX[EASYTAB_PACKETQUEUE_SIZE];
621     int32_t PosY[EASYTAB_PACKETQUEUE_SIZE];
622     float   Pressure[EASYTAB_PACKETQUEUE_SIZE]; // Range: 0.0f to 1.0f
623     int32_t NumPackets;  // Number of PosX, PosY, Pressure elements available in arrays.
624     EASYTAB_BOOL PenInProximity;  // EASYTAB_TRUE if pen is in proximity to table. EASYTAB_FALSE otherwise.
625 #else
626     int32_t PosX, PosY;
627     float   Pressure; // Range: 0.0f to 1.0f
628 #endif
629     int32_t Buttons; // Bit field. Use with the EasyTab_Buttons_ enum.
630 
631     int32_t RangeX, RangeY;
632     int32_t MaxPressure;
633 
634     EasyTab_Orientation Orientation;
635 
636 #ifdef __DragonFly__
637     XDevice* Device;
638     uint32_t MotionType;
639     uint32_t ProximityTypeIn;
640     uint32_t ProximityTypeOut;
641     uint32_t ButtonTypePress;
642     uint32_t ButtonTypeRelease;
643     XEventClass EventClasses[1024];
644     uint32_t NumEventClasses;
645 #endif // __DragonFly__
646 
647 #ifdef WIN32
648     HINSTANCE Dll;
649     HCTX      Context;
650 
651     WTINFOA           WTInfoA;
652     WTOPENA           WTOpenA;
653     WTGETA            WTGetA;
654     WTSETA            WTSetA;
655     WTCLOSE           WTClose;
656     WTPACKET          WTPacket;
657     WTENABLE          WTEnable;
658     WTOVERLAP         WTOverlap;
659     WTSAVE            WTSave;
660     WTCONFIG          WTConfig;
661     WTRESTORE         WTRestore;
662     WTEXTSET          WTExtSet;
663     WTEXTGET          WTExtGet;
664     WTQUEUESIZESET    WTQueueSizeSet;
665 #ifdef MILTON_EASYTAB
666     WTQUEUESIZEGET    WTQueueSizeGet;
667 #endif
668     WTDATAPEEK        WTDataPeek;
669     WTPACKETSGET      WTPacketsGet;
670     WTMGROPEN         WTMgrOpen;
671     WTMGRCLOSE        WTMgrClose;
672     WTMGRDEFCONTEXT   WTMgrDefContext;
673     WTMGRDEFCONTEXTEX WTMgrDefContextEx;
674 
675 
676     LONG InputOriginX;
677     LONG InputOriginY;
678 
679     LONG InputExtentX;
680     LONG InputExtentY;
681 
682     LONG OutputOriginX;
683     LONG OutputOriginY;
684 
685     LONG OutputExtentX;
686     LONG OutputExtentY;
687 
688 
689 #endif // WIN32
690 } EasyTabInfo;
691 
692 extern EasyTabInfo* EasyTab;
693 
694 // -----------------------------------------------------------------------------
695 // Function declarations
696 // -----------------------------------------------------------------------------
697 #if defined(__DragonFly__)
698 
699     EasyTabResult EasyTab_Load(Display* Disp, Window Win);
700     EasyTabResult EasyTab_HandleEvent(XEvent* Event);
701     void EasyTab_Unload(Display* Disp);
702 
703 #elif defined(_WIN32)
704 
705     EasyTabResult EasyTab_Load(HWND Window);
706     EasyTabResult EasyTab_Load_Ex(HWND Window,
707                                   EasyTabTrackingMode Mode,
708                                   float RelativeModeSensitivity,
709                                   int32_t MoveCursor);
710     EasyTabResult EasyTab_HandleEvent(HWND Window,
711                                       UINT Message,
712                                       LPARAM LParam,
713                                       WPARAM WParam);
714     void EasyTab_Unload();
715 
716 #else
717 
718     // Save some trouble when porting.
719     #ifndef MILTON_EASYTAB
720     #error "Unsupported platform."
721     #endif
722 
723 #endif // __DragonFly__ _WIN32
724 // -----------------------------------------------------------------------------
725 
726 #endif // EASYTAB_H
727 
728 
729 
730 // =============================================================================
731 // EasyTab implementation section
732 // =============================================================================
733 
734 #ifdef EASYTAB_IMPLEMENTATION
735 
736 EasyTabInfo* EasyTab;
737 
738 // -----------------------------------------------------------------------------
739 // Linux implementation
740 // -----------------------------------------------------------------------------
741 #ifdef __DragonFly__
742 
EasyTab_Load(Display * Disp,Window Win)743 EasyTabResult EasyTab_Load(Display* Disp, Window Win)
744 {
745     EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
746     if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
747 
748     int32_t Count;
749     XDeviceInfoPtr Devices = (XDeviceInfoPtr)XListInputDevices(Disp, &Count);
750     if (!Devices) { return EASYTAB_X11_ERROR; }
751 
752     for (int32_t i = 0; i < Count; i++)
753     {
754         if (!strstr(Devices[i].name, "stylus") &&
755             !strstr(Devices[i].name, "eraser")) { continue; }
756 
757         EasyTab->Device = XOpenDevice(Disp, Devices[i].id);
758         XAnyClassPtr ClassPtr = Devices[i].inputclassinfo;
759 
760         for (int32_t j = 0; j < Devices[i].num_classes; j++)
761         {
762 #if defined(__cplusplus)
763             switch (ClassPtr->c_class)
764 #else
765             switch (ClassPtr->class)
766 #endif
767             {
768                 case ValuatorClass:
769                 {
770                     XValuatorInfo *Info = (XValuatorInfo *)ClassPtr;
771                     // X
772                     if (Info->num_axes > 0)
773                     {
774                         int32_t min     = Info->axes[0].min_value;
775                         EasyTab->RangeX = Info->axes[0].max_value;
776                         //printf("Max/min x values: %d, %d\n", min, EasyTab->RangeX); // TODO: Platform-print macro
777                     }
778 
779                     // Y
780                     if (Info->num_axes > 1)
781                     {
782                         int32_t min     = Info->axes[1].min_value;
783                         EasyTab->RangeY = Info->axes[1].max_value;
784                         //printf("Max/min y values: %d, %d\n", min, EasyTab->RangeY);
785                     }
786 
787                     // Pressure
788                     if (Info->num_axes > 2)
789                     {
790                         int32_t min          = Info->axes[2].min_value;
791                         EasyTab->MaxPressure = Info->axes[2].max_value;
792                         //printf("Max/min pressure values: %d, %d\n", min, EasyTab->MaxPressure);
793                     }
794 
795                     XEventClass EventClassMotion;
796                     XEventClass EventClassProximityIn;
797                     XEventClass EventClassProximityOut;
798                     XEventClass EventClassButtonPress;
799                     XEventClass EventClassButtonRelease;
800                     DeviceMotionNotify(EasyTab->Device, EasyTab->MotionType, EventClassMotion);
801                     ProximityIn(EasyTab->Device, EasyTab->ProximityTypeIn, EventClassProximityIn);
802                     ProximityOut(EasyTab->Device, EasyTab->ProximityTypeOut,EventClassProximityOut );
803                     DeviceButtonPress(EasyTab->Device, EasyTab->ButtonTypePress, EventClassButtonPress);
804                     DeviceButtonPress(EasyTab->Device, EasyTab->ButtonTypeRelease, EventClassButtonRelease);
805 
806                     #define APPEND_EVENT_CLASS(EventClass) \
807                         if (EventClass)                                                     \
808                         {                                                                   \
809                             EasyTab->EventClasses[EasyTab->NumEventClasses] = EventClass;   \
810                             EasyTab->NumEventClasses++;                                     \
811                         }
812 
813                     APPEND_EVENT_CLASS(EventClassMotion);
814                     APPEND_EVENT_CLASS(EventClassProximityIn);
815                     APPEND_EVENT_CLASS(EventClassProximityOut);
816 
817                     #undef APPEND_EVENT_CLASS
818                 } break;
819             }
820 
821             ClassPtr = (XAnyClassPtr) ((uint8_t*)ClassPtr + ClassPtr->length); // TODO: Access this as an array to avoid pointer arithmetic?
822         }
823 
824         XSelectExtensionEvent(Disp, Win, EasyTab->EventClasses, EasyTab->NumEventClasses);
825     }
826 
827     XFreeDeviceList(Devices);
828 
829     if (EasyTab->Device != 0) { return EASYTAB_OK; }
830     else                      { return EASYTAB_X11_ERROR; }
831 }
832 
833 
834 #ifdef MILTON_EASYTAB
EasyTab_HandleEvent(XEvent * Event)835 EasyTabResult EasyTab_HandleEvent(XEvent* Event)
836 {
837     EasyTab->NumPackets = 0;
838 
839     if (Event->type == EasyTab->MotionType)
840     {
841         XDeviceMotionEvent* MotionEvent = (XDeviceMotionEvent*)(Event);
842         EasyTab->PosX[0]     = MotionEvent->x;
843         EasyTab->PosY[0]     = MotionEvent->y;
844         EasyTab->Pressure[0] = (float)MotionEvent->axis_data[2] / (float)EasyTab->MaxPressure;
845 
846         if (EasyTab->Pressure[0] > 0.0f)
847         {
848             EasyTab->Buttons |= EasyTab_Buttons_Pen_Touch;
849         }
850         else
851         {
852             EasyTab->Buttons &= ~EasyTab_Buttons_Pen_Touch;
853         }
854 
855         EasyTab->NumPackets = 1;
856     }
857     else if (Event->type == EasyTab->ProximityTypeIn)
858     {
859         EasyTab->PenInProximity = EASYTAB_TRUE;
860     }
861     else if (Event->type == EasyTab->ProximityTypeOut)
862     {
863         EasyTab->PenInProximity = EASYTAB_FALSE;
864     }
865     else if (Event->type == EasyTab->ButtonTypePress)
866     {
867         // TODO: Buttons
868     }
869     else if (Event->type == EasyTab->ButtonTypeRelease)
870     {
871 
872     }
873     else
874     {
875         return EASYTAB_EVENT_NOT_HANDLED;
876     }
877 
878     return EASYTAB_OK;
879 }
880 #else
EasyTab_HandleEvent(XEvent * Event)881 EasyTabResult EasyTab_HandleEvent(XEvent* Event)
882 {
883     if (Event->type != EasyTab->MotionType) { return EASYTAB_EVENT_NOT_HANDLED; }
884 
885     XDeviceMotionEvent* MotionEvent = (XDeviceMotionEvent*)(Event);
886     EasyTab->PosX     = MotionEvent->x;
887     EasyTab->PosY     = MotionEvent->y;
888     EasyTab->Pressure = (float)MotionEvent->axis_data[2] / (float)EasyTab->MaxPressure;
889     return EASYTAB_OK;
890 }
891 #endif
892 
EasyTab_Unload(Display * Disp)893 void EasyTab_Unload(Display* Disp)
894 {
895     XCloseDevice(Disp, EasyTab->Device);
896     free(EasyTab);
897     EasyTab = NULL;
898 }
899 
900 #endif // __DragonFly__
901 
902 
903 // -----------------------------------------------------------------------------
904 // Windows implementation
905 // -----------------------------------------------------------------------------
906 #ifdef WIN32
907 
908 #define GETPROCADDRESS(type, func)                                              \
909     EasyTab->func = (type)GetProcAddress(EasyTab->Dll, #func);                  \
910     if (!EasyTab->func)                                                         \
911     {                                                                           \
912         OutputDebugStringA("Function " #func " not found in Wintab32.dll.\n");  \
913         return EASYTAB_INVALID_FUNCTION_ERROR;                                                           \
914     }
915 
916 
EasyTab_Load(HWND Window)917 EasyTabResult EasyTab_Load(HWND Window)
918 {
919     return EasyTab_Load_Ex(Window, EASYTAB_TRACKING_MODE_SYSTEM, 0, 1);
920 }
921 
EasyTab_Load_Ex(HWND Window,EasyTabTrackingMode TrackingMode,float RelativeModeSensitivity,int32_t MoveCursor)922 EasyTabResult EasyTab_Load_Ex(HWND Window,
923                               EasyTabTrackingMode TrackingMode,
924                               float RelativeModeSensitivity,
925                               int32_t MoveCursor)
926 {
927     EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
928     if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
929 
930 
931     // Load Wintab DLL and get function addresses
932     {
933         EasyTab->Dll = LoadLibraryA("Wintab32.dll");
934         if (!EasyTab->Dll)
935         {
936             OutputDebugStringA("Wintab32.dll not found.\n");
937             free(EasyTab);
938             EasyTab = NULL;
939             return EASYTAB_DLL_LOAD_ERROR;
940         }
941 
942         GETPROCADDRESS(WTINFOA           , WTInfoA);
943         GETPROCADDRESS(WTOPENA           , WTOpenA);
944         GETPROCADDRESS(WTGETA            , WTGetA);
945         GETPROCADDRESS(WTSETA            , WTSetA);
946         GETPROCADDRESS(WTCLOSE           , WTClose);
947         GETPROCADDRESS(WTPACKET          , WTPacket);
948         GETPROCADDRESS(WTENABLE          , WTEnable);
949         GETPROCADDRESS(WTOVERLAP         , WTOverlap);
950         GETPROCADDRESS(WTSAVE            , WTSave);
951         GETPROCADDRESS(WTCONFIG          , WTConfig);
952         GETPROCADDRESS(WTRESTORE         , WTRestore);
953         GETPROCADDRESS(WTEXTSET          , WTExtSet);
954         GETPROCADDRESS(WTEXTGET          , WTExtGet);
955         GETPROCADDRESS(WTQUEUESIZESET    , WTQueueSizeSet);
956         GETPROCADDRESS(WTDATAPEEK        , WTDataPeek);
957         GETPROCADDRESS(WTPACKETSGET      , WTPacketsGet);
958         GETPROCADDRESS(WTMGROPEN         , WTMgrOpen);
959         GETPROCADDRESS(WTMGRCLOSE        , WTMgrClose);
960         GETPROCADDRESS(WTMGRDEFCONTEXT   , WTMgrDefContext);
961         GETPROCADDRESS(WTMGRDEFCONTEXTEX , WTMgrDefContextEx);
962         #ifdef MILTON_EASYTAB
963             GETPROCADDRESS(WTQUEUESIZEGET    , WTQueueSizeGet);  // Note: In wintab samples this is done via #defines
964         #endif
965     }
966 
967     if (!EasyTab->WTInfoA(0, 0, NULL))
968     {
969         OutputDebugStringA("Wintab services not available.\n");
970         return EASYTAB_WACOM_WIN32_ERROR;
971     }
972 
973 #ifdef MILTON_EASYTAB
974     // Note(Sergio): I want about 3 packets per frame. This could be a parameter for Load_Ex
975     UINT DesiredPktRate = 200;
976     {
977         UINT MaxPktRate = 0;
978         // Get maxiumum rate (DVX_PKTRATE)
979         if (EasyTab->WTInfoA(WTI_DEVICES, DVC_PKTRATE, &MaxPktRate))
980         {
981             DesiredPktRate = min(DesiredPktRate, MaxPktRate);
982         }
983     }
984 #endif
985 
986 
987     // Open context
988     {
989         LOGCONTEXTA LogContext = {0};
990         AXIS        RangeX     = {0};
991         AXIS        RangeY     = {0};
992         AXIS        Pressure   = {0};
993 
994         EasyTab->WTInfoA(WTI_DEFSYSCTX, 0, &LogContext);
995         EasyTab->WTInfoA(WTI_DEVICES, DVC_X, &RangeX);
996         EasyTab->WTInfoA(WTI_DEVICES, DVC_Y, &RangeY);
997         EasyTab->WTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
998 
999         LogContext.lcPktData = PACKETDATA;  // Specify the data we want in each packet.
1000         LogContext.lcOptions |= CXO_MESSAGES;
1001         if (MoveCursor) { LogContext.lcOptions |= CXO_SYSTEM; }
1002         LogContext.lcPktMode = PACKETMODE;
1003         LogContext.lcMoveMask = PACKETDATA;
1004         LogContext.lcBtnUpMask = LogContext.lcBtnDnMask;
1005 
1006         #ifdef MILTON_EASYTAB
1007         LogContext.lcPktRate = DesiredPktRate;
1008         #endif
1009 
1010         EasyTab->InputOriginX = LogContext.lcInOrgX;
1011         EasyTab->InputOriginY = LogContext.lcInOrgY;
1012         EasyTab->InputExtentX = LogContext.lcInExtX;
1013         EasyTab->InputExtentY = LogContext.lcInExtY;
1014 
1015         LogContext.lcOutOrgX = 0;
1016         LogContext.lcOutExtX = LogContext.lcInExtX;
1017 
1018         LogContext.lcOutOrgY = 0;
1019         LogContext.lcOutExtY = -LogContext.lcInExtY;
1020 
1021 
1022 
1023         LogContext.lcOutOrgX = 0;
1024         LogContext.lcOutExtX = LogContext.lcInExtX;
1025 
1026         LogContext.lcOutOrgY = 0;
1027         LogContext.lcOutExtY = -LogContext.lcInExtY;
1028 
1029 
1030         EasyTab->OutputOriginX = GetSystemMetrics(SM_XVIRTUALSCREEN); // LogContext.lcOutOrgX;
1031         EasyTab->OutputOriginY = GetSystemMetrics(SM_YVIRTUALSCREEN); // LogContext.lcOutOrgY;
1032         EasyTab->OutputExtentX = GetSystemMetrics( SM_CXVIRTUALSCREEN );
1033         EasyTab->OutputExtentY = GetSystemMetrics( SM_CYVIRTUALSCREEN );
1034 
1035         if (TrackingMode == EASYTAB_TRACKING_MODE_RELATIVE)
1036         {
1037             LogContext.lcPktMode |= PK_X | PK_Y; // TODO: Should this be included in the
1038                                                  //       PACKETMODE macro define up top?
1039             LogContext.lcSysMode = 1;
1040 
1041             if (RelativeModeSensitivity > 1.0f)
1042             {
1043                 RelativeModeSensitivity = 1.0f;
1044             }
1045             else if (RelativeModeSensitivity < 0.0f)
1046             {
1047                 RelativeModeSensitivity = 0.0f;
1048             }
1049 
1050             // Wintab expects sensitivity to be a 32-bit fixed point number
1051             // with the radix point between the two words. Thus, the type
1052             // contains 16 bits to the left of the radix point and 16 bits to
1053             // the right of it.
1054             //
1055             // 0x10000 Hex
1056             // = 65,536 Decimal
1057             // = 0000 0000 0000 0001 . 0000 0000 0000 0000 Binary
1058             // = 1.0 Fixed Point
1059             uint32_t Sensitivity = (uint32_t)(0x10000 * RelativeModeSensitivity);
1060 
1061             if (MoveCursor)
1062             {
1063                 LogContext.lcSysSensX = LogContext.lcSysSensY = Sensitivity;
1064             }
1065             else
1066             {
1067                 LogContext.lcSensX = LogContext.lcSensY = Sensitivity;
1068             }
1069         }
1070 
1071         EasyTab->Context = EasyTab->WTOpenA(Window, &LogContext, TRUE);
1072 
1073         if (!EasyTab->Context)
1074         {
1075             OutputDebugStringA("Wintab context couldn't be opened.\n");
1076             return EASYTAB_WACOM_WIN32_ERROR;
1077         }
1078 
1079         // Get tablet capabilites
1080         {
1081             EasyTab->MaxPressure = Pressure.axMax;
1082             EasyTab->RangeX      = RangeX.axMax;
1083             EasyTab->RangeY      = RangeY.axMax;
1084         }
1085 
1086 #ifdef MILTON_EASYTAB
1087         // Try and set the queue size
1088         int QueueSize = EasyTab->WTQueueSizeGet(EasyTab->Context);
1089         if (!EasyTab->WTQueueSizeSet(EasyTab->Context, EASYTAB_PACKETQUEUE_SIZE))
1090         {
1091             return EASYTAB_QUEUE_SIZE_ERROR;
1092         }
1093 #endif
1094     }
1095 
1096     return EASYTAB_OK;
1097 }
1098 
1099 #undef GETPROCADDRESS
1100 
1101 #ifdef MILTON_EASYTAB
EasyTab_HandleEvent(HWND Window,UINT Message,LPARAM LParam,WPARAM WParam)1102 EasyTabResult EasyTab_HandleEvent(HWND Window, UINT Message, LPARAM LParam, WPARAM WParam)
1103 {
1104     EasyTabResult result = EASYTAB_EVENT_NOT_HANDLED;
1105 
1106     PACKET PacketBuffer[EASYTAB_PACKETQUEUE_SIZE] = {0};
1107 
1108     EasyTab->NumPackets = 0;
1109     if (Message == WT_PACKET)
1110     {
1111         #define EASYTAB_SIGN(val) ( ((val) >= 0) ? 1 : -1 )
1112 
1113         int NumPackets = EasyTab->WTPacketsGet(EasyTab->Context, EASYTAB_PACKETQUEUE_SIZE, PacketBuffer);
1114 
1115         if ( NumPackets ) { EasyTab->Buttons = 0; }
1116         for (int i = 0; i < NumPackets; ++i)
1117         {
1118             float x;
1119             float y;
1120             if (EASYTAB_SIGN(EasyTab->OutputExtentX) == EASYTAB_SIGN(EasyTab->InputExtentX))
1121             {
1122                 x = ((PacketBuffer[i].pkX - EasyTab->InputOriginX) * EASYTAB_ABS(EasyTab->OutputExtentX) / (float)EASYTAB_ABS(EasyTab->InputExtentX)) + EasyTab->OutputOriginX;
1123             }
1124             else
1125             {
1126                 x = EASYTAB_ABS(EasyTab->OutputExtentX) * (EASYTAB_ABS(EasyTab->InputExtentX) - (PacketBuffer[i].pkX - EasyTab->InputOriginX)) / (float)EASYTAB_ABS(EasyTab->InputExtentX) +  EasyTab->OutputOriginX;
1127             }
1128 
1129             if (EASYTAB_SIGN(EasyTab->OutputExtentX) == EASYTAB_SIGN(EasyTab->InputExtentX))
1130             {
1131                 y = ((PacketBuffer[i].pkY - EasyTab->InputOriginY) * EASYTAB_ABS(EasyTab->OutputExtentY) / (float)EASYTAB_ABS(EasyTab->InputExtentY)) + EasyTab->OutputOriginY;
1132             }
1133             else
1134             {
1135                 y = EASYTAB_ABS(EasyTab->OutputExtentY) * (EASYTAB_ABS(EasyTab->InputExtentY) - (PacketBuffer[i].pkY - EasyTab->InputOriginY)) / (float)EASYTAB_ABS(EasyTab->InputExtentY) +  EasyTab->OutputOriginY;
1136             }
1137 
1138 
1139             POINT point = { (long)x, (long)y };
1140 
1141             ScreenToClient(Window, &point);
1142 
1143             EasyTab->PosX[i] = point.x;
1144             EasyTab->PosY[i] = point.y;
1145 
1146             EasyTab->Pressure[i] = (float)PacketBuffer[i].pkNormalPressure / (float)EasyTab->MaxPressure;
1147 
1148             // Setting the Buttons variable if any of the packets had a button pushed
1149             EasyTab->Buttons |= PacketBuffer[i].pkButtons;
1150         }
1151 
1152         // Fill the ergtation of the last packet in the buffer.
1153         if (NumPackets)
1154         {
1155             EasyTab->Orientation.Azimuth = PacketBuffer[NumPackets - 1].pkOrientation.orAzimuth;
1156             EasyTab->Orientation.Altitude = PacketBuffer[NumPackets - 1].pkOrientation.orAltitude;
1157             EasyTab->Orientation.Twist = PacketBuffer[NumPackets - 1].pkOrientation.orTwist;
1158         }
1159 
1160         EasyTab->NumPackets = NumPackets;
1161 
1162         result = EASYTAB_OK;
1163 
1164         #undef EASYTAB_SIGN
1165     }
1166     else if (Message == WT_PROXIMITY &&
1167              (HCTX)WParam == EasyTab->Context)
1168     {
1169         if (LOWORD(LParam) != 0)
1170         {
1171             // Entering context
1172             EasyTab->PenInProximity = EASYTAB_TRUE;
1173         }
1174         else
1175         {
1176             EasyTab->PenInProximity = EASYTAB_FALSE;
1177 
1178         }
1179         result = EASYTAB_OK;
1180         // Alway clear the queue.
1181         EasyTab->WTPacketsGet(EasyTab->Context, EASYTAB_PACKETQUEUE_SIZE+1, NULL);
1182     }
1183     else if (Message == WM_ACTIVATE && EasyTab->Context)
1184     {
1185         // Extract the low word of WParam, which specifies whether the window became active or not
1186         // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms646274.aspx
1187         BOOL Active = (WParam & 0xFFFF) != 0;
1188 
1189         // see http://www.wacomeng.com/windows/docs/NotesForTabletAwarePCDevelopers.html#_Toc274818945
1190         EasyTab->WTEnable(EasyTab->Context, Active);
1191         result = EASYTAB_OK;
1192     }
1193     else if (Message == WT_CTXOVERLAP && EasyTab->Context)
1194     {
1195         if (LParam & CXS_OBSCURED)
1196         {
1197             // We want to be on top even when obscured, because of overlayed
1198             // windows that don't steal focus.
1199             EasyTab->WTOverlap(EasyTab->Context, true);
1200         }
1201         result = EASYTAB_OK;
1202     }
1203     else if (Message == WT_CTXUPDATE)
1204     {
1205         HCTX UpdatedContext = (HCTX)WParam;
1206         result = EASYTAB_OK;
1207     }
1208     else if (Message == WT_CTXOPEN)
1209     {
1210         HCTX NewContext = (HCTX)WParam;
1211         EasyTab->Context = NewContext;
1212         result = EASYTAB_OK;
1213     }
1214     else if (Message == WT_CTXCLOSE)
1215     {
1216         if ((HCTX)WParam == EasyTab->Context)
1217         {
1218             EasyTab->Context = 0;
1219         }
1220         result = EASYTAB_OK;
1221     }
1222     else if (Message == WT_INFOCHANGE)
1223     {
1224         result = EASYTAB_NEEDS_REINIT;
1225     }
1226 
1227     return result;
1228 }
1229 #else
EasyTab_HandleEvent(HWND Window,UINT Message,LPARAM LParam,WPARAM WParam)1230 EasyTabResult EasyTab_HandleEvent(HWND Window, UINT Message, LPARAM LParam, WPARAM WParam)
1231 {
1232     PACKET Packet = { 0 };
1233 
1234     if (Message == WT_PACKET &&
1235         (HCTX)LParam == EasyTab->Context &&
1236         EasyTab->WTPacket(EasyTab->Context, (UINT)WParam, &Packet))
1237     {
1238         POINT Point = { 0 };
1239         Point.x = Packet.pkX;
1240         Point.y = Packet.pkY;
1241         ScreenToClient(Window, &Point);
1242         EasyTab->PosX = Point.x;
1243         EasyTab->PosY = Point.y;
1244 
1245         EasyTab->Pressure = (float)Packet.pkNormalPressure / (float)EasyTab->MaxPressure;
1246         EasyTab->Buttons = Packet.pkButtons;
1247         return EASYTAB_OK;
1248     }
1249 
1250     return EASYTAB_EVENT_NOT_HANDLED;
1251 }
1252 #endif
1253 
EasyTab_Unload()1254 void EasyTab_Unload()
1255 {
1256     if (EasyTab)
1257     {
1258         if (EasyTab->Context && EasyTab->WTClose) { EasyTab->WTClose(EasyTab->Context); }
1259         #ifndef MILTON_EASYTAB
1260         // NOTE(Sergio): Wacom DLL has a memory leak, AppVerifier nags about it
1261         #else
1262         if (EasyTab->Dll)     { FreeLibrary(EasyTab->Dll); }
1263         #endif
1264         free(EasyTab);
1265         EasyTab = NULL;
1266     }
1267 }
1268 
1269 #endif // WIN32
1270 // -----------------------------------------------------------------------------
1271 
1272 
1273 #endif // EASYTAB_IMPLEMENTATION
1274