Tablet PC (Wacom) Pen Programming?

Windows specific questions.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

In the end, I just applied the steps above to the original code.

Here's the modified tilttest.bas:

Code: Select all

' /*----------------------------------------------------------------------------
'
'	NAME
'		TiltTest.c
'
'	PURPOSE
'		Tests pressure, eraser and tilt output
'
'	AUTHORS
'		Based on prstest from LCS Telegraphics  RICO 4/1/92
'		Modified by Ken Loftus @ WACOM Technology Corp 2/15/95
'		Project file created by Kim Ritchie @ WACOM Technology Corp 8/2004
'		Modified by Robert Cohn @ WACOM Technology Corp 2/26/2010
'
'	COPYRIGHT
'		Copyright (C) 1998  LCS/Telegraphics
'		Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved
'		All rights reserved.
'
'---------------------------------------------------------------------------- */

#Include Once "fbgfx.bi" 
#Include Once "windows.bi"
'#include <math.h>
'#include <string.h>

#Include Once "wintab.bi"

#define PACKETDATA (PK_X or PK_Y or PK_BUTTONS or PK_NORMAL_PRESSURE or PK_ORIENTATION or PK_CURSOR)
#define PACKETMODE 0
'#include "pktdef.bi" '// NOTE: get from wactab header package
Type tagPACKET
    As UINT pkCursor
    As DWORD pkButtons
    As Integer pkX
    As Integer pkY
    As UINT pkNormalPressure
    As ORIENTATION pkOrientation
End Type: Type As tagPACKET PACKET
Type As tagPACKET Ptr PPACKET, NPPACKET, LPPACKET

Type tagPACKETEXT
    As EXTENSIONBASE pkBase
End Type: Type As tagPACKETEXT PACKETEXT
Type As tagPACKETEXT Ptr PPACKETEXT, NPPACKETEXT, LPPACKETEXT

'' Tablet data event queue
Type TabletData
    As Point       pt
    As UINT        cur
    As UINT        prs
    As ORIENTATION ort
    As TabletData Ptr nxt
End Type
Dim Shared As TabletData Ptr tdFront = 0, tdBack = 0

Extern fb_hWin32ExtWinProc Alias "fb_hWin32ExtWinProc" As Sub (Byval hWnd As HWND, Byval message As Uinteger, Byval wParam As WPARAM, Byval lParam As LPARAM)
Declare Sub FBWndProc (Byval hWnd As HWND, Byval message As Uinteger, Byval wParam As WPARAM, Byval lParam As LPARAM)

#define WACOM_DEBUG

#include Once "msgpack.bi"
#Include Once "Utils.bi"
#include Once "TiltTest.bi"

' /* converts FIX32 to double */
'#define FIX_DOUBLE(x) ((double)(FIX32_INT(x))+((double)FIX32_FRAC(x)/65536))
#define FIX_DOUBLE(x) (CDbl(x) / 65536.0)
#define pi 3.14159265359

'#ifdef WIN32                                
'#define MoveTo(h,x,y) MoveToEx(h,x,y,NULL)
'#endif

Dim Shared As ZString Ptr gpszProgramName = @"TiltTest"

Dim Shared As HANDLE          hInst               ' /* Handle for instance */
Dim Shared As HCTX            hTab = NULL         ' /* Handle for Tablet Context */
Dim Shared As Point           ptNew               ' /* XY value storage */
Dim Shared As UINT            prsNew              ' /* Pressure value storage */
Dim Shared As UINT            curNew              ' /* Cursor number storage */
Dim Shared As ORIENTATION     ortNew              ' /* Tilt value storage */
'Dim Shared As RECT            rcClient            ' /* Size of current Client */
'Dim Shared As RECT            rcInfoTilt          ' /* Size of tilt info box */
'Dim Shared As RECT            rcInfoName          ' /* Size of cursor name box */
'Dim Shared As RECT            rcInfoGen           ' /* Size of testing box */
'Dim Shared As RECT            rcDraw              ' /* Size of draw area */
Dim Shared As Double          aziFactor = 1       ' /* Azimuth factor */
Dim Shared As Double          altFactor = 1       ' /* Altitude factor */
Dim Shared As Double          altAdjust = 1       ' /* Altitude zero adjust */
Dim Shared As BOOL            tilt_support = TRUE ' /* Is tilt supported */

'FB Entry/Exit Point
End WinMain( GetModuleHandle( NULL ), NULL, Command, SW_NORMAL )

' /* ------------------------------------------------------------------------- */
Function WinMain Pascal (Byval hInstance As HINSTANCE, Byval hPrevInstance As HINSTANCE, Byval lpCmdLine As LPSTR, Byval nCmdShow As Integer) As Integer
    Dim msg_ As MSG
    
    'If hPrevInstance = 0 Then If InitApplication(hInstance) = 0 Then Return FALSE
    
    ' /* Perform initializations that apply to a specific instance */
    If InitInstance(hInstance, nCmdShow) = 0 Then Return FALSE
    
    fb_hWin32ExtWinProc = @FBWndProc

    ' /* Acquire and dispatch messages until a WM_QUIT message is received. */
    'Do While GetMessage(@msg_, NULL, 0, 0) 
    '	TranslateMessage(@msg_)
    '	DispatchMessage(@msg_)
    'Loop
    Do
        Sleep 1
    Loop While Inkey = ""
    
    '// Return Wintab resources.
    Cleanup()
    
    Return msg_.wParam
End Function

'* ------------------------------------------------------------------------- */
#if 0
Function InitApplication(Byval hInstance As HANDLE) As BOOL
	Dim As WNDCLASS wc

	' /* Fill in window class structure with parameters that describe the */
	' /* main window. */
	wc.style = 0
	wc.lpfnWndProc = Procptr(MainWndProc)
	wc.cbClsExtra = 0
	wc.cbWndExtra = 0
	wc.hInstance = hInstance
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION)
	wc.hCursor = LoadCursor(NULL, IDC_ARROW)
	wc.hbrBackground = Cast(HBRUSH, COLOR_APPWORKSPACE + 1)
	wc.lpszMenuName = @"TiltTestMenu"
	wc.lpszClassName = @"TiltTestWClass"
	
	' /* Register the window class and return success/failure code. */
	Return RegisterClass(@wc)
End Function
#endif

' /* ------------------------------------------------------------------------- */
Function InitInstance(Byval hInstance As HANDLE, Byval nCmdShow As Integer) As BOOL
	Dim As HWND            hWnd             ' /* Handle for window */
	Dim As HDC             hDC              ' /* Handle for Device Context */
	'Dim As TEXTMETRIC      textmetric       ' /* Structure for font info */
	'Dim As INTEGER             nLineH           ' /* Holds the text height */
	'Dim As INTEGER             Xinch, Yinch     ' /* Holds the number of pixels per inch */
	'Dim As INTEGER             Hres, Vres       ' /* Holds the screen resolution */
	Dim As ZString*50            WName        ' /* String to hold window name */
	Dim As tagAXIS         TpOri(3) ' /* The capabilities of tilt */
	Dim As Double          tpvar            ' /* A temp for converting fix to double */

	' /* Save the instance handle in static variable, which will be used in  */
	' /* many subsequence calls from this application to Windows.            */
	hInst = hInstance

	If LoadWintab() = 0 Then
		ShowError( "Wintab not available" )
		Return FALSE
	End If

	' /* check if WinTab available. */
	If gpWTInfoA(0, 0, NULL) = 0 Then
		MessageBox(NULL, "WinTab Services Not Available.", gpszProgramName, _ 
			   MB_OK Or MB_ICONHAND)
		Return FALSE
	End If

	' /* check if WACOM available. */
    gpWTInfoA(WTI_DEVICES, DVC_NAME, @WName)
    If Left(WName, 5) <> "WACOM" Then
		MessageBox(NULL, "Wacom Tablet Not Installed.", gpszProgramName, _
		    	   MB_OK Or MB_ICONHAND)
