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 »

Based on http://support.microsoft.com/kb/11570, I imagine the fix looks 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)      '<---
        ClientToScreen(hwnd, cast(LPPOINT, @rMyRect.left));      '<---
        ClientToScreen(hwnd, cast(LPPOINT, @rMyRect.right));     '<---
        with *p
            .pt.x = pkt.pkX - rcClient.left '<---
            .pt.y = pkt.pkY - rcClient.top  '<---
...
I haven't tried, but I think for most purposes you can (probably) drop 0.24.0's gfxlib into 0.90.
But perhaps once the code is finalised I'll think about getting around to a new TiltTest bundle.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Here's the code that works for me. It now displays the coords for the tablet surface as a whole, and within the FB window. Had to use a little hackery to get the latter, as you'll see. Haven't tried your latest solution, which is surely more elegant. I'll let you know whether the old gfxlib works with the new FB -

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 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"
    #define FIX_DOUBLE(x) (CDbl(x) / 65536.0)
    #define pi 3.14159265359

    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 */
    'Restored these DIMS.
    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            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 */
    'Added global vars to set window size, necessary for pen coords.
    Dim Shared As Integer         ScreenHeight, Screenwidth, WindowOffset

    '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
     
        ' /* Perform initializations that apply to a specific instance */
        If InitInstance(hInstance, nCmdShow) = 0 Then Return FALSE
       
        fb_hWin32ExtWinProc = @FBWndProc

        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
    '/
    'Changed to a higher resolution for demo; need vars for later pen coords. 
       ScreenHeight = 768: ScreenWidth = 1024
       ScreenRes ScreenWidth,ScreenHeight,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
       
       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
                    
                    'We use GetWindowRect because it provides all four RECT cordinates.
                    'rcClient was dimensioned globally at beginning. 
                    GetWindowRect(hWnd, @rcClient)
                    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

    Sub Cleanup()
       WACOM_TRACE( !"Cleanup()\n" )      
       UnloadWintab()
    End Sub


    Sub FBPaint()

        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
                    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
   
                ScreenLock
                    Cls
                    locate 3
                    'Coordinates refer at first to entire tablet surface.
                    print Using "ScrnX: ####"; .pt.x
                    Print Using "ScrnY: ####"; .pt.y
                    
                    'Now for demo purposes let .pt.x and .pt.y be set to client window.
                    .pt.x = .pt.x - rcClient.left
                    .pt.y = .pt.y - rcClient.top
                    
                    'Top of client window includes width of control bar in Aero, so we 
                    ' need to calculate this width and subtract it off to set pen Y-coord.
                    ' I know there's a better way that relies on determining WINVER.

                    WindowOffset = rcClient.bottom - rcClient.top - ScreenHeight
                    .pt.y = .pt.y - WindowOffset  
                    
                    print Using "WindX: ####"; .pt.x 
                    Print Using "WindY: ####"; .pt.y 
                   
                    print Using "Press: #####"; .prs   
                    ' /* write raw tilt info */
                    If tilt_support Then                             
                        print using "TiltX: ####";Z1Angle.x
                        print using "TiltY: ####";Z1Angle.y
                        print using "Theta: ####";Theta
                    		 
                    Else
                        print       !"Tilt not supported.    \t"
                    End If
                   
                    ' /* write tablet name */
                    gpWTInfoA(WTI_DEVICES, DVC_NAME, @szOutput)
                    Locate 1
                    print szOutput & !"\t"
                    gpWTInfoA(WTI_CURSORS + .cur, CSR_NAME, @szOutput)
                    Locate 2
                    print szOutput & !"\t"
                    circle (.pt.x, .pt.y), .prs\10, 1,,,, F
                    Line (.pt.x, .pt.y) - step(Z1Angle.x, -Z1Angle.y), 4
                    line (.pt.x - 20, .pt.y) - step(40, 0), 2
                    line (.pt.x, .pt.y - 20) - step(0, 40), 2
                    ScreenUnLock
               
            end with
           
            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, new download link. I cleaned up some of the formatting in TiltTest.bas (mainly just case changes and indentation), applied and fixed my suggested patch for the window positioning fix, and made a new version of libfbgfx.a for version 0.90.0.
The result compiles but is untested.
https://www.dropbox.com/s/jmy31llm0euca ... B_0.90.zip
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Thanks!
I get this build error when I try to compile both my .BAS code and yours under FB .90 with the new gfx lib.

Code: Select all

