using System; using System.Runtime.InteropServices; using System.Reflection; //Access the Wacom or Genius tablet digitizer through wintab32.dll //Written by Karl Lilje 2008 //Version 1.0 /* Usage: CTablet tablet = new CTablet( this.Handle, this.Width, this.Height); in your form(this) add the function: protected override void WndProc(ref Message m) { if ( m.Msg == CTablet.WT_PACKET ) { tablet.Packet( m.LParam, m.WParam ); } base.WndProc (ref m); } */ //now you can query tablet for X, Y, Z, Pressure, Puck ID //Automatically sets the tablet to move the mouse cursor and click buttons namespace StereoPaint3 { [StructLayout(LayoutKind.Explicit)] public struct CONTEXT { [FieldOffset(0)][MarshalAs( UnmanagedType.ByValTStr, SizeConst=40)] public string lcName ; [FieldOffset(40)] public int lcOptions; [FieldOffset(44)] public int lcStatus; [FieldOffset(48)]public int lcLocks; [FieldOffset(52)]public int lcMsgBase; [FieldOffset(56)]public int lcDevice; [FieldOffset(60)]public int lcPktRate; [FieldOffset(64)]public int lcPktData; [FieldOffset(68)]public int lcPktMode; [FieldOffset(72)]public int lcMoveMask; [FieldOffset(76)]public int lcBtnDnMask; [FieldOffset(80)]public int lcBtnUpMask; [FieldOffset(84)]public int lcInOrgX; [FieldOffset(88)]public int lcInOrgY; [FieldOffset(92)]public int lcInOrgZ; [FieldOffset(96)]public int lcInExtX; [FieldOffset(100)]public int lcInExtY; [FieldOffset(104)]public int lcInExtZ; [FieldOffset(108)]public int lcOutOrgX; [FieldOffset(112)]public int lcOutOrgY; [FieldOffset(116)]public int lcOutOrgZ; [FieldOffset(120)]public int lcOutExtX; [FieldOffset(124)]public int lcOutExtY; [FieldOffset(128)]public int lcOutExtZ; [FieldOffset(132)]public int lcSensX; [FieldOffset(136)]public int lcSensY; [FieldOffset(140)]public int lcSensZ; [FieldOffset(144)]public int lcSysMode; [FieldOffset(148)]public int lcSysOrgX; [FieldOffset(152)]public int lcSysOrgY; [FieldOffset(156)]public int lcSysExtX; [FieldOffset(160)]public int lcSysExtY; [FieldOffset(164)]public int lcSysSensX; [FieldOffset(168)]public int lcSysSensY; } //change this according to your packet required public struct structPACKET { //public int pkStatus; //public int pkTime; //public int pkSerial; public int pkCursor; public int pkButtons; public int pkX; public int pkY; public int pkZ; public int pkNormalPressure; //public int pkTangentPressure; //public int pkAzimuth; //public int pkAltitude; //public int pkTwist; //public int pkPitch; //public int pkRoll; //public int pkYaw; //[MarshalAs(UnmanagedType.ByValTStr, SizeConst=1024)] public string extra; } /// /// /// public class CTablet { [DllImport("wintab32.dll")] static extern uint WTInfo(uint a, uint b, ref CONTEXT c); [DllImport("wintab32.dll")] static extern uint WTInfo(uint a, uint b, ref int c); [DllImport("wintab32.dll")] static extern IntPtr WTOpen(IntPtr a, ref CONTEXT b, bool v); [DllImport("wintab32.dll")] static extern int WTPacket(IntPtr hCtx, int wSerial, ref structPACKET p); [DllImport("wintab32.dll")] static extern bool WTClose(IntPtr a); // Get default context information IntPtr Handle = IntPtr.Zero; public bool TabletAvailable = false; public int Pressure = 0; public int X = 0; public int Y = 0; public int Z = 0; public int Buttons = 0; uint WTI_DEFSYSCTX = 4; public const short WT_DEFBASE = 0x7ff0; public const short WT_MAXOFFSET = 0xF; public const int WT_PACKET = WT_DEFBASE + 0; public const short CXO_MESSAGES = 0x0004; public const short PK_CURSOR = 0x0020; //the PUCK number public const short PK_BUTTONS = 0x0040; public const short PK_X = 0x0080; public const short PK_Y = 0x0100; public const short PK_Z = 0x0200; public const short PK_NORMAL_PRESSURE = 0x0400; //this works in conjunction with the structPACKET structure //see the Wintab documentation from Wacom for more information public const short PACKETDATA = PK_CURSOR | PK_X | PK_Y | PK_Z | PK_NORMAL_PRESSURE | PK_BUTTONS; CONTEXT Context = new CONTEXT(); //winhandle = handle of the window that will receive tablet messages //usually Form1.Handle (this.Handle) public CTablet( IntPtr winhandle, int w, int h ) { Console.WriteLine( "Load Wintab.dll..." ); CONTEXT ret = new CONTEXT(); Handle=(IntPtr)WTInfo( 0,0, ref ret); if ( Handle == IntPtr.Zero ) return ; TabletAvailable = true; WTInfo( WTI_DEFSYSCTX, 0, ref Context ); //Console.WriteLine( "Tablet loaded, Handle = " + Handle ); Console.WriteLine( "Tablet: " + Context.lcName ); Context.lcPktData = PACKETDATA ; Context.lcPktMode = 0; Context.lcMoveMask = PACKETDATA; Context.lcOptions |= CXO_MESSAGES; //notify window of packets Context.lcOutOrgX = 0; Context.lcOutOrgY = 0; Context.lcOutExtX = w; Context.lcOutExtY = -h; Handle = WTOpen( winhandle, ref Context, true ); Console.WriteLine( "loaded, Handle = " + Handle ); } //call this from the window that was registered in the constructor //from the WndProc override. It decodes the packet message public void Packet( IntPtr LPARAM, IntPtr WPARAM) { structPACKET pkt = new structPACKET(); WTPacket((IntPtr)LPARAM, (int)WPARAM, ref pkt); X = pkt.pkX; Y = pkt.pkY; Z = pkt.pkZ; Buttons = pkt.pkButtons ; Pressure = pkt.pkNormalPressure ; } ~CTablet( ) { bool b = WTClose( Handle ); TabletAvailable = false; //Console.WriteLine ( "Closed : " + b ); } } }