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