'//      return FALSE;
    End If

	' /* get info about tilt */
	tilt_support = gpWTInfoA(WTI_DEVICES,DVC_ORIENTATION,@TpOri(0))
	If tilt_support Then
		' /* does the tablet support azimuth and altitude */
		If TpOri(0).axResolution Andalso TpOri(1).axResolution Then

			' /* convert azimuth resulution to double */
			tpvar = FIX_DOUBLE(TpOri(0).axResolution)
			' /* convert from resolution to radians */
			aziFactor = tpvar/(2*pi)  
			
			' /* convert altitude resolution to double */
			tpvar = FIX_DOUBLE(TpOri(1).axResolution)
			' /* scale to arbitrary value to get decent line length */ 
			altFactor = tpvar/1000
			 ' /* adjust for maximum value at vertical */
			altAdjust = Cdbl(TpOri(1).axMax/altFactor)
		Else  ' /* no so dont do tilt stuff */
			tilt_support = FALSE
		End If
	End If
	
	' /* Create a main window for this application instance.  */
/'
	wsprintf(WName, "TiltTest:%x", hInst)
	hWnd = CreateWindow( _
		"TiltTestWClass", _
		WName, _
		WS_OVERLAPPEDWINDOW, _
		0, _
		0, _
		CW_USEDEFAULT, _
		CW_USEDEFAULT, _
		NULL, _
		NULL, _
		hInstance, _
		NULL _
	)
	
	' /* If window could not be created, return "failure" */
	If hWnd = 0 Then Return FALSE
'/
	Screenres 640, 480
	Screencontrol(FB.GET_WINDOW_HANDLE , *Cast(Integer Ptr, @hWnd))  
/'
    ' /* Get Device Context and setup a rects  to write packet info */
    hDC = GetDC(hWnd)
    If hDC = 0 Then Return FALSE
    GetTextMetrics(hDC, @textmetric)
    nLineH = textmetric.tmExternalLeading + textmetric.tmHeight
    Xinch = GetDeviceCaps(hDC, LOGPIXELSX)
    Yinch = GetDeviceCaps(hDC, LOGPIXELSY)
    Hres = GetDeviceCaps(hDC, HORZRES)
    Vres = GetDeviceCaps(hDC, VERTRES)
    ReleaseDC(hWnd, hDC)

	GetClientRect(hWnd, @rcClient)
	rcInfoTilt = rcClient
    rcInfoTilt.left   = Xinch / 8
    rcInfoTilt.top    = Yinch / 8
    rcInfoTilt.bottom = rcInfoTilt.top + nLineH
    rcInfoName = rcInfoTilt
    rcInfoName.top    += nLineH
    rcInfoName.bottom += nLineH
    rcInfoGen = rcInfoName
    rcInfoGen.top    += nLineH
    rcInfoGen.bottom += nLineH
    rcDraw = rcInfoGen
    rcDraw.left   = 0
    rcDraw.top   += nLineH
    rcDraw.bottom = rcClient.bottom
'/
	' /* Make the window visible; update its client area; and return "success" */
	'ShowWindow(hWnd, nCmdShow)
	'UpdateWindow(hWnd)
	Return TRUE
End Function

' /* ------------------------------------------------------------------------- */
Function TabletInit(Byval hWnd As HWND) As HCTX
	Dim As LOGCONTEXT      lcMine           ' /* The context of the tablet */
	Dim As AXIS            TabletX, TabletY ' /* The maximum tablet size */

	' /* get default region */
	gpWTInfoA(WTI_DEFCONTEXT, 0, @lcMine)

	' /* modify the digitizing region */
	wsprintf(lcMine.lcName, "TiltTest Digitizing %x", hInst)
	lcMine.lcOptions Or= CXO_MESSAGES
	lcMine.lcPktData = PACKETDATA
	lcMine.lcPktMode = PACKETMODE
	lcMine.lcMoveMask = PACKETDATA
	lcMine.lcBtnUpMask = lcMine.lcBtnDnMask

    ' /* Set the entire tablet as active */
	gpWTInfoA(WTI_DEVICES,DVC_X,@TabletX)
	gpWTInfoA(WTI_DEVICES,DVC_Y,@TabletY)
	lcMine.lcInOrgX = 0
	lcMine.lcInOrgY = 0
	lcMine.lcInExtX = TabletX.axMax
	lcMine.lcInExtY = TabletY.axMax

    ' /* output the data in screen coords */
	lcMine.lcOutOrgX = 0
	lcMine.lcOutOrgY = 0
	lcMine.lcOutExtX = GetSystemMetrics(SM_CXSCREEN)
    ' /* move origin to upper left */
	lcMine.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN)

	' /* open the region */
	Return gpWTOpenA(hWnd, @lcMine, TRUE)
End Function

' /* ------------------------------------------------------------------------- */
Sub FBWndProc (Byval hWnd As HWND, Byval message As Uinteger, Byval wParam As WPARAM, Byval lParam As LPARAM)
    
	Dim As FARPROC         lpProcAbout     ' /* pointer to the about function */
	Dim As HDC             hDC             ' /* handle for Device Context */
	Dim As PAINTSTRUCT     psPaint         ' /* the paint structure */
	Dim As PACKET          pkt             ' /* the current packet */
	Dim As BOOL            fHandled = TRUE ' /* whether the message was handled or not */
	Dim As LRESULT         lResult = 0     ' /* the result of the message */

	Select Case message
		Case WT_PACKET ' /* A packet is waiting from WINTAB */
			If gpWTPacket(Cast(HCTX,lParam), wParam, @pkt) Then
                
                Dim As TabletData Ptr p = New TabletData
                With *p
                    .pt.x = pkt.pkX
                    .pt.y = pkt.pkY
                    .cur = pkt.pkCursor
                    .prs = pkt.pkNormalPressure
                    .ort = pkt.pkOrientation
                    .nxt = 0
                End With
                
                '' push new TabletData event to back of queue
                If tdBack <> 0 Then tdBack->nxt = p
                tdBack = p
                If tdFront = 0 Then tdFront = p
			End If
			
		Case Else
			fHandled = FALSE
	End Select
End Sub


'//////////////////////////////////////////////////////////////////////////////
'// Purpose
'//		Release resources we used in this example.
'//
Sub Cleanup()
	WACOM_TRACE( !"Cleanup()\n" )
	
	UnloadWintab()
End Sub