C:\Program Files (x86)\FreeBASIC90\fbc -s gui "TiltTest.bas" "TILTTEST.RC" "Utils.bas"
TiltTest.o:fake:(.text+0x3d): undefined reference to `fb_hWin32ExtWinProc'
Both my code and yours compile fine under FB .24.
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 »

It works for me. I just installed into a fresh directory (c:\fb90), copied my libfbgfx.a into C:\fb90\lib\win32 - overwriting the original there - and running 'c:\fb90\fbc TiltTest.bas Util.bas', and it worked fine. But I could reproduce the error by reinstating the original libfbgfx.bi.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Whoops, forgot to copy your modded .a file over to the FB .90 LIB folder. That fixed it! All's well. Many thx.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

This is an old thread because I had to suspend the project for other priorities. I believe I have some time to pick it up again. I wonder if I could ask you to make modded libfbgfx files for FB 1.0.5 as you did for ver 0.90 so that I can resume with the newest version of FB? Thanks in advance.
Alan
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Tablet PC (Wacom) Pen Programming?

Post by St_W »

Do you really need a modified gfxlib for that?

Can't you simply subclass the gfxlib window to handle the relevant window messages yourself and pass everything else to gfxlib's default window procedure? You can get the window handle with the ScreenControl function and use SetWindowLongPtr to override the default window procedure.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

I regret that what you're proposing is beyond my knowledge. I had my application code working with the modded lib and have my hands full with just that (it's the basis of a psych experiment). I could upload my code here so you could mod it to work with the std lib, but I would not want to impose. I'm hopeful that the lib mod is just an easy patch. Otherwise, I'll stick with 0.90. Thanks tho -
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Tablet PC (Wacom) Pen Programming?

Post by St_W »

Actually the implementation is pretty simple and probably sounds more complicated than it is. I've written an example for you:

Code: Select all

#Include "windows.bi"
#Include "fbgfx.bi"

Declare Function FbGfxWindow(hWnd As HWND, msg As UINT, wParam As WPARAM, lParam As LPARAM) As LRESULT

'initialize screen here
ScreenRes 300, 200, 32


Dim hWndFbGfx As HWND
ScreenControl FB.GET_WINDOW_HANDLE, Cast(Integer, hWndFbGfx)

Dim Shared fbGfxWndProc As WNDPROC
fbGfxWndProc = Cast(WNDPROC, SetWindowLongPtr(hWndFbGfx, GWLP_WNDPROC, Cast(LONG_PTR, @FbGfxWindow)))

Function FbGfxWindow(hWnd As HWND, msg As UINT, wParam As WPARAM, lParam As LPARAM) As LRESULT
	
	'call your WndProc hook or handle the relevant window messages here
	'return 0 if the message was processed by your code and shouldn't be processed by gfxlib2
	'e.g.:
	'fb_hWin32ExtWinProc(hWnd, msg, wParam, lParam)
	
	Return CallWindowProc(fbGfxWndProc, hWnd, msg, wParam, lParam)
	
End Function
You just need to call (or do) your message processing inside the FbGfxWindow function as the code-comment explains.

If you've any further questions regarding the code or its integration don't hesitate to ask. You could also upload your code and I'll try to integrate it for you.
The advantage of this method is that it would work with any FB version.
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 »

I'd be in favour of a more elegant solution, particularly because I don't actually have ready access to the Windows build environment at the moment.
Although last time I remember setting it up it was fairly easy to do following the instructions at DevBuildWindows, and would probably only take an hour or so. If you want a new build of the gfxlib, you might prefer to try it yourself, rather than wait for me to get myself sorted out with it.

All that said, I think St_W's approach is probably the better in any case.
St_W
Posts: 1619
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Tablet PC (Wacom) Pen Programming?

Post by St_W »

I have a build environment ready to use (on the CI machine), but I'd really suggest to try to get it working with the default (unmodified) gfxlib2 first. If that doesn't work you can still resort to the old approach and build a modified gfxlib2 (or I could do that for you). The build environment is quite straightforward to set up as counting_pine already said.
fridlund
Posts: 24
Joined: Jun 03, 2007 15:24
Location: Southern California

Re: Tablet PC (Wacom) Pen Programming?

Post by fridlund »

Thank you both for your advice and expertise. I'll try adapting my code as you suggest St_W according to the examples you provided and I'll get back to you. If it doesn't work I'll ask C_P for the gfxlib2 changes I need to make and I'll try to build the mod lib myself. I wish I had more time to dive in to FB and manage an elegant solution that I can grok, but I have to get something working even if it's an ungraceful hack.
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 »

As best I can recall, the only changes I made to the gfxlib were in https://github.com/countingpine/fbc/commit/extwndproc. They will probably apply cleanly to the latest version, or the changes can be made manually.
Post Reply