Sub FBPaint()

    'case WM_PAINT ' /* Paint the window */
    Dim As Integer ZAngle         ' /* Raw Altitude */
    Dim As UINT Theta         ' /* Raw Azimuth */
    Dim As Double ZAngle2     ' /* Adjusted Altitude */
    Dim As Double Theta2      ' /* Adjusted Azimuth */
    Dim As Point Z1Angle      ' /* Rect coords from polar coords */
    Dim As ZString*128 szOutput ' /* String for outputs */
    
    '' fetch new TabletData from front of queue
    Dim As TabletData Ptr p = tdFront
    
    If p <> 0 Then
        With *p
            If tilt_support Then
                ' /* 
                '   wintab.h defines .orAltitude 
                '   as a UINT but documents .orAltitude 
                '   as positive for upward angles 
                '   and negative for downward angles.
                '   WACOM uses negative altitude values to 
                '   show that the pen is inverted; 
                '   therefore we cast .orAltitude as an 
                '   (int) and then use the absolute value. 
                '*/
                ZAngle  = Cint(.ort.orAltitude)
                ZAngle2 = altAdjust - Cdbl(Abs(ZAngle)/altFactor)
                ' /* adjust azimuth */
                Theta  = .ort.orAzimuth
                Theta2 = Cdbl(Theta/aziFactor)
                ' /* get the length of the diagnal to draw */  
                Z1Angle.x = Cint(ZAngle2*Sin(Theta2))
                Z1Angle.y = Cint(ZAngle2*Cos(Theta2))
            Else
                Z1Angle.x = 0
                Z1Angle.y = 0
            End If
            
            'hDC = BeginPaint(hWnd, @psPaint)
            'If hDC Then
            Screenlock
            
                Locate 1
                
                ' /* write raw tilt info */ 
                If tilt_support Then                             
                    'wsprintf(Cast(LPSTR,szOutput), !"Tilt: %03i, Theta: %04u\0", ZAngle,Theta)
                    'szOutput = "Tilt: " & ZAngle & ", Theta: " & Theta
                    Print Using !"Tilt: ###_, Theta: ####\t"; ZAngle; Theta
                Else
                    'strcpy(szOutput,"Tilt not supported.")
                    'szOutput = "Tilt not supported."
                    Print       !"Tilt not supported.    \t"
                End If
                
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoTilt,DT_LEFT)
            
                ' /* write current cursor name */ 
                gpWTInfoA(WTI_CURSORS + .cur, CSR_NAME, @szOutput)
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoName,DT_LEFT)
                Print szOutput & !"\t"
                
                ' /* write tablet name */
                gpWTInfoA(WTI_DEVICES, DVC_NAME, @szOutput)
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoGen,DT_LEFT)
                Print szOutput & !"\t"
                
                ' /* draw circle based on tablet pressure */
                'Ellipse(hDC, ptNew.x - prsNew, ptNew.y - prsNew, _
                '        ptNew.x + prsNew, ptNew.y + prsNew)
                Circle (ptNew.x, ptNew.y), .prs, 1
            
                ' /* draw a line based on tablet tilt */
                'MoveTo(hDC,ptNew.x,ptNew.y)
                'LineTo(hDC,ptNew.x + Z1Angle.x,ptNew.y - Z1Angle.y)
                Line (.pt.x, .pt.y) - Step(Z1Angle.x, Z1Angle.y), 4
                
                ' /* draw CROSS based on tablet position */ 
                'MoveTo(hDC,ptNew.x - 20,ptNew.y     )
                'LineTo(hDC,ptNew.x + 20,ptNew.y     )
                'MoveTo(hDC,ptNew.x     ,ptNew.y - 20)
                'LineTo(hDC,ptNew.x     ,ptNew.y + 20)
                Line (.pt.x - 20, .pt.y) - Step(40, 0), 2
                Line (.pt.x, .pt.y - 20) - Step(0, 40), 2
                
                'EndPaint(hWnd, @psPaint)
            Screenunlock
            
        End With
        
        '' pop/delete TabletData event
        tdFront = p->nxt
        If tdFront = 0 Then tdBack = 0
        Delete p
        
    End If
    
End Sub
It's still a bit of a mess though. Probably there's still a lot of stuff that doesn't need to be there.

A simple patch like this one is needed to the gfxlib:

Code: Select all

 src/gfxlib2/win32/gfx_win32.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/gfxlib2/win32/gfx_win32.c b/src/gfxlib2/win32/gfx_win32.c
index 15842f5..91ed9ff 100644
--- a/src/gfxlib2/win32/gfx_win32.c
+++ b/src/gfxlib2/win32/gfx_win32.c
@@ -133,6 +133,11 @@ static BOOL WINAPI fb_hTrackMouseEvent(TRACKMOUSEEVENT *e)
 	return FALSE;
 }
 
+
+/* callback to be implemented by programmer */
+extern FBCALL void (*fb_hWin32ExtWinProc)(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+FBCALL void (*fb_hWin32ExtWinProc)(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) = 0;
+
 LRESULT CALLBACK fb_hWin32WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
 	BYTE key_state[256];
@@ -144,6 +149,11 @@ LRESULT CALLBACK fb_hWin32WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
 	BOOL is_minimized;
 	MINMAXINFO *mmi;
 
+	if (fb_hWin32ExtWinProc != 0)
+	{
+		fb_hWin32ExtWinProc(hWnd, message, wParam, lParam);
+	}
+
 	e.type = 0;
 
 	GetClientRect(fb_win32.wnd, rect);
(EDIT: added to github as a branch off 0.24 here: https://github.com/countingpine/fbc/commit/extwndproc)

Note: Everything compiles and links, but I can't test because I don't have a tablet or the DLL.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

You were probably going to ask for this, so here's a link to a modified TiltTest project:

https://www.dropbox.com/s/lwwvebxev486h ... FB_new.zip

It includes the updated TiltTest.bas (with the original renamed), a recompiled version of 0.24's gfxlib (libfbgfx.a) with the patch I gave above, which needs to replace the original in your FB installation (which I recommend backing up first).

And lastly, it includes a newly built version of TiltTest.exe, which should hopefully work right out of the box.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Seems like we're close. When I run your EXE, I get a nice FB graphics window and the Wacom pen pulls focus when I tap in the window. When I try to compile the project myself, I get the error msgs below (I did copy over the patched lib). When I'm able to compile myself, I'll verify that pen values are being pulled in OK. Thanks for your effort -

C:\Program Files (x86)\FreeBASIC\fbc -s gui "TiltTest.bas" "TILTTEST.RC" "Utils.bas"
C:\Program Files (x86)\FreeBASIC\lib\win32/libfbgfx.a(gfx_inkey.o):gfx_inkey.c:(.text+0x14c): undefined reference to `fb_hMakeInkeyStr'

Build error(s)
C:\Program Files (x86)\FreeBASIC\fbc -s gui "TiltTest.bas" "TILTTEST.RC" "Utils.bas"
C:\Program Files (x86)\FreeBASIC\lib\win32/libfbgfx.a(gfx_inkey.o):gfx_inkey.c:(.text+0x14c): undefined reference to `fb_hMakeInkeyStr'

Build error(s)
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

Perhaps a new copy of the rtlib is also needed. I will remake both when I got the chance..
It is discouraging that the pen is not making marks in the window. It should look similar to what is seen in the original TiltTest.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Thanks for your continued effort. Almost every one of the new Windows 8 touchscreen hardware has Wacom-compatible drivers underneath, so I'm hoping someone with more programing savvy than I can try out and expt with your code. I would send you my Cintiq tablet to test on, but it weighs 30 lb and is extremely delicate! Let me know when/if you want me to test the next iteration.
Alan
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

OK, I've recompiled the gxlib2 again from scratch, dropped it into my 0.24.0 installation, and it worked fine. I've also recompiled the rtlib (although I disabled ffi to avoid some hassle, so Threadcall won't work).
Both sets of libraries are included in the new archive and should work fine in tandem, but again you should only need the single gfx one - the other library files are included "just in case", and I advise trying them only if it doesn't work without.
https://www.dropbox.com/s/gv6jxnpvmmkeh ... estFB2.zip
(File size: 587,492 bytes, md5sum: 210dd50db000c9f0efabc7776b2fcade)
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: Tablet PC (Wacom) Pen Programming?

Post by gothon »

Hi, counting_pine, I am having trouble with the zip files. I cannot open the archive with 7-zip or with windows, furthermore the file seems to be slightly (by just a couple bytes) different in size every time I download it??

I'll see if I can compile the libraries myself but it will take me some time to set up the tool chain as prescribed in the docs: http://www.freebasic.net/wiki/wikka.php?wakka=DevBuild
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

Sorry, I don't know why you're having troubles. I just downloaded it successfully from the above link, and a quick test with 7-zip didn't reveal any problems. I've updated my above post to give the md5sum and size in bytes.
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: Tablet PC (Wacom) Pen Programming?

Post by gothon »

Indeed it is odd, the file I'm getting is only 29k (~29,726 bytes). Not anywhere near the 587,492 bytes you reported.

Oh, apparently I didn't distinguish the download page from the file itself because of the download page having the .zip file extension. I have extracted it now, no need to set up MinGW/MSYS.
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: Tablet PC (Wacom) Pen Programming?

Post by gothon »

Ok, only a few bugs I had to fix to get it working.

First, you never call TabletInit (and hence gpWTOpenA) which means that the tablet is never captured. Second you never call FBPaint, so the screen ends up being blank anyway. After those issues are fixed all you have is some minor rendering stuff. I added a cls call and fixed the coordinates of the circle to the new values, and I also filled in the circle to make it easier to see.

With those changes the code works ok with my tablet, but the code could definitely be cleaned up and simplified.

TiltTest.bas

Code: Select all


' /*----------------------------------------------------------------------------
'
'	NAME
'		TiltTest.c
'
'	PURPOSE
'		Tests pressure, eraser and tilt output
'
'	AUTHORS
'		Based on prstest from LCS Telegraphics  RICO 4/1/92
'		Modified by Ken Loftus @ WACOM Technology Corp 2/15/95
'		Project file created by Kim Ritchie @ WACOM Technology Corp 8/2004
'		Modified by Robert Cohn @ WACOM Technology Corp 2/26/2010
'
'	COPYRIGHT
'		Copyright (C) 1998  LCS/Telegraphics
'		Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved
'		All rights reserved.
'
'---------------------------------------------------------------------------- */

#Include Once "fbgfx.bi" 
#Include Once "windows.bi"
'#include <math.h>
'#include <string.h>

#Include Once "wintab.bi"

#define PACKETDATA (PK_X or PK_Y or PK_BUTTONS or PK_NORMAL_PRESSURE or PK_ORIENTATION or PK_CURSOR)
#define PACKETMODE 0
'#include "pktdef.bi" '// NOTE: get from wactab header package
type tagPACKET
    As UINT pkCursor
    As DWORD pkButtons
    As INTEGER pkX
    As INTEGER pkY
    As UINT pkNormalPressure
    As ORIENTATION pkOrientation
end type: type as tagPACKET PACKET
type as tagPACKET PTR PPACKET, NPPACKET, LPPACKET

type tagPACKETEXT
    As EXTENSIONBASE pkBase
end type: type as tagPACKETEXT PACKETEXT
type as tagPACKETEXT PTR PPACKETEXT, NPPACKETEXT, LPPACKETEXT

'' Tablet data event queue
type TabletData
    As POINT       pt
    As UINT        cur
    As UINT        prs
    As ORIENTATION ort
    As TabletData ptr nxt
end type
dim shared as TabletData ptr tdFront = 0, tdBack = 0

Extern fb_hWin32ExtWinProc alias "fb_hWin32ExtWinProc" as sub (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
Declare Sub FBWndProc (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
Declare Function TabletInit(ByVal hWnd As HWND) As HCTX
Declare Sub FBPaint()

#define WACOM_DEBUG

#include Once "msgpack.bi"
#Include Once "Utils.bi"
#include Once "TiltTest.bi"

' /* converts FIX32 to double */
'#define FIX_DOUBLE(x) ((double)(FIX32_INT(x))+((double)FIX32_FRAC(x)/65536))
#define FIX_DOUBLE(x) (CDbl(x) / 65536.0)
#define pi 3.14159265359

'#ifdef WIN32                                
'#define MoveTo(h,x,y) MoveToEx(h,x,y,NULL)
'#endif

Dim Shared As ZString Ptr gpszProgramName = @"TiltTest"

Dim Shared As HANDLE          hInst               ' /* Handle for instance */
Dim Shared As HCTX            hTab = NULL         ' /* Handle for Tablet Context */
Dim Shared As POINT           ptNew               ' /* XY value storage */
Dim Shared As UINT            prsNew              ' /* Pressure value storage */
Dim Shared As UINT            curNew              ' /* Cursor number storage */
Dim Shared As ORIENTATION     ortNew              ' /* Tilt value storage */
'Dim Shared As RECT            rcClient            ' /* Size of current Client */
'Dim Shared As RECT            rcInfoTilt          ' /* Size of tilt info box */
'Dim Shared As RECT            rcInfoName          ' /* Size of cursor name box */
'Dim Shared As RECT            rcInfoGen           ' /* Size of testing box */
'Dim Shared As RECT            rcDraw              ' /* Size of draw area */
Dim Shared As double          aziFactor = 1       ' /* Azimuth factor */
Dim Shared As double          altFactor = 1       ' /* Altitude factor */
Dim Shared As double          altAdjust = 1       ' /* Altitude zero adjust */
Dim Shared As BOOL            tilt_support = TRUE ' /* Is tilt supported */

'FB Entry/Exit Point
End WinMain( GetModuleHandle( NULL ), NULL, Command, SW_NORMAL )

' /* ------------------------------------------------------------------------- */
Function WinMain PASCAL (ByVal hInstance As HINSTANCE, ByVal hPrevInstance As HINSTANCE, ByVal lpCmdLine As LPSTR, ByVal nCmdShow As Integer) As Integer
    Dim msg_ As MSG
    
    'If hPrevInstance = 0 Then If InitApplication(hInstance) = 0 Then Return FALSE
    
    ' /* Perform initializations that apply to a specific instance */
    If InitInstance(hInstance, nCmdShow) = 0 Then Return FALSE
    
    fb_hWin32ExtWinProc = @FBWndProc

    ' /* Acquire and dispatch messages until a WM_QUIT message is received. */
    'Do While GetMessage(@msg_, NULL, 0, 0) 
    '	TranslateMessage(@msg_)
    '	DispatchMessage(@msg_)
    'Loop
    do
        sleep 1
        FBPaint
    loop while inkey = ""
    
    '// Return Wintab resources.
    Cleanup()
    
    Return msg_.wParam
End Function

'* ------------------------------------------------------------------------- */
#if 0
Function InitApplication(ByVal hInstance As HANDLE) As BOOL
	Dim As WNDCLASS wc

	' /* Fill in window class structure with parameters that describe the */
	' /* main window. */
	wc.style = 0
	wc.lpfnWndProc = ProcPtr(MainWndProc)
	wc.cbClsExtra = 0
	wc.cbWndExtra = 0
	wc.hInstance = hInstance
	wc.hIcon = LoadIcon(NULL, IDI_APPLICATION)
	wc.hCursor = LoadCursor(NULL, IDC_ARROW)
	wc.hbrBackground = Cast(HBRUSH, COLOR_APPWORKSPACE + 1)
	wc.lpszMenuName = @"TiltTestMenu"
	wc.lpszClassName = @"TiltTestWClass"
	
	' /* Register the window class and return success/failure code. */
	return RegisterClass(@wc)
End Function
#endif

' /* ------------------------------------------------------------------------- */
Function InitInstance(ByVal hInstance As HANDLE, ByVal nCmdShow As INTEGER) As BOOL
	Dim As HWND            hWnd             ' /* Handle for window */
	Dim As HDC             hDC              ' /* Handle for Device Context */
	'Dim As TEXTMETRIC      textmetric       ' /* Structure for font info */
	'Dim As INTEGER             nLineH           ' /* Holds the text height */
	'Dim As INTEGER             Xinch, Yinch     ' /* Holds the number of pixels per inch */
	'Dim As INTEGER             Hres, Vres       ' /* Holds the screen resolution */
	Dim As ZString*50            WName        ' /* String to hold window name */
	Dim As tagAXIS         TpOri(3) ' /* The capabilities of tilt */
	Dim As double          tpvar            ' /* A temp for converting fix to double */

	' /* Save the instance handle in static variable, which will be used in  */
	' /* many subsequence calls from this application to Windows.            */
	hInst = hInstance

	If LoadWintab() = 0 Then
		ShowError( "Wintab not available" )
		return FALSE
	End If

	' /* check if WinTab available. */
	If gpWTInfoA(0, 0, NULL) = 0 Then
		MessageBox(NULL, "WinTab Services Not Available.", gpszProgramName, _ 
			   MB_OK Or MB_ICONHAND)
		return FALSE
	End If

	' /* check if WACOM available. */
    gpWTInfoA(WTI_DEVICES, DVC_NAME, @WName)
    If Left(WName, 5) <> "WACOM" Then
		MessageBox(NULL, "Wacom Tablet Not Installed.", gpszProgramName, _
		    	   MB_OK Or MB_ICONHAND)
'//      return FALSE;
    End If

	' /* get info about tilt */
	tilt_support = gpWTInfoA(WTI_DEVICES,DVC_ORIENTATION,@TpOri(0))
	If tilt_support Then
		' /* does the tablet support azimuth and altitude */
		If TpOri(0).axResolution AndAlso TpOri(1).axResolution Then

			' /* convert azimuth resulution to double */
			tpvar = FIX_DOUBLE(TpOri(0).axResolution)
			' /* convert from resolution to radians */
			aziFactor = tpvar/(2*pi)  
			
			' /* convert altitude resolution to double */
			tpvar = FIX_DOUBLE(TpOri(1).axResolution)
			' /* scale to arbitrary value to get decent line length */ 
			altFactor = tpvar/1000
			 ' /* adjust for maximum value at vertical */
			altAdjust = CDbl(TpOri(1).axMax/altFactor)
		Else  ' /* no so dont do tilt stuff */
			tilt_support = FALSE
		End If
	End If
	
	' /* Create a main window for this application instance.  */
/'
	wsprintf(WName, "TiltTest:%x", hInst)
	hWnd = CreateWindow( _
		"TiltTestWClass", _
		WName, _
		WS_OVERLAPPEDWINDOW, _
		0, _
		0, _
		CW_USEDEFAULT, _
		CW_USEDEFAULT, _
		NULL, _
		NULL, _
		hInstance, _
		NULL _
	)
	
	' /* If window could not be created, return "failure" */
	If hWnd = 0 Then Return FALSE
'/
	screenres 640, 480
	Screencontrol(FB.GET_WINDOW_HANDLE , *Cast(Integer Ptr, @hWnd))
	hTab = TabletInit(hWnd)
	If hTab = 0 Then
		MessageBox(NULL, " Could Not Open Tablet Context.", "WinTab", _ 
		   MB_OK Or MB_ICONHAND)
		End
	End If
/'
    ' /* Get Device Context and setup a rects  to write packet info */
    hDC = GetDC(hWnd)
    If hDC = 0 Then Return FALSE
    GetTextMetrics(hDC, @textmetric)
    nLineH = textmetric.tmExternalLeading + textmetric.tmHeight
    Xinch = GetDeviceCaps(hDC, LOGPIXELSX)
    Yinch = GetDeviceCaps(hDC, LOGPIXELSY)
    Hres = GetDeviceCaps(hDC, HORZRES)
    Vres = GetDeviceCaps(hDC, VERTRES)
    ReleaseDC(hWnd, hDC)

	GetClientRect(hWnd, @rcClient)
	rcInfoTilt = rcClient
    rcInfoTilt.left   = Xinch / 8
    rcInfoTilt.top    = Yinch / 8
    rcInfoTilt.bottom = rcInfoTilt.top + nLineH
    rcInfoName = rcInfoTilt
    rcInfoName.top    += nLineH
    rcInfoName.bottom += nLineH
    rcInfoGen = rcInfoName
    rcInfoGen.top    += nLineH
    rcInfoGen.bottom += nLineH
    rcDraw = rcInfoGen
    rcDraw.left   = 0
    rcDraw.top   += nLineH
    rcDraw.bottom = rcClient.bottom
'/
	' /* Make the window visible; update its client area; and return "success" */
	'ShowWindow(hWnd, nCmdShow)
	'UpdateWindow(hWnd)
	return TRUE
End Function

' /* ------------------------------------------------------------------------- */
Function TabletInit(ByVal hWnd As HWND) As HCTX
	Dim As LOGCONTEXT      lcMine           ' /* The context of the tablet */
	Dim As AXIS            TabletX, TabletY ' /* The maximum tablet size */

	' /* get default region */
	gpWTInfoA(WTI_DEFCONTEXT, 0, @lcMine)

	' /* modify the digitizing region */
	wsprintf(lcMine.lcName, "TiltTest Digitizing %x", hInst)
	lcMine.lcOptions Or= CXO_MESSAGES
	lcMine.lcPktData = PACKETDATA
	lcMine.lcPktMode = PACKETMODE
	lcMine.lcMoveMask = PACKETDATA
	lcMine.lcBtnUpMask = lcMine.lcBtnDnMask

    ' /* Set the entire tablet as active */
	gpWTInfoA(WTI_DEVICES,DVC_X,@TabletX)
	gpWTInfoA(WTI_DEVICES,DVC_Y,@TabletY)
	lcMine.lcInOrgX = 0
	lcMine.lcInOrgY = 0
	lcMine.lcInExtX = TabletX.axMax
	lcMine.lcInExtY = TabletY.axMax

    ' /* output the data in screen coords */
	lcMine.lcOutOrgX = 0
	lcMine.lcOutOrgY = 0
	lcMine.lcOutExtX = GetSystemMetrics(SM_CXSCREEN)
    ' /* move origin to upper left */
	lcMine.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN)

	' /* open the region */
	return gpWTOpenA(hWnd, @lcMine, TRUE)
End Function

' /* ------------------------------------------------------------------------- */
Sub FBWndProc (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
    
	Dim As FARPROC         lpProcAbout     ' /* pointer to the about function */
	Dim As HDC             hDC             ' /* handle for Device Context */
	Dim As PAINTSTRUCT     psPaint         ' /* the paint structure */
	Dim As PACKET          pkt             ' /* the current packet */
	Dim As BOOL            fHandled = TRUE ' /* whether the message was handled or not */
	Dim As LRESULT         lResult = 0     ' /* the result of the message */

	Select Case message
		case WT_PACKET ' /* A packet is waiting from WINTAB */
			If gpWTPacket(Cast(HCTX,lParam), wParam, @pkt) Then
                
                dim as TabletData ptr p = new TabletData
                with *p
                    .pt.x = pkt.pkX
                    .pt.y = pkt.pkY
                    .cur = pkt.pkCursor
                    .prs = pkt.pkNormalPressure
                    .ort = pkt.pkOrientation
                    .nxt = 0
                end with
                
                '' push new TabletData event to back of queue
                if tdBack <> 0 then tdBack->nxt = p
                tdBack = p
                if tdFront = 0 then tdFront = p
			End If
			
		Case Else
			fHandled = FALSE
	End Select
End Sub


'//////////////////////////////////////////////////////////////////////////////
'// Purpose
'//		Release resources we used in this example.
'//
Sub Cleanup()
	WACOM_TRACE( !"Cleanup()\n" )
	
	UnloadWintab()
End Sub


Sub FBPaint()

    'case WM_PAINT ' /* Paint the window */
    Dim As Integer ZAngle         ' /* Raw Altitude */
    Dim As UINT Theta         ' /* Raw Azimuth */
    Dim As double ZAngle2     ' /* Adjusted Altitude */
    Dim As double Theta2      ' /* Adjusted Azimuth */
    Dim As POINT Z1Angle      ' /* Rect coords from polar coords */
    Dim As ZString*128 szOutput ' /* String for outputs */
    
    '' fetch new TabletData from front of queue
    dim as TabletData ptr p = tdFront
    
    if p <> 0 then
        with *p
            If tilt_support Then
                ' /* 
                '   wintab.h defines .orAltitude 
                '   as a UINT but documents .orAltitude 
                '   as positive for upward angles 
                '   and negative for downward angles.
                '   WACOM uses negative altitude values to 
                '   show that the pen is inverted; 
                '   therefore we cast .orAltitude as an 
                '   (int) and then use the absolute value. 
                '*/
                ZAngle  = CInt(.ort.orAltitude)
                ZAngle2 = altAdjust - CDbl(Abs(ZAngle)/altFactor)
                ' /* adjust azimuth */
                Theta  = .ort.orAzimuth
                Theta2 = CDbl(Theta/aziFactor)
                ' /* get the length of the diagnal to draw */  
                Z1Angle.x = CInt(ZAngle2*sin(Theta2))
                Z1Angle.y = CInt(ZAngle2*cos(Theta2))
            Else
                Z1Angle.x = 0
                Z1Angle.y = 0
            End If
            
            'hDC = BeginPaint(hWnd, @psPaint)
            'If hDC Then
            screenlock
                Cls
                locate 1
                
                ' /* write raw tilt info */ 
                If tilt_support Then                             
                    'wsprintf(Cast(LPSTR,szOutput), !"Tilt: %03i, Theta: %04u\0", ZAngle,Theta)
                    'szOutput = "Tilt: " & ZAngle & ", Theta: " & Theta
                    print using !"Tilt: ###_, Theta: ####\t"; ZAngle; Theta
                Else
                    'strcpy(szOutput,"Tilt not supported.")
                    'szOutput = "Tilt not supported."
                    print       !"Tilt not supported.    \t"
                End If
                
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoTilt,DT_LEFT)
            
                ' /* write current cursor name */ 
                gpWTInfoA(WTI_CURSORS + .cur, CSR_NAME, @szOutput)
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoName,DT_LEFT)
                print szOutput & !"\t"
                
                ' /* write tablet name */
                gpWTInfoA(WTI_DEVICES, DVC_NAME, @szOutput)
                'DrawText(hDC,szOutput,len(szOutput),@rcInfoGen,DT_LEFT)
                print szOutput & !"\t"
                
                ' /* draw circle based on tablet pressure */
                'Ellipse(hDC, ptNew.x - prsNew, ptNew.y - prsNew, _
                '        ptNew.x + prsNew, ptNew.y + prsNew)
                circle (.pt.x, .pt.y), .prs, 1,,,, F
            
                ' /* draw a line based on tablet tilt */
                'MoveTo(hDC,ptNew.x,ptNew.y)
                'LineTo(hDC,ptNew.x + Z1Angle.x,ptNew.y - Z1Angle.y)
                line (.pt.x, .pt.y) - step(Z1Angle.x, Z1Angle.y), 4
                
                ' /* draw CROSS based on tablet position */ 
                'MoveTo(hDC,ptNew.x - 20,ptNew.y     )
                'LineTo(hDC,ptNew.x + 20,ptNew.y     )
                'MoveTo(hDC,ptNew.x     ,ptNew.y - 20)
                'LineTo(hDC,ptNew.x     ,ptNew.y + 20)
                line (.pt.x - 20, .pt.y) - step(40, 0), 2
                line (.pt.x, .pt.y - 20) - step(0, 40), 2
                
                'EndPaint(hWnd, @psPaint)
            screenunlock
            
        end with
        
        '' pop/delete TabletData event
        tdFront = p->nxt
        if tdFront = 0 then tdBack = 0
        delete p
        
    end if
    
End Sub

counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

Thanks, some silly mistakes there.
I left a lot of old code in as comments, which could obviously be removed. Beyond that I'm not sure how easy it will be to work out what can stay and what can go.
The other thing that's probably worth doing is to write a simple wrapper function to fetch the tablet events, rather than having to deal with pointers and stuff.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

I am grateful to everyone's efforts in getting to some code that lets me move forward with my research. I took the liberty of making a correction in how pen tilt is shown, and I broke out the X and Y components of tilt and a few other changes at the top. There's still one major issue, which is that the X and Y coordinates refer to the tablet's full screen coordinates and not to the active window. This is *not* a problem for me, since I will use only a full-screen FB graphics window. Other FB programmers may want the option, tho, and figuring out the fix is beyond my powers.

Here's the code with my very minor tweaks:

Code: Select all


    ' /*----------------------------------------------------------------------------
    '
    '   NAME
    '      TiltTest.c
    '
    '   PURPOSE
    '      Tests pressure, eraser and tilt output
    '
    '   AUTHORS
    '      Based on prstest from LCS Telegraphics  RICO 4/1/92
    '      Modified by Ken Loftus @ WACOM Technology Corp 2/15/95
    '      Project file created by Kim Ritchie @ WACOM Technology Corp 8/2004
    '      Modified by Robert Cohn @ WACOM Technology Corp 2/26/2010
    '
    '   COPYRIGHT
    '      Copyright (C) 1998  LCS/Telegraphics
    '      Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved
    '      All rights reserved.
    '
    '---------------------------------------------------------------------------- */

    #Include Once "fbgfx.bi"
    #Include Once "windows.bi"
    '#include <math.h>
    '#include <string.h>

    #Include Once "wintab.bi"

    #define PACKETDATA (PK_X or PK_Y or PK_BUTTONS or PK_NORMAL_PRESSURE or PK_ORIENTATION or PK_CURSOR)
    #define PACKETMODE 0
    '#include "pktdef.bi" '// NOTE: get from wactab header package
    type tagPACKET
        As UINT pkCursor
        As DWORD pkButtons
        As INTEGER pkX
        As INTEGER pkY
        As UINT pkNormalPressure
        As ORIENTATION pkOrientation
    end type: type as tagPACKET PACKET
    type as tagPACKET PTR PPACKET, NPPACKET, LPPACKET

    type tagPACKETEXT
        As EXTENSIONBASE pkBase
    end type: type as tagPACKETEXT PACKETEXT
    type as tagPACKETEXT PTR PPACKETEXT, NPPACKETEXT, LPPACKETEXT

    '' Tablet data event queue
    type TabletData
        As POINT       pt
        As UINT        cur
        As UINT        prs
        As ORIENTATION ort
        As TabletData ptr nxt
    end type
    dim shared as TabletData ptr tdFront = 0, tdBack = 0

    Extern fb_hWin32ExtWinProc alias "fb_hWin32ExtWinProc" as sub (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
    Declare Sub FBWndProc (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
    Declare Function TabletInit(ByVal hWnd As HWND) As HCTX
    Declare Sub FBPaint()

    #define WACOM_DEBUG

    #include Once "msgpack.bi"
    #Include Once "Utils.bi"
    #include Once "TiltTest.bi"

    ' /* converts FIX32 to double */
    '#define FIX_DOUBLE(x) ((double)(FIX32_INT(x))+((double)FIX32_FRAC(x)/65536))
    #define FIX_DOUBLE(x) (CDbl(x) / 65536.0)
    #define pi 3.14159265359

    '#ifdef WIN32                               
    '#define MoveTo(h,x,y) MoveToEx(h,x,y,NULL)
    '#endif

    Dim Shared As ZString Ptr gpszProgramName = @"TiltTest"

    Dim Shared As HANDLE          hInst               ' /* Handle for instance */
    Dim Shared As HCTX            hTab = NULL         ' /* Handle for Tablet Context */
    Dim Shared As POINT           ptNew               ' /* XY value storage */
    Dim Shared As UINT            prsNew              ' /* Pressure value storage */
    Dim Shared As UINT            curNew              ' /* Cursor number storage */
    Dim Shared As ORIENTATION     ortNew              ' /* Tilt value storage */
    'Dim Shared As RECT            rcClient            ' /* Size of current Client */
    'Dim Shared As RECT            rcInfoTilt          ' /* Size of tilt info box */
    'Dim Shared As RECT            rcInfoName          ' /* Size of cursor name box */
    'Dim Shared As RECT            rcInfoGen           ' /* Size of testing box */
    'Dim Shared As RECT            rcDraw              ' /* Size of draw area */
    Dim Shared As double          aziFactor = 1       ' /* Azimuth factor */
    Dim Shared As double          altFactor = 1       ' /* Altitude factor */
    Dim Shared As double          altAdjust = 1       ' /* Altitude zero adjust */
    Dim Shared As BOOL            tilt_support = TRUE ' /* Is tilt supported */

    'FB Entry/Exit Point
    End WinMain( GetModuleHandle( NULL ), NULL, Command, SW_NORMAL )

    ' /* ------------------------------------------------------------------------- */
    Function WinMain PASCAL (ByVal hInstance As HINSTANCE, ByVal hPrevInstance As HINSTANCE, ByVal lpCmdLine As LPSTR, ByVal nCmdShow As Integer) As Integer
        Dim msg_ As MSG
       
        'If hPrevInstance = 0 Then If InitApplication(hInstance) = 0 Then Return FALSE
       
        ' /* Perform initializations that apply to a specific instance */
        If InitInstance(hInstance, nCmdShow) = 0 Then Return FALSE
       
        fb_hWin32ExtWinProc = @FBWndProc

        ' /* Acquire and dispatch messages until a WM_QUIT message is received. */
        'Do While GetMessage(@msg_, NULL, 0, 0)
        '   TranslateMessage(@msg_)
        '   DispatchMessage(@msg_)
        'Loop
        do
            sleep 1
            FBPaint
        loop while inkey = ""
       
        '// Return Wintab resources.
        Cleanup()
       
        Return msg_.wParam
    End Function

    '* ------------------------------------------------------------------------- */
    #if 0
    Function InitApplication(ByVal hInstance As HANDLE) As BOOL
       Dim As WNDCLASS wc

       ' /* Fill in window class structure with parameters that describe the */
       ' /* main window. */
       wc.style = 0
       wc.lpfnWndProc = ProcPtr(MainWndProc)
       wc.cbClsExtra = 0
       wc.cbWndExtra = 0
       wc.hInstance = hInstance
       wc.hIcon = LoadIcon(NULL, IDI_APPLICATION)
       wc.hCursor = LoadCursor(NULL, IDC_ARROW)
       wc.hbrBackground = Cast(HBRUSH, COLOR_APPWORKSPACE + 1)
       wc.lpszMenuName = @"TiltTestMenu"
       wc.lpszClassName = @"TiltTestWClass"
       
       ' /* Register the window class and return success/failure code. */
       return RegisterClass(@wc)
    End Function
    #endif

    ' /* ------------------------------------------------------------------------- */
    Function InitInstance(ByVal hInstance As HANDLE, ByVal nCmdShow As INTEGER) As BOOL
       Dim As HWND            hWnd             ' /* Handle for window */
       Dim As HDC             hDC              ' /* Handle for Device Context */
       'Dim As TEXTMETRIC      textmetric       ' /* Structure for font info */
       'Dim As INTEGER             nLineH           ' /* Holds the text height */
       'Dim As INTEGER             Xinch, Yinch     ' /* Holds the number of pixels per inch */
       'Dim As INTEGER             Hres, Vres       ' /* Holds the screen resolution */
       Dim As ZString*50            WName        ' /* String to hold window name */
       Dim As tagAXIS         TpOri(3) ' /* The capabilities of tilt */
       Dim As double          tpvar            ' /* A temp for converting fix to double */

       ' /* Save the instance handle in static variable, which will be used in  */
       ' /* many subsequence calls from this application to Windows.            */
       hInst = hInstance

       If LoadWintab() = 0 Then
          ShowError( "Wintab not available" )
          return FALSE
       End If

       ' /* check if WinTab available. */
       If gpWTInfoA(0, 0, NULL) = 0 Then
          MessageBox(NULL, "WinTab Services Not Available.", gpszProgramName, _
                MB_OK Or MB_ICONHAND)
          return FALSE
       End If

       ' /* check if WACOM available. */
        gpWTInfoA(WTI_DEVICES, DVC_NAME, @WName)
        If Left(WName, 5) <> "WACOM" Then
          MessageBox(NULL, "Wacom Tablet Not Installed.", gpszProgramName, _
                    MB_OK Or MB_ICONHAND)
    '//      return FALSE;
        End If

       ' /* get info about tilt */
       tilt_support = gpWTInfoA(WTI_DEVICES,DVC_ORIENTATION,@TpOri(0))
       If tilt_support Then
          ' /* does the tablet support azimuth and altitude */
          If TpOri(0).axResolution AndAlso TpOri(1).axResolution Then

             ' /* convert azimuth resulution to double */
             tpvar = FIX_DOUBLE(TpOri(0).axResolution)
             ' /* convert from resolution to radians */
             aziFactor = tpvar/(2*pi) 
             
             ' /* convert altitude resolution to double */
             tpvar = FIX_DOUBLE(TpOri(1).axResolution)
             ' /* scale to arbitrary value to get decent line length */
             altFactor = tpvar/1000
              ' /* adjust for maximum value at vertical */
             altAdjust = CDbl(TpOri(1).axMax/altFactor)
          Else  ' /* no so dont do tilt stuff */
             tilt_support = FALSE
          End If
       End If
       
       ' /* Create a main window for this application instance.  */
    /'
       wsprintf(WName, "TiltTest:%x", hInst)
       hWnd = CreateWindow( _
          "TiltTestWClass", _
          WName, _
          WS_OVERLAPPEDWINDOW, _
          0, _
          0, _
          CW_USEDEFAULT, _
          CW_USEDEFAULT, _
          NULL, _
          NULL, _
          hInstance, _
          NULL _
       )
       
       ' /* If window could not be created, return "failure" */
       If hWnd = 0 Then Return FALSE
    '/
    'Changed res to show better that coordinates refer to tablet and not window reference frame.
           SCREENRES 800,600,8
              Screencontrol(FB.GET_WINDOW_HANDLE , *Cast(Integer Ptr, @hWnd))
       hTab = TabletInit(hWnd)
       If hTab = 0 Then
          MessageBox(NULL, " Could Not Open Tablet Context.", "WinTab", _
             MB_OK Or MB_ICONHAND)
          End
       End If
    /'
        ' /* Get Device Context and setup a rects  to write packet info */
        hDC = GetDC(hWnd)
        If hDC = 0 Then Return FALSE
        GetTextMetrics(hDC, @textmetric)
        nLineH = textmetric.tmExternalLeading + textmetric.tmHeight
        Xinch = GetDeviceCaps(hDC, LOGPIXELSX)
        Yinch = GetDeviceCaps(hDC, LOGPIXELSY)
        Hres = GetDeviceCaps(hDC, HORZRES)
        Vres = GetDeviceCaps(hDC, VERTRES)
        ReleaseDC(hWnd, hDC)

       GetClientRect(hWnd, @rcClient)
       rcInfoTilt = rcClient
        rcInfoTilt.left   = Xinch / 8
        rcInfoTilt.top    = Yinch / 8
        rcInfoTilt.bottom = rcInfoTilt.top + nLineH
        rcInfoName = rcInfoTilt
        rcInfoName.top    += nLineH
        rcInfoName.bottom += nLineH
        rcInfoGen = rcInfoName
        rcInfoGen.top    += nLineH
        rcInfoGen.bottom += nLineH
        rcDraw = rcInfoGen
        rcDraw.left   = 0
        rcDraw.top   += nLineH
        rcDraw.bottom = rcClient.bottom
    '/
       ' /* Make the window visible; update its client area; and return "success" */
       'ShowWindow(hWnd, nCmdShow)
       'UpdateWindow(hWnd)
       return TRUE
    End Function

    ' /* ------------------------------------------------------------------------- */
    Function TabletInit(ByVal hWnd As HWND) As HCTX
       Dim As LOGCONTEXT      lcMine           ' /* The context of the tablet */
       Dim As AXIS            TabletX, TabletY ' /* The maximum tablet size */

       ' /* get default region */
       gpWTInfoA(WTI_DEFCONTEXT, 0, @lcMine)

       ' /* modify the digitizing region */
       wsprintf(lcMine.lcName, "TiltTest Digitizing %x", hInst)
       lcMine.lcOptions Or= CXO_MESSAGES
       lcMine.lcPktData = PACKETDATA
       lcMine.lcPktMode = PACKETMODE
       lcMine.lcMoveMask = PACKETDATA
       lcMine.lcBtnUpMask = lcMine.lcBtnDnMask

        ' /* Set the entire tablet as active */
       gpWTInfoA(WTI_DEVICES,DVC_X,@TabletX)
       gpWTInfoA(WTI_DEVICES,DVC_Y,@TabletY)
       lcMine.lcInOrgX = 0
       lcMine.lcInOrgY = 0
       lcMine.lcInExtX = TabletX.axMax
       lcMine.lcInExtY = TabletY.axMax

        ' /* output the data in screen coords */
       lcMine.lcOutOrgX = 0
       lcMine.lcOutOrgY = 0
       lcMine.lcOutExtX = GetSystemMetrics(SM_CXSCREEN)
        ' /* move origin to upper left */
       lcMine.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN)

       ' /* open the region */
       return gpWTOpenA(hWnd, @lcMine, TRUE)
    End Function

    ' /* ------------------------------------------------------------------------- */
    Sub FBWndProc (ByVal hWnd As HWND, ByVal message As UINTEGER, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
       
       Dim As FARPROC         lpProcAbout     ' /* pointer to the about function */
       Dim As HDC             hDC             ' /* handle for Device Context */
       Dim As PAINTSTRUCT     psPaint         ' /* the paint structure */
       Dim As PACKET          pkt             ' /* the current packet */
       Dim As BOOL            fHandled = TRUE ' /* whether the message was handled or not */
       Dim As LRESULT         lResult = 0     ' /* the result of the message */

       Select Case message
          case WT_PACKET ' /* A packet is waiting from WINTAB */
             If gpWTPacket(Cast(HCTX,lParam), wParam, @pkt) Then
                   
                    dim as TabletData ptr p = new TabletData
                    with *p
                        .pt.x = pkt.pkX
                        .pt.y = pkt.pkY
                        .cur = pkt.pkCursor
                        .prs = pkt.pkNormalPressure
                        .ort = pkt.pkOrientation
                        .nxt = 0
                    end with
                   
                    '' push new TabletData event to back of queue
                    if tdBack <> 0 then tdBack->nxt = p
                    tdBack = p
                    if tdFront = 0 then tdFront = p
             End If
             
          Case Else
             fHandled = FALSE
       End Select
    End Sub


    '//////////////////////////////////////////////////////////////////////////////
    '// Purpose
    '//      Release resources we used in this example.
    '//
    Sub Cleanup()
       WACOM_TRACE( !"Cleanup()\n" )
       
       UnloadWintab()
    End Sub


    Sub FBPaint()

        'case WM_PAINT ' /* Paint the window */
        Dim As Integer ZAngle         ' /* Raw Altitude */
        Dim As UINT Theta         ' /* Raw Azimuth */
        Dim As double ZAngle2     ' /* Adjusted Altitude */
        Dim As double Theta2      ' /* Adjusted Azimuth */
        Dim As POINT Z1Angle      ' /* Rect coords from polar coords */
        Dim As ZString*128 szOutput ' /* String for outputs */
       
        '' fetch new TabletData from front of queue
        dim as TabletData ptr p = tdFront
       
        if p <> 0 then
            with *p
                If tilt_support Then
                    ' /*
                    '   wintab.h defines .orAltitude
                    '   as a UINT but documents .orAltitude
                    '   as positive for upward angles
                    '   and negative for downward angles.
                    '   WACOM uses negative altitude values to
                    '   show that the pen is inverted;
                    '   therefore we cast .orAltitude as an
                    '   (int) and then use the absolute value.
                    '*/
                    ZAngle  = CInt(.ort.orAltitude)
                    ZAngle2 = altAdjust - CDbl(Abs(ZAngle)/altFactor)
                    ' /* adjust azimuth */
                    Theta  = .ort.orAzimuth
                    Theta2 = CDbl(Theta/aziFactor)
                    ' /* get the length of the diagnal to draw */ 
                    Z1Angle.x = CInt(ZAngle2*sin(Theta2))
                    Z1Angle.y = CInt(ZAngle2*cos(Theta2))
                Else
                    Z1Angle.x = 0
                    Z1Angle.y = 0
                End If
               
                'hDC = BeginPaint(hWnd, @psPaint)
                'If hDC Then
                ScreenLock
                    Cls
                    locate 3
                    print Using "X-Pos: ####"; .pt.x
                    Print Using "Y-Pos: ####"; .pt.y 
                    print Using "Press: #####"; .prs   
                    ' /* write raw tilt info */
                    If tilt_support Then                             
                        'wsprintf(Cast(LPSTR,szOutput), !"Tilt: %03i, Theta: %04u\0", ZAngle,Theta)
                        'szOutput = "Tilt: " & ZAngle & ", Theta: " & Theta
                        'print using !"Tilt: ###_, Theta: ####\t"; ZAngle; Theta
                        print using "TiltX: ####";Z1Angle.x
                        print using "TiltY: ####";Z1Angle.y
                        print using "Theta: ####";Theta
                    		 
                    Else
                        'strcpy(szOutput,"Tilt not supported.")
                        'szOutput = "Tilt not supported."
                        print       !"Tilt not supported.    \t"
                    End If
                   
                    'DrawText(hDC,szOutput,len(szOutput),@rcInfoTilt,DT_LEFT)
                          
                   
                    ' /* write tablet name */
                    gpWTInfoA(WTI_DEVICES, DVC_NAME, @szOutput)
                    'DrawText(hDC,szOutput,len(szOutput),@rcInfoGen,DT_LEFT)
                    Locate 1
                    print szOutput & !"\t"
                 
                    ' /* write current cursor name */
                    gpWTInfoA(WTI_CURSORS + .cur, CSR_NAME, @szOutput)
                    'DrawText(hDC,szOutput,len(szOutput),@rcInfoName,DT_LEFT)
                    Locate 2
                    print szOutput & !"\t"
                       
                    ' /* draw circle based on tablet pressure */
                    'Ellipse(hDC, ptNew.x - prsNew, ptNew.y - prsNew, _
                    '        ptNew.x + prsNew, ptNew.y + prsNew)
                    circle (.pt.x, .pt.y), .prs\10, 1,,,, F
               	  
               	  
               	  
                    ' /* draw a line based on tablet tilt */
                    'MoveTo(hDC,ptNew.x,ptNew.y)
                    'LineTo(hDC,ptNew.x + Z1Angle.x,ptNew.y - Z1Angle.y)
                    'line (.pt.x, .pt.y) - step(Z1Angle.x, Z1Angle.y), 4
                    'Fix line drawn in wrong direction.
                    Line (.pt.x, .pt.y) - step(Z1Angle.x, -Z1Angle.y), 4
                    ' /* draw CROSS based on tablet position */
                    'MoveTo(hDC,ptNew.x - 20,ptNew.y     )
                    'LineTo(hDC,ptNew.x + 20,ptNew.y     )
                    'MoveTo(hDC,ptNew.x     ,ptNew.y - 20)
                    'LineTo(hDC,ptNew.x     ,ptNew.y + 20)
                    line (.pt.x - 20, .pt.y) - step(40, 0), 2
                    line (.pt.x, .pt.y - 20) - step(0, 40), 2
                   
                    'EndPaint(hWnd, @psPaint)
                ScreenUnLock
               
            end with
           
            '' pop/delete TabletData event
            tdFront = p->nxt
            if tdFront = 0 then tdBack = 0
            delete p
           
        end if
       
    End Sub

counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Tablet PC (Wacom) Pen Programming?

Post by counting_pine »

OK, this is untested, but the changes to allow for the window coordinates should look something like this:

Code: Select all

...
    Select Case message
        case WT_PACKET ' /* A packet is waiting from WINTAB */

    If gpWTPacket(Cast(HCTX,lParam), wParam, @pkt) Then

    dim as TabletData ptr p = new TabletData
        dim as RECT rcClient                '<---
        GetClientRect(hWnd, @rcClient)      '<---
        with *p
            .pt.x = pkt.pkX - rcClient.left '<---
            .pt.y = pkt.pkY - rcClient.top  '<---
...
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Sorry for the delay in getting back to you. The extra code to get and subtract off the client window top and left coordinates produced zeroes, leaving pt.x and pt.y to show the overall screen coordinates as before. Happy to try any other ideas, and I promise a quicker turnaround!
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

I think I discovered the problem. The GetClientRect func only returns values for the right and bottom values of the rectangle; top and right are designed to return zeroes. When I changed the code appropriately, it works! I'll post all my changes when they're in readable form.

Thanks for all your help. Would very much appreciate the necessary patch to gfxlib to make this work in the new version of FB.
Post Reply