/******************************************************************************
*                                                                             *
*  File Name   : WRTSAMPL.C                                                   *
*                                                                             *
*  Description : Example of WRT APIs                                          *
*                                                                             *
*  Function:  This is a sample of all Wrt APIs                                *
*                                                                             *
*  Copyright (C) 1993 IBM Corporation                                         *
*                                                                             *
*      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is            *
*      sample code created by IBM Corporation. This sample code is not        *
*      part of any standard or IBM product and is provided to you solely      *
*      for  the purpose of assisting you in the development of your           *
*      applications.  The code is provided "AS IS", without                   *
*      warranty of any kind.  IBM shall not be liable for any damages         *
*      arising out of your use of the sample code, even if they have been     *
*      advised of the possibility of such damages.                            * 
*                                                                             *
*******************************************************************************/

#define INCL_DOS
#define INCL_PM
#define INCL_GPI
#define INCL_DOSMEMMGR
#define  INCL_WINLOAD
#define  INCL_DOSPROCESS
#define  INCL_DOSSEMAPHORES
#include <os2.h>

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <process.h>

#include <penpm.h>

#define  WRTSAMPL_MAIN
#include "wrtsampl.h"
HWND       hwndClient;
HWND       hwndFrame;
HWND       hwndTFrame;
HAB        habTMain;
HWND       hwndT2Frame;          /* For the LiftOff thread. */
HAB        habT2Main;            /* For the LiftOff thread. */
ULONG      uMsgLeft = 0L;
TID        tidLiftOffT;
SHORT      sLastP = 0;           /* Last pressure of the point on the line */
SHORT      sCurrP = 0;           /* Current pressure of the point on the line */
LONG       lLastWidth = 1L;      /* Last width of line drawned */


int main()
{
  HMQ   hmqMain;
  QMSG  qmsgMain;
  ULONG flCreate;

  /****************************************************************************/
  /* Initialize PM for this program and create its PM message queue.          */
  /****************************************************************************/
  habMain = WinInitialize( (ULONG) NULL );
  hmqMain = WinCreateMsgQueue( habMain, 0L );


  /****************************************************************************/
  /* Register "ClientWndProc" as the handling procedure for the "MyClient"    */
  /* class window.                                                            */
  /****************************************************************************/
  WinRegisterClass( habMain,
                    "MyClient",
                    (PFNWP)ClientWndProc,
                    CS_SIZEREDRAW,
                    0UL );

  /****************************************************************************/
  /* Tell PM that we want the standard frame window, but we will set the      */
  /* the size and position the frame window.  This frame window will          */
  /* surround a "MyClient" class client window.                               */
  /****************************************************************************/
    flCreate =  FCF_STANDARD & ~FCF_SHELLPOSITION;

  hwndFrame = WinCreateStdWindow( HWND_DESKTOP,
                                  0L,
                                  (PULONG)&flCreate,
                                  "MyClient",
                                  "wrtsampl",
                                  0L,
                                  (HMODULE)NULL,
                                  ID_MAIN,
                                  (PHWND)&hwndClient );

  /****************************************************************************/
  /* Tell PM to display our window at the designated size and place           */
  /****************************************************************************/
  WinSetWindowPos( hwndFrame,
                   HWND_TOP,
                   50,50,550,380,
                   SWP_SIZE | SWP_MOVE | SWP_ACTIVATE | SWP_SHOW );


  /****************************************************************************/
  /* This while loop waits for messages from PM.  If not a WM_CLOSE msg,      */
  /* then we dispatch the message to our client window procedure.             */
  /****************************************************************************/
  while( WinGetMsg( habMain, &qmsgMain, (HWND) NULL, 0, 0 ) )
  {
    WinDispatchMsg( habMain, &qmsgMain );
  }

  /****************************************************************************/
  /* We will drop out of the while loop if the program receives a WM_CLOSE    */
  /* message.  We must destroy our PM resources and return to the             */
  /* invoking procedure.                                                      */
  /****************************************************************************/
  WinDestroyWindow( hwndFrame );
  WinDestroyMsgQueue( hmqMain );
  WinTerminate( habMain );
  return( 0 );
}

MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  HPS               hpsPaint;
  RECTL             rcClient;
  ULONG             ulBuflen, ulOptions, flAuxData;
  PSTROKEDATA       psdCurStroke;
  ULONG             ulfButton;
  APIRET            irc;               /* return code from Wrt APIs           */
  ULONG             ulLocatorID;       /* variable for Locator IDs            */
  WRTDISPLAYDEVINFO dcInfo;            /* Display capabilities structure      */
  ULONG             ulDisplayID;       /* variable for Display IDs            */
  WRTSYSTEMINFO     scInfo;            /* System capabilities structure       */
  CHAR              cbuffer[MAXCBUFFER];
  LONG              lvalue;            /* variable to hold system value       */
  ULONG             ulid;
  INT               i;
  POINTL            ptlXY;
  SHORT             *psCurrP;             /* pointer to get the pressure during WM_LIFTOFF */
  static SWP        swpClient;
  static HPOINTER   hptrClient;
  static HPS        hpsClient;
  static ULONG      MouMovCount = 0L;
  static ULONG      MouseDivide =1L;
  static BOOL       btoggle_mouse_sense = FALSE;
  static BOOL       btoggle_strick_mous = FALSE;
  static BOOL       bTouchDown = FALSE;
  static BOOL       fButton1Down = FALSE;
  static BOOL       fButton2Down = FALSE;

  switch( msg )
  {
    case WM_CREATE:
    {
      /************************************************************************/
      /* The APIs being used in this procedure depend on the Pen for OS/2     */
      /* subsystem being correctly initialized.  Thus we check to make sure   */
      /* Pen for OS/2 is up before we do anything else.                       */
      /************************************************************************/

      if( ( irc = WrtWaitActive ( WRT_IMMEDIATE_RETURN ) ) != WRT_NO_ERROR )
      {
        /**********************************************************************/
        /* If Pen for OS/2 is NOT active then put up a message box and        */
        /* terminate the program.                                             */
        /**********************************************************************/
        WinLoadString (
                        habMain,
                        NULLHANDLE,
                        WRTERR_NOT_ACTIVE,
                        MAXCBUFFER,
                        cbuffer
                        );
        WinMessageBox( HWND_DESKTOP,
                       hwnd,
                       cbuffer,
                       NULL, 1, MB_OK );
        WinSendMsg ( hwnd, WM_CLOSE, NULL, NULL );
        return( 0 );
      } /* endif */
      _beginthread ( BackThread,
                           NULL,
                           16384,
                           NULL
                         );
      tidLiftOffT = _beginthread ( LiftOffThread,
                           NULL,
                           16384,
                           NULL
                         );
      /* initialize structure size to save time */
      apdExtra.cbStructSize = sizeof ( AUXPOINTDATA );
      edInfo.cbStructSize = sizeof ( WRTEVENTDATA );

      /************************************************************************/
      /* Initialize the ldiarr with all the locator information so it can be  */
      /* used during WM_SENSOR_MOVE                                           */
      /************************************************************************/
      /************************************************************************/
      /*  Find out how many locators the system has by querying the           */
      /*  locator capabilities API with ulLocatorID = 0L.                     */
      /*  The API will write the number of locator IDs in the system in       */
      /*  the variable ulLocatorID.                                           */
      /************************************************************************/
      ulLocatorID = 0L;
      irc = WrtQueryLocatorCaps ( &ulLocatorID, NULL );
      if ( irc != WRT_NO_ERROR )
      {
        /**********************************************************************/
        /* ERROR from API                                                     */
        /**********************************************************************/
        DisplayError ( hwnd, irc );
      } else
      {
        /**********************************************************************/
        /* Find out if locator are greater than zero                          */
        /**********************************************************************/
        if ( ulLocatorID == 0L ) 
        {
          WinMessageBox( HWND_DESKTOP,
                          hwnd,
                          "WrtQueryLocatorCaps return 0 locators",
                          NULL, 1, MB_OK );
        } else 
        {
          /********************************************************************/
          /* Display the Capabilities for all the locator in the system       */
          /********************************************************************/
          for ( ; ulLocatorID > 0L; ulLocatorID-- )
          {
            /******************************************************************/
            /* The cbStructureSize variable in the WRTLOCATORDEVINFO          */
            /* structure must be initialize to the size of the                */
            /* WRTLOCATORDEVINFO structure before querying the locator        */
            /* capabilities.                                                  */
            /******************************************************************/
            ldiarr[ulLocatorID].cbStructSize = sizeof ( ldiarr[ulLocatorID] );
 
            /******************************************************************/
            /* ulLocatorID variable has the ID of the locator that you        */
            /* want to query                                                  */
            /******************************************************************/
            irc = WrtQueryLocatorCaps ( &ulLocatorID, &ldiarr[ulLocatorID] );
 
            if ( irc == WRT_NO_ERROR ) 
            {
              /****************************************************************/
              /*  good return from API                                        */
              /*  mark good locator array as good                             */
              /****************************************************************/
              blocarr[ulLocatorID] = TRUE;
            } else 
            {
              /****************************************************************/
              /* ERROR from API                                               */
              /****************************************************************/
              DisplayError ( hwnd, irc );
            } /* endif */
          } /* endfor */
        } /* endif */
      } /* endif */
      
      /************************************************************************/
      /* post message to see what is active in the system                     */
      /************************************************************************/
      WinPostMsg(hwnd, ID_DISP, NULL, NULL);

      /************************************************************************/
      /* Load the "Blob" pointer we are going to use instead of the system    */
      /* pointer when the pointer is over the client area.                    */
      /************************************************************************/
      hptrClient = WinLoadPointer( HWND_DESKTOP, 0L, PTR_BLOB );

      break;
    }

    /**************************************************************************/
    /* Pen for OS/2 messages                                                  */
    /**************************************************************************/
    case WM_TOUCHDOWN:
    {
      /************************************************************************/
      /* Ensure that the client window is active.                             */
      /************************************************************************/
      WinSetActiveWindow( HWND_DESKTOP, hwnd );

      /************************************************************************/
      /* We are going to keep a count of mouse moves that make will make      */
      /* up this stroke.                                                      */
      /************************************************************************/
      MouMovCount  = 0L;

      /************************************************************************/
      /* Set the lLastWidth to 1 pel wide to start with                       */
      /************************************************************************/
      lLastWidth = 1L;

      /************************************************************************/
      /* Tell PM that ALL pointer messages should come to this window.        */
      /************************************************************************/
      WinSetCapture( HWND_DESKTOP, hwnd ) ;

      /************************************************************************/
      /* Determine where on the DESKTOP the client window is currently.       */
      /* This will be used to make sure we do not draw strokes that go        */
      /* outside our client window.                                           */
      /************************************************************************/
      WinQueryWindowPos( hwnd, &swpClient );

      /************************************************************************/
      /* Get event data pointer from mp2                                      */
      /************************************************************************/
      pedInfo = (PWRTEVENTDATA)PVOIDFROMMP ( mp2 );

      /************************************************************************/
      /* Check to see if we have the LOCATOR information set up               */
      /************************************************************************/
      if ( blocarr[pedInfo->ulLocatorID] == TRUE ) 
      {
        ulocindx = pedInfo->ulLocatorID;

        /* Set the MouseDivide variable */
          switch ( ldiarr[ulocindx].ulLocatorType )  
        {                                            
           case LT_PEN:                              
                   MouseDivide = (ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ) ? 4L : 1L ;
                   break;                            
           case LT_TOUCH:                            
           case LT_MOUSE:                            
           case LT_OTHER:                            
                   MouseDivide = 1L;                 
                   break;                            
        } /* endswitch */
      } /* endif */
      /************************************************************************/
      /* Mask out the mouse button from the EventStatus flag.                 */
      /************************************************************************/
      ulfButton = pedInfo->flEventStatus & WRT_MBUTTON_MASK;

      if( ulfButton & WRT_MBUTTON2 )
      {
        /**********************************************************************/
        /* Set the Mouse state to mouse button 2 down                         */
        /**********************************************************************/
        fButton1Down  = FALSE;
        fButton2Down  = TRUE;
      }
      else
      {
        /**********************************************************************/
        /* Set the Mouse state to mouse button 1 down                         */
        /**********************************************************************/
        fButton1Down  = TRUE;
        fButton2Down  = FALSE;
      }

      hpsClient = WinGetPS ( hwnd );

      /************************************************************************/
      /* Get the mouse coordinates                                            */
      /************************************************************************/
      ptlXY.x = (SHORT)MOUSEMSG(&msg)->x ;
      ptlXY.y = (SHORT)MOUSEMSG(&msg)->y ;

      /**************************************************************************/
      /* if fButton1Down is set to zero it means that fButton2Down is to to one */
      /* and we are in erase mode. Set the ink to the background to erase       */
      /**************************************************************************/
      GpiSetColor( hpsClient, fButton1Down ? CLR_NEUTRAL : CLR_BACKGROUND );

      GpiMove( hpsClient, &ptlXY );

      /************************************************************************/
      /* Tell the Pen for OS/2 subsystem that we want                         */
      /* 1) no button down message TDN_INFINITE,                              */
      /* 2) as many mouse moves message as possible TDN_HIFREQ_MOUSEMOVE, and */
      /* 2A)as many sensor move messages as possible TDN_SENSOR_MOVE          */
      /* 3) that we will take care of inking any strokes TDN_NO_INK_STROKE.   */
      /************************************************************************/
      /************************************************************************/
      /*  Find out if mouse move is on or sense move is on                    */
      /************************************************************************/
      if ( btoggle_mouse_sense ) 
      {
       return((MRESULT) ( TDN_INFINITE | TDN_NO_INK_STROKE |
                         TDN_SENSOR_MOVE ));
      } else 
      {
        return((MRESULT) (TDN_INFINITE | TDN_NO_INK_STROKE |
                          TDN_HIFREQ_MOUSEMOVE ));
      } /* endif */
    }

    /**************************************************************************/
    /* Pen for OS/2 message                                                   */
    /**************************************************************************/
    case WM_LIFTOFF:
    {
      /************************************************************************/
      /* Tell PM to resume routing pointer messages to the windows that       */
      /* the pointer goes over.                                               */
      /************************************************************************/
      WinSetCapture( HWND_DESKTOP, (HWND) NULL ) ;

      /************************************************************************/
      /* Get the WRT event Data to see if the STROKE DATA is valid            */
      /************************************************************************/
      pedInfo = (PWRTEVENTDATA)PVOIDFROMMP ( mp2 );

      if( ( pedInfo->flEventStatus & WRT_STROKE_AVAIL ) )
      {
        /* Post message to display the information of the EVENT data structure */
        if ( btoggle_event )
        {
          WinPostMsg ( hwndTFrame, ID_TEVENT, NULL, NULL );
        } /* endif */

        /************************************************************************/
        /* There is stroke data, query the size of the data, when put in        */
        /* a POINTL array of screen coordinates.                               */
        /************************************************************************/
        ulOptions = QSD_SCALE;     /* return in screen resolution */
        ulBuflen = 0L;
  
        /*********************************************************************************/
        /* Get the screen Z information for every point                                  */
        /* if ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ is true else do not get any */
        /*********************************************************************************/
        flAuxData = (ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ) ? ADF_SCREENZ : 0L ;
  
        irc = WrtQueryStrokeData ( NULL, &ulBuflen, hwnd, ulOptions, 
                                   0UL, 0UL,
                                   flAuxData   /* get the AUX data per point identify in flAuxData */
                                   );
        if( irc != WRT_NO_ERROR )
        {
          DisplayError ( hwnd, irc );
        }
        else
        {
          if( !ulBuflen )
          {
            WinMessageBox( HWND_DESKTOP, hwnd, "Zero ulBuflen", NULL, 1, MB_OK);
          }
          else
          {
            /********************************************************************/
            /* Alloc the memory for the stroke buffer and then call Pen for OS/2*/
            /* to fill in the buffer.                                           */
            /********************************************************************/
            if( ( psdCurStroke = (PSTROKEDATA) malloc( ulBuflen ) ) == NULL )
            {
              WinMessageBox( HWND_DESKTOP, hwnd, "malloc error",
                             NULL, 1, MB_OK );
            }
            else
            {
              psdCurStroke->cbStructSize = sizeof ( STROKEDATA );
              irc = WrtQueryStrokeData ( (PBYTE)psdCurStroke,
                                         &ulBuflen, hwnd, ulOptions,
                                         0UL, 0UL,  /*  scaled to screen        */
                                         flAuxData   /* get the AUX data per point identify in flAuxData */
                                         );
              if( irc != WRT_NO_ERROR )
              {
                DisplayError ( hwnd, irc );
              }
              else
              {
                uMsgLeft++;
                if ( uMsgLeft > 90L ) 
                {
                   /* Move the priority of the Lift Off Thread higher because     */
                   /* we are running out of message queues since we only have 100 */
                   DosSetPrty ( PRTYS_THREAD, PRTYC_REGULAR, 31, tidLiftOffT );
                } /* endif */
                WinPostMsg ( hwndT2Frame, ID_TLIFTOFF, MPFROMP ( psdCurStroke ), MPFROMCHAR ( fButton1Down ) );
              } /* endif */
            } /* endif */
          } /* endif */
        } /* endif */
      } /* endif */
      /************************************************************************/
      /* Reset our flags                                                      */
      /************************************************************************/
      fButton1Down = FALSE;
      fButton2Down = FALSE;
      bTouchDown = FALSE;
      MouMovCount = 0;
      WinReleasePS ( hpsClient );
      return( (MRESULT) LO_STROKE_PROCESSED );
    }

    case WM_MOUSEMOVE:
    case WM_SENSOR_MOVE:
    {
      /************************************************************************/
      /* We are over our client window, change pointer bitmap to our          */
      /* "BLOB" pointer bitmap.                                               */
      /************************************************************************/
      WinSetPointer( HWND_DESKTOP, hptrClient );

      if( !fButton1Down && !fButton2Down )
      {
        return( (MRESULT) FALSE );
      } /* endif */
      /************************************************************/
      /* get the event data to check if the stroke buffer is full */
      /* if the stroke buffer is full. The stroke buffer is 1000  */
      /* which is about nine(9) seconds of data                   */
      /************************************************************/
      if ( msg == WM_SENSOR_MOVE ) /* if is a WM_SENSOR_MOVE the event data is             */
      {                            /* in mp2 and you do not need to call WrtQueryEventData */
         pedInfo = (PWRTEVENTDATA)PVOIDFROMMP ( mp2 );
      } else
      {
        /*******************************************************/
        /* initialize structure size at WM_CREATE to save time */
        /* edInfo.cbStructSize = sizeof ( WRTEVENTDATA );      */
        /*******************************************************/
        WrtQueryEventData ( &edInfo );
        pedInfo = &edInfo;
      } /* endif */
      if ( pedInfo->flEventStatus & WRT_BUFFER_OVERRUN )
      {
        return( (MRESULT) FALSE ); /* if the buffer is full do not draw any more points */
      } /* endif */

      MouMovCount++;
      /*******************************************************************************/
      /* processing every other mouse move to speed up the inking with the          */
      /* movement of the PEN. On WM_LIFTOFF return we set the value of              */
      /* TDN_HIFREQ_MOUSEMOVE to force the system to give us all the mouse moves    */
      /* but on slower machines it is too fast for the ink to keep up with the      */
      /* user. By setting TDN_HIFREQ_MOUSEMOVE and dividing by 2 you are guaranty   */
      /* to draw every other point. With out TDN_HIFREQ_MOUSEMOVE PM may throw away */
      /* as many WM_MOUSEMOVE as it needs to on buffer overflow.                    */
      /* The same is true when on WM_LIFTOFF you return TDN_SENSOR_MOVE             */
      /*******************************************************************************/
      if ( (MouMovCount % MouseDivide ) )   
      {                                      
        return( (MRESULT) TRUE );            
      } /* endif */

      /************************************************************************/
      /* Get the mouse coordinates                                            */
      /************************************************************************/
      ptlXY.x = (SHORT)MOUSEMSG ( &msg )->x;
      ptlXY.y = (SHORT)MOUSEMSG ( &msg )->y;

      if ( msg == WM_SENSOR_MOVE ) 
      {
        /**********************************************************************/
        /* map sensor coordinates to screen coordinates                       */
        /**********************************************************************/
        irc = WrtMapPointLong (
                        hwnd,    /* coordinates are made relative to window */
                        &ptlXY,     /* address of POINTL containing X/Y coord. */
                        MP_SCALE,/* scale to coordinates in the ulX and ulY */
                                 /* ulXInput if MP_RESOLUTION               */
                        ldiarr[ulocindx].ulSensorXpts,     
                                 /* ulYInput if MP_RESOLUTION               */
                        ldiarr[ulocindx].ulSensorYpts,     
                        0L,      /* ulXOutput if MP_RESOLUTION              */
                        0L,      /* ulYOutput if MP_RESOLUTION              */
                        1        /* one pair of coordinates                 */
                        );
        if ( irc != WRT_NO_ERROR )
        {
          DisplayError ( hwnd, irc );
          return( (MRESULT) FALSE );
        } /* endif */
      } /* endif */

      /*************************************************************************/
      /* get the AUX data. I will use the the AUXPOINTDATA.sScrZ to figure out */
      /* the ink width. the the more pressured applied the wider the ink       */
      /*************************************************************************/
      /*******************************************/
      /* find out if AUXPOINTDATA.sScrZ is valid */
      /*******************************************/
      if ( (ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ) )
      {
        /*******************************************/
        /* AUXPOINTDATA.sScrZ is valid             */
        /*******************************************/
        /*******************************************************/
        /* initialize structure size at WM_CREATE to save time */
        /* apdExtra.cbStructSize = sizeof ( AUXPOINTDATA );    */
        /*******************************************************/

        if ( !btoggle_aux ) /* if btoggle_aux is TRUE I already got the AUX DATA */
        {                   /* so do not do it again                             */
          /*******************************************************/
          /* initialize structure size at WM_CREATE to save time */
          /* apdExtra.cbStructSize = sizeof ( AUXPOINTDATA );    */
          /*******************************************************/
          WrtQueryPointAuxData ( &apdExtra );
        } /* endif */
        sCurrP = apdExtra.sScrZ;  /* get the current pressure */
        if ( !bTouchDown )
        {
           bTouchDown = TRUE;
           /* First move after a WM_TOUCHDOWN initialize sLastP */
           sLastP = sCurrP;
        }   /* endif */

        /***********************************************************************/
        /*  the smaller AUXPOINTDATA.sScrZ the closer you are to the surface   */
        /* once you go negative value you are applying pressure to the screen  */
        /***********************************************************************/
        lLastWidth += (sLastP > sCurrP) ? (1) : (-1);

        /***********************************************************************/
        /* for this example I do not want the width to get bigger than 16 pels */
        /* and the width should never be allow to be less than 1 pel.          */
        /***********************************************************************/
        lLastWidth = ( lLastWidth <= 16L ) ? lLastWidth : 16L;
        lLastWidth = ( lLastWidth > 0L ) ? lLastWidth : 1L;

        sLastP = sCurrP;      /* set the last pressure to the current pressure */

        /*************************************************/
        /* Set the current geometric line-width.         */
        /* This width is only used in the GpiStrokePath  */
        /*************************************************/
        GpiSetLineWidthGeom ( hpsClient, lLastWidth );
  
        /*********************************************/
        /* Begins a figure that has  geometric width */
        /*********************************************/
        GpiBeginPath ( hpsClient, 1L );
  
        /************************/
        /* The figure is a line */
        /************************/
        GpiLine ( hpsClient, &ptlXY );
  
        /********************************************/
        /* Ends the figure that has geometric width */
        /********************************************/
        GpiEndPath ( hpsClient );
  
        /***************************************************/
        /* draws the figures with the geometric line-width */
        /* and fills it in                                 */
        /***************************************************/
        GpiStrokePath ( hpsClient, 1L, 0L );
      } else
      {
        /*****************************/
        /* The draw a line is a line */
        /*****************************/
        GpiLine ( hpsClient, &ptlXY );
      } /* endif */

      /******************************************************************/
      /* You can move this to the begining of WM_MOUSEMOVE              */
      /* so you can display the information before WM_TOUCHDOWN.          */
      /* This way if the btoggle_aux or btoggle_event is set            */
      /* you can see the information change before touchdown            */
      /******************************************************************/
      /* if btoogle_aux is TRUE  get the AUX structure                  */
      /******************************************************************/
      if ( btoggle_aux )
      {
        /*******************************************************/
        /* initialize structure size at WM_CREATE to save time */
        /* apdExtra.cbStructSize = sizeof ( AUXPOINTDATA );    */
        /*******************************************************/
        WrtQueryPointAuxData ( &apdExtra );
        WinPostMsg ( hwndTFrame, ID_TAUX, NULL, NULL );
      } /* endif */
      /******************************************************************/
      /* if btoogle_event is TRUE  get the event structure              */
      /******************************************************************/
      if ( btoggle_event )
      {
        WinPostMsg ( hwndTFrame, ID_TEVENT, NULL, NULL );
      } /* endif */

      return( (MRESULT) TRUE );
    }

    case WM_WRT_SYSVALUECHANGED:
    {
      switch ( LONGFROMMP (mp1) )
      {
         case VT_PPMSV:
            /* some program changed a system value */
            ulid = LONGFROMMP (mp2);
            for ( i= 0; i< QSVALUESIZE; i++ )
            {
               if ( qsvalue[i].valueid == ulid )
               {
                  break;
               } /* endif */
            } /* endfor */
            if ( i < QSVALUESIZE )
            {
              sprintf ( cbuffer, "%s [%ld] System Variable got changed",
                       qsvalue[i].valname, ulid );
            } else 
            {
              sprintf ( cbuffer, "Error [%ld] is not a valid System Variable ID",
                        ulid );
            } /* endif */
            WinMessageBox( HWND_DESKTOP,
                           hwnd,
                           cbuffer,
                           NULL, 1, MB_OK );
            break;
         case VT_PPMID:
            /* some program change a Device Variable */
            ulid = LONGFROMMP (mp2);
            for ( i= 0; i< PPMIDSIZE; i++ )
            {
               if ( ppmid[i].ValueID == ulid )
               {
                  break;
               } /* endif */
            } /* endfor */
            if ( i < PPMIDSIZE )
            {
              sprintf ( cbuffer, "%s [%ld] Device Variable got changed",
                       ppmid[i].name, ulid );
            } else 
            {
              sprintf ( cbuffer, "Error [%ld] is not a valid Device Variable ID",
                        ulid );
            } /* endif */
            WinMessageBox( HWND_DESKTOP,
                           hwnd,
                           cbuffer,
                           NULL, 1, MB_OK );
            break;
      } /* endswitch */
      break;
    }
    case WM_PAINT:
    {
      hpsPaint = WinBeginPaint( hwnd, (HPS) NULL, &rcClient );
      WinQueryWindowRect ( hwnd, &rcClient );
      WinFillRect( hpsPaint, &rcClient, SYSCLR_WINDOW );
      WinEndPaint( hpsPaint );
      break;
    }

    case ID_DISP:
    {
       /*******************************************************************/
       /* 1.Find out if there are any Button Caps                         */
       /*   if no button disable the query button menu                    */
       /* 2.Find out if there are any Locator Caps                        */
       /*   if no locator disable query Locator Caps                      */
       /*******************************************************************/
       scInfo.cbStructSize = sizeof ( scInfo );

       irc = WrtQuerySystemCaps ( &scInfo );

       if ( irc == WRT_NO_ERROR ) 
       {
          if ( scInfo.ulNumButtons == 0L )
          {
           /***************************************************************/
           /* disable the query Button menu                               */
           /***************************************************************/
           WinSendDlgItemMsg (
                             hwndFrame
                            ,(ULONG) FID_MENU
                            ,(ULONG) MM_SETITEMATTR
                            ,MPFROM2SHORT ( ID_BCAPS, TRUE )
                            ,MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED )
                            );
          } /* endif */
          
          if ( scInfo.ulNumLocators == 0L )
          {
           /***************************************************************/
           /* disable the query Locator menu                              */
           /***************************************************************/
           WinSendDlgItemMsg (
                             hwndFrame
                            ,(ULONG) FID_MENU
                            ,(ULONG) MM_SETITEMATTR
                            ,MPFROM2SHORT ( ID_LCAPS, TRUE )
                            ,MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED )
                            );
          } /* endif */

          if ( scInfo.ulNumDisplays == 0L )
          {
            /**************************************************************/
            /* disable the query display menu                             */
            /**************************************************************/
            WinSendDlgItemMsg (
                              hwndFrame
                             ,(ULONG) FID_MENU
                             ,(ULONG) MM_SETITEMATTR
                             ,MPFROM2SHORT ( ID_DCAPS, TRUE )
                             ,MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED )
                             );
            /**************************************************************/
            /* disable the backlight menu                                 */
            /**************************************************************/
            WinSendDlgItemMsg (
                              hwndFrame
                             ,(ULONG) FID_MENU
                             ,(ULONG) MM_SETITEMATTR
                             ,MPFROM2SHORT ( ID_BACKL, TRUE )
                             ,MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED )
                             );
          } else
          {
            /**************************************************************/
            /* Find out if the Backlight is supported                     */
            /* 1.Find out if any of the display attached support backlight*/
            /*       if no backlight supported disable backlight menu     */
            /**************************************************************/
            ulDisplayID = 0L;
            irc = WrtQueryDisplayCaps ( &ulDisplayID, NULL );
            if ( irc != WRT_NO_ERROR )
            {
              /************************************************************/
              /* ERROR from API                                           */
              /************************************************************/
              DisplayError ( hwnd, irc );
            } else
            {
              /************************************************************/
              /* Find out if any of the display support the backlight     */
              /************************************************************/
              i = 0;
              for ( ; ulDisplayID > 0L; ulDisplayID-- )
              {
                /**********************************************************/
                /* The cbStructureSize variable in the WRTDISPLAYDEVINFO  */
                /* structure must be initialize to the size of the        */
                /* WRTDISPLAYDEVINFO structure before querying the Display*/
                /* capabilities.                                          */
                /**********************************************************/
                dcInfo.cbStructSize = sizeof ( dcInfo );
    
                /**********************************************************/
                /* ulDisplayID variable has the ID of the Display that you*/
                /* want to query                                          */
                /**********************************************************/
                irc = WrtQueryDisplayCaps ( &ulDisplayID, &dcInfo );
    
                if ( irc == WRT_NO_ERROR ) 
                { 
                  irc = WrtQueryInputDeviceVariable ( dcInfo.pszDriverName,
                                                      dcInfo.pszDeviceName,
                                                      PPMID_BACKLIGHTBLANK,
                                                      &lvalue,
                                                      NULL,
                                                      NULL
                                                     );
                  if ( irc == WRT_NO_ERROR )
                  {
                    /* save the display ID for use in the BACKLIGHT DLG */
                    ulbacklight_displayID[i++] = ulDisplayID;
                  } /* endif */
                } else 
                {
                  /********************************************************/
                  /* ERROR from API                                       */
                  /********************************************************/
                  DisplayError ( hwnd, irc );
                } /* endif */
              } /* endfor */
              ulbacklight_displayID[i] = 0L;
              if ( i == 0 )
              {
                /**********************************************************/
                /* No display with backlight support found                */
                /* disable the backlight menu                             */
                /**********************************************************/
                WinSendDlgItemMsg (
                                  hwndFrame
                                 ,(ULONG) FID_MENU
                                 ,(ULONG) MM_SETITEMATTR
                                 ,MPFROM2SHORT ( ID_BACKL, TRUE )
                                 ,MPFROM2SHORT ( MIA_DISABLED, MIA_DISABLED )
                                 );
              } /* endif */
            } /* endif */
          } /* endif */
       } else 
       {
         /*****************************************************************/
         /* ERROR from API                                                */
         /*****************************************************************/
         DisplayError ( hwnd, irc );
       } /* endif */

      break;
    }

    case WM_COMMAND:
    {
      switch ( SHORT1FROMMP(mp1) )
      {
        case ID_CLEAR:
        {
          /********************************************************************/
          /* If there was a clear cmd, then tell the procedure to clear       */
          /* the client window, and clear the memory bitmap now.              */
          /********************************************************************/
          WinInvalidateRect( hwndClient, NULL, TRUE );

          break;
        }

        case ID_EXIT:
          WinSendMsg(hwnd, WM_CLOSE, NULL, NULL);
          break;

       /***********************************************************************/
       /* Toggle between mouse mode and sense mode                            */
       /***********************************************************************/
       case ID_FULL:
          btoggle_mouse_sense = btoggle_mouse_sense ^ 1;     /* toggle variable */
          WinSendDlgItemMsg (
                              hwndFrame
                             ,(ULONG) FID_MENU
                             ,(ULONG) MM_SETITEMATTR
                             ,MPFROM2SHORT ( ID_FULL, TRUE )
                             ,MPFROM2SHORT ( MIA_CHECKED, btoggle_mouse_sense ? MIA_CHECKED : 0 )
                             );
          break;
       /***********************************************************************/
       /* Toggle between display Aux Data and not display Aux Data            */
       /***********************************************************************/
       case ID_AUX:
          btoggle_aux = btoggle_aux ^ 1;     /* toggle variable */
          WinSendDlgItemMsg (
                            hwndFrame
                           ,(ULONG) FID_MENU
                           ,(ULONG) MM_SETITEMATTR
                           ,MPFROM2SHORT ( ID_AUX, TRUE )
                           ,MPFROM2SHORT ( MIA_CHECKED, btoggle_aux ? MIA_CHECKED : 0 )
                           );

          if ( !btoggle_aux )
          {
               AUXTEST = 0;
               WinDismissDlg ( hwndAuxDLG, EXIT );
          } /* endif */
          break;
       /***********************************************************************/
       /* Toggle between display Event Data and not display Event Data        */
       /***********************************************************************/
       case ID_EVENT:
          btoggle_event = btoggle_event ^ 1;     /* toggle variable */
          WinSendDlgItemMsg (
                            hwndFrame
                           ,(ULONG) FID_MENU
                           ,(ULONG) MM_SETITEMATTR
                           ,MPFROM2SHORT ( ID_EVENT, TRUE )
                           ,MPFROM2SHORT ( MIA_CHECKED, btoggle_event ? MIA_CHECKED : 0 )
                           );
          if ( !btoggle_event )
          {
               EVENTTEST = 0;
               WinDismissDlg ( hwndEventDLG, EXIT );
          } /* endif */
          break;
       /***********************************************************************/
       /* System Capability                                                   */
       /***********************************************************************/
       case ID_SCAPS:
            /******************************************************************/
            /* The cbStructureSize variable in the WRTSYSTEMINFO              */
            /* structure must be initialize to the size of the                */
            /* WRTSYSTEMINFO structure before querying the System             */
            /* capabilities.                                                  */
            /******************************************************************/
            scInfo.cbStructSize = sizeof ( scInfo );
  
            irc = WrtQuerySystemCaps ( &scInfo );
  
            if ( irc == WRT_NO_ERROR ) 
            {
              /****************************************************************/
              /*  good return from API                                        */
              /*  display the System capabilities                             */
              /****************************************************************/
              WinDlgBox(HWND_DESKTOP,
                             hwnd,
                             SysCapDlgProc,
                             0UL,
                             IDD_SCDLG,
                             &scInfo);
            } else 
            {
              /****************************************************************/
              /* ERROR from API                                               */
              /****************************************************************/
              DisplayError ( hwnd, irc );
            } /* endif */
          break;
  
       /***********************************************************************/
       /* Locator Capability                                                  */
       /***********************************************************************/
       case ID_LCAPS:
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           LocCapDlgProc,
                           0UL,
                           IDD_LCDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Button  Capability                                                  */
       /***********************************************************************/
       case ID_BCAPS:
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           ButCapDlgProc,
                           0UL,
                           IDD_BCDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Display Capability                                                  */
       /***********************************************************************/
       case ID_DCAPS:
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           DisCapDlgProc,
                           0UL,
                           IDD_DCDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Query System Values                                                 */
       /***********************************************************************/
       case ID_QSVAL:
            /******************************************************************/
            /*  display the System values                                     */
            /******************************************************************/
            WinDlgBox ( HWND_DESKTOP,
                              hwnd,
                              SysValDlgProc,
                              0UL,
                              IDD_SVDLG,
                              NULL);
          break;
  
       /***********************************************************************/
       /* Set   System Values                                                 */
       /***********************************************************************/
       case ID_SSVAL:
            /******************************************************************/
            /*  Call dialog to set the system value.                          */
            /*  WARNING: Changing the system value will affect the system     */
            /******************************************************************/
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           SSysVlDlgProc,
                           0UL,
                           IDD_SSDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Write System Values                                                 */
       /***********************************************************************/
       case ID_WSVAL:
            /******************************************************************/
            /*  Call dialog to write a system value.                          */
            /*  WARNING: Changing the system value will affect the system     */
            /******************************************************************/
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           WSysVlDlgProc,
                           0UL,
                           IDD_WSDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Read  System Values                                                 */
       /***********************************************************************/
       case ID_RSVAL:
            /******************************************************************/
            /*  Call dialog to Read  a system value.                          */
            /*  WARNING: Changing the system value will affect the system     */
            /******************************************************************/
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           RSysVlDlgProc,
                           0UL,
                           IDD_RSDLG,
                           NULL );
          break;
       /***********************************************************************/
       /* Enumerate Input Drivers                                             */
       /***********************************************************************/
       case ID_ENUDR:
            /* Find out how many input driver there are */
            ulNumDrivers = 0L;
            irc = WrtEnumInputDrivers ( &ulNumDrivers, NULL );
            if ( irc != WRT_NO_ERROR )
            {
               DisplayError ( hwnd, irc );
            } else
            {
              if ( ulNumDrivers > 10L )
              {
                sprintf ( cbuffer, "Too many drivers[%ld] for my ARRAY",
                        ulNumDrivers );
                WinMessageBox( HWND_DESKTOP,
                               hwnd,
                               cbuffer,
                               NULL, 1, MB_OK );
              } else
              {
                if ( ulNumDrivers == 0L )
                {
                  WinMessageBox( HWND_DESKTOP,
                                  hwnd,
                                  "WrtEnumInputDrivers return 0 drivers",
                                  NULL, 1, MB_OK );
                } else
                {
                  irc = WrtEnumInputDrivers ( &ulNumDrivers, szDriverName );
                  if ( irc == WRT_NO_ERROR ) 
                  {
                    WinDlgBox(HWND_DESKTOP,
                                   hwnd,
                                   EnumDrvDlgProc,
                                   0UL,
                                   IDD_EIDLG,
                                   NULL );
                  } else 
                  {
                     DisplayError ( hwnd, irc );
                  } /* endif */
                } /* endif */
              } /* endif */
            } /* endif */
          break;
       /***********************************************************************/
       /* Query Input Device Names                                            */
       /***********************************************************************/
       case ID_QDNAM:
                  WinDlgBox(HWND_DESKTOP,
                                 hwnd,
                                 QInDevNDlgProc,
                                 0UL,
                                 IDD_DNDLG,
                                 NULL );
          break; 
  
       /***********************************************************************/
       /* Query Input Device Variable                                         */
       /***********************************************************************/
       case ID_QDVAR:
                  WinDlgBox(HWND_DESKTOP,
                                 hwnd,
                                 QInpDevDlgProc,
                                 0UL,
                                 IDD_QVDLG,
                                 NULL );
          break;
       /***********************************************************************/
       /* Set   Input Device Variable                                         */
       /***********************************************************************/
       case ID_SDVAR:
                  WinDlgBox(HWND_DESKTOP,
                                 hwnd,
                                 SInpDevDlgProc,
                                 0UL,
                                 IDD_SNDLG,
                                 NULL );
          break;
       /***********************************************************************/
       /* Set Strict Emulation                                                */
       /***********************************************************************/
       case ID_SEMUL:
          btoggle_strick_mous = btoggle_strick_mous ^ 1;     /* toggle variable */
          WinSendDlgItemMsg (
                               hwndFrame
                              ,(ULONG) FID_MENU
                              ,(ULONG) MM_SETITEMATTR
                              ,MPFROM2SHORT ( ID_SEMUL, TRUE )
                              ,MPFROM2SHORT ( MIA_CHECKED, btoggle_strick_mous ? MIA_CHECKED : 0 )
                              );
          irc = WrtSetStrictEmulation ( hwnd,btoggle_strick_mous ? SSE_SET : SSE_RESET );
          if ( irc != WRT_NO_ERROR ) 
          {
            DisplayError ( hwnd, irc );
          } /* endif */
          break;
       /***********************************************************************/
       /* ON/OFF Backlight                                                    */
       /***********************************************************************/
       case ID_BACKL:
            WinDlgBox(HWND_DESKTOP,
                           hwnd,
                           BACKLTDlgProc,
                           0UL,
                           IDD_BLDLG,
                           NULL );
          break;
      }
      break;
    }

    default:
    {
      return( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
    }
  }
  return( (MRESULT) FALSE );
}


VOID BackThread ( VOID * arg )
{
  HMQ   hmqTMain;
  QMSG  qmsgTMain;

  /****************************************************************************/
  /* Initialize PM for this program and create its PM message queue.          */
  /* The message queue is set to 100 because the thread will be running at    */
  /* idle item and the main thread will be posting messages for every .       */
  /* mouse move. Still you may loose some data because of queue overflow.     */
  /****************************************************************************/
  habTMain = WinInitialize( (ULONG) NULL );
  hmqTMain = WinCreateMsgQueue( habTMain, 100L );


  /****************************************************************************/
  /* Register "ThreadWndProc" as the handling procedure for the               */
  /* "Object Class" class window.                                             */
  /****************************************************************************/
  WinRegisterClass( habTMain,
                  (PSZ)"Object Class",
                  (PFNWP)ThreadWndProc,
                  0L,
                  0L );


  hwndTFrame = WinCreateWindow(HWND_OBJECT,             /* Create an Object Window */
                               (PSZ)"Object Class",
                               NULL,
                               0L,
                               0,
                               0,
                               0,
                               0,
                               0L,
                               HWND_TOP,
                               OBJECTID1,
                               NULL,
                               NULL);
  /********************************************************************************/
  /* Set this thread's priority to idle class                                     */
  /* If you want to set the thread priority lower than default uncomment the      */
  /* DosSetPrty statement. The lower the priority the more time you give to other */
  /* threads (WM_MOUSEMOVE message thread                                         */
  /********************************************************************************/
  /* DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, 31, 0 ); */

  /****************************************************************************/
  /* This while loop waits for messages from PM.  If not a WM_CLOSE msg,      */
  /* then we dispatch the message to our client window procedure.             */
  /****************************************************************************/
  while( WinGetMsg( habTMain, &qmsgTMain, (HWND) NULL, 0, 0 ) )
  {
    WinDispatchMsg( habTMain, &qmsgTMain );
  }

  /****************************************************************************/
  /* We will drop out of the while loop if the program receives a WM_CLOSE    */
  /* message.  We must destroy our PM resources and return to the             */
  /* invoking procedure.                                                      */
  /****************************************************************************/
  WinDestroyWindow( hwndTFrame );
  WinDestroyMsgQueue( hmqTMain );
  WinTerminate( habTMain );

}
MRESULT EXPENTRY ThreadWndProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  CHAR      cbuffer[MAXCBUFFER];
  INT       i;

  switch( msg )
  {
    case ID_TAUX:
         if ( AUXTEST == 0 ) 
         {
           hwndAuxDLG = WinLoadDlg ( HWND_DESKTOP,
                           hwnd,
                           AUXPNTDlgProc,
                           0L,
                           IDD_PADLG,
                           NULL );
           AUXTEST = 1;
         } else 
         {
           /****************************************************************/
           /* ulocindx will be pointing to the last locator device that    */
           /* did a WM_TOUCHDOWN. When changing from a pen to a finger you */
           /* must do at least one touchdown before ulocindx changes from  */
           /* the pen to the finger                                        */
           /****************************************************************/
           if ( ldiarr[ulocindx].ulValidityFlags & ADF_TIMESTAMP )
           {
              sprintf ( cbuffer, "%ld", apdExtra.ulTimestamp );
              WinSetDlgItemText ( hwndAuxDLG, wrtelc02, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_FLAGS )
           {
             sprintf ( cbuffer, "%#x", apdExtra.usFlags );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc03, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_USER )
           {
             sprintf ( cbuffer, "%d", apdExtra.usUser );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc04, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ )
           {
             sprintf ( cbuffer, "%d", apdExtra.sScrZ );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc05, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_DEVZ )
           {
            sprintf ( cbuffer, "%d", apdExtra.sDevZ );
            WinSetDlgItemText ( hwndAuxDLG, wrtelc06, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_ANGLE )
           {
             sprintf ( cbuffer, "%d", apdExtra.sAngle );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc07, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_ROTATION )
           {
             sprintf ( cbuffer, "%d", apdExtra.sRotation );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc08, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_BUTTON )
           {
             sprintf ( cbuffer, "%#x", apdExtra.usButton );
             WinSetDlgItemText ( hwndAuxDLG, wrtelc09, cbuffer );
           } /* endif */

           if ( ldiarr[ulocindx].ulValidityFlags & ADF_OEM )
           {
            /* adf_oem_count_mask is not supported in release 1 */
            for ( i= 0; i < ldiarr[ulocindx].ulOEMValidityCnt; i++ )
            {
               sprintf ( cbuffer, "OEM[%i]= %li", i, apdExtra.OEM[i] );
               WinSendDlgItemMsg(hwndAuxDLG,
                                  wrtelc10,
                                  LM_INSERTITEM,
                                  MPFROM2SHORT(LIT_END, 0),
                                  MPFROMP( cbuffer ) );

            } /* endfor */
           } /* endif */
         } /* endif */
      break;
    case ID_TEVENT:
         if ( EVENTTEST == 0 )
         {
           hwndEventDLG = WinLoadDlg ( HWND_DESKTOP,
                           hwnd,
                           EVNTDTDlgProc,
                           0L,
                           IDD_EVDLG,
                           NULL );
           EVENTTEST = 1;
         } else 
         {
           sprintf ( cbuffer, "%#x", pedInfo->usKCFlags );
           WinSetDlgItemText ( hwndEventDLG, wrtelc02, cbuffer );

           sprintf ( cbuffer, "%#x", pedInfo->usHitTest );
           WinSetDlgItemText ( hwndEventDLG, wrtelc03, cbuffer );

           sprintf ( cbuffer, "%#x", pedInfo->flEventStatus );
           WinSetDlgItemText ( hwndEventDLG, wrtelc04, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ptlDisplay.x );
           WinSetDlgItemText ( hwndEventDLG, wrtelc05, cbuffer );
           sprintf ( cbuffer, "%ld", pedInfo->ptlDisplay.y );
           WinSetDlgItemText ( hwndEventDLG, wrtelc06, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ptlSensor.x );
           WinSetDlgItemText ( hwndEventDLG, wrtelc07, cbuffer );
           sprintf ( cbuffer, "%ld", pedInfo->ptlSensor.y  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc08, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ptlStandard.x );
           WinSetDlgItemText ( hwndEventDLG, wrtelc09, cbuffer );
           sprintf ( cbuffer, "%ld", pedInfo->ptlStandard.y  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc10, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ulStrokeSeq  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc11, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ulStrokeSize );
           WinSetDlgItemText ( hwndEventDLG, wrtelc12, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ulLocatorID  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc13, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->ulLocatorType  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc14, cbuffer );

           sprintf ( cbuffer, "%#lx", pedInfo->ulLocatorFlags  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc15, cbuffer );

           sprintf ( cbuffer, "%#lx", pedInfo->ulValidityFlags );
           WinSetDlgItemText ( hwndEventDLG, wrtelc16, cbuffer );

           sprintf ( cbuffer, "%#lx", pedInfo->ulButtonStatus  );
           WinSetDlgItemText ( hwndEventDLG, wrtelc17, cbuffer );

           sprintf ( cbuffer, "%ld", pedInfo->hwndUnderPtr );
           WinSetDlgItemText ( hwndEventDLG, wrtelc18, cbuffer );
         } /* endif */
      break;
    default:
    {
      return( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
    }
  } /* endswitch */
  return( (MRESULT) FALSE );
}

VOID LiftOffThread ( VOID * arg )
{
  HMQ   hmqTMain;
  QMSG  qmsgTMain;

  /********************************************************************************/
  /* Initialize PM for this program and create its PM message queue.              */
  /* The message queue is set to 100 because the thread will be running at        */
  /* idle item and the main thread will be posting messages for for every stroke. */
  /********************************************************************************/
  habT2Main = WinInitialize( (ULONG) NULL );
  hmqTMain = WinCreateMsgQueue( habT2Main, 100L );


  /****************************************************************************/
  /* Register "ThreadLiftOffProc" as the handling procedure for the           */
  /* "Object Class" class window.                                             */
  /****************************************************************************/
  WinRegisterClass( habT2Main,
                  (PSZ)"Object Class",
                  (PFNWP)ThreadLiftOffProc,
                  0L,
                  0L );


  hwndT2Frame = WinCreateWindow(HWND_OBJECT,             /* Create an Object Window */
                               (PSZ)"Object Class",
                               NULL,
                               0L,
                               0,
                               0,
                               0,
                               0,
                               0L,
                               HWND_TOP,
                               OBJECTID2,
                               NULL,
                               NULL);
  /* Set this thread's priority to idle class */
  DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, 31, 0 );

  /****************************************************************************/
  /* This while loop waits for messages from PM.  If not a WM_CLOSE msg,      */
  /* then we dispatch the message to our client window procedure.             */
  /****************************************************************************/
  while( WinGetMsg( habT2Main, &qmsgTMain, (HWND) NULL, 0, 0 ) )
  {
    WinDispatchMsg( habT2Main, &qmsgTMain );
  }

  /****************************************************************************/
  /* We will drop out of the while loop if the program receives a WM_CLOSE    */
  /* message.  We must destroy our PM resources and return to the             */
  /* invoking procedure.                                                      */
  /****************************************************************************/
  WinDestroyWindow( hwndT2Frame );
  WinDestroyMsgQueue( hmqTMain );
  WinTerminate( habT2Main );

}
MRESULT EXPENTRY ThreadLiftOffProc (HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
  INT          i;
  HPS          hpsTClient;
  PSTROKEDATA  psdCurStroke;
  POINTL       *pxyCurStroke;
  SHORT        *psCurrP;             /* pointer to get the pressure */
  CHAR         fButton1Down;

  switch( msg )
  {
    case ID_TLIFTOFF:
    {
         psdCurStroke = (PSTROKEDATA)PVOIDFROMMP ( mp1 );
         fButton1Down = CHAR1FROMMP ( mp2 );

         hpsTClient = WinGetPS ( hwndClient );
         pxyCurStroke = psdCurStroke->pXY;

         /* decrease the number of message waiting */
         uMsgLeft--;
         if ( uMsgLeft == 80L )
         {
            /* Move the priority of the Lift Off Thread lower because     */
            /* we we have enough space in the  message queue we  have 100 */
            DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, 31, 0 );
         } /* endif */
         /**************************************************************************/
         /* if fButton1Down is set to zero it means that fButton2Down is to to one */
         /* and we are in erase mode. Set the ink to the background to erase       */
         /**************************************************************************/
         GpiSetColor( hpsTClient, fButton1Down ? CLR_BLUE : CLR_BACKGROUND );

         /**************************************************************/
         /* Move the staring point of the the line to the beging of    */
         /* the stroke                                                 */
         /**************************************************************/
         GpiMove( hpsTClient, &pxyCurStroke[0] );

         /*******************************************/
         /* find out if AUXPOINTDATA.sScrZ is valid */
         /*******************************************/
         if ( (ldiarr[ulocindx].ulValidityFlags & ADF_SCREENZ) )
         {
           /***********************************************************/
           /* Since I only requested one AUX data                     */
           /* psdCurStroke->pAuxInfo->cbAuxDesc == 24                 */ /* 4*/
           /* psdCurStroke->pAuxInfo->ulNumElements == 1              */ /* 8*/
           /* psdCurStroke->pAuxInfo->ulAuxSize == 2                  */ /*12*/
           /* psdCurStroke->pAuxInfo->addAuxDesc[0].id == ADT_SCREENZ */ /*16*/
           /* psdCurStroke->pAuxInfo->addAuxDesc[0].offset == 0L      */ /*20*/
           /* psdCurStroke->pAuxInfo->addAuxDesc[0].cb == 2L          */ /*24*/
           /***********************************************************/

           /* get the first SCREENZ information */
psCurrP = (SHORT *)&(psdCurStroke->pAuxData->bAuxData[0][psdCurStroke->pAuxInfo->addAuxDesc[0].offset]);
           sLastP = *psCurrP;    /* this is done becuase bAuxData is unsign CHAR and SCREENZ is SHORT */

           /* for all the point in the stroke after the first point */
           for ( i= 1L; i< psdCurStroke->ulNumPoints ; i++ )
           {
psCurrP = (SHORT *)&(psdCurStroke->pAuxData->bAuxData[ (i*psdCurStroke->pAuxInfo->ulAuxSize) ][psdCurStroke->pAuxInfo->addAuxDesc[0].offset]);
             sCurrP = *psCurrP;

             /***********************************************************************/
             /*  the smaller AUXPOINTDATA.sScrZ the closer you are to the surface   */
             /* once you go negative value you are applying pressure to the screen  */
             /***********************************************************************/
             lLastWidth += (sLastP > sCurrP) ? (1) : (-1);
     
             /***********************************************************************/
             /* for this example I do not want the width to get bigger than 16 pels */
             /* and teh width should never be allow to be less than 1 pel.          */
             /***********************************************************************/
             lLastWidth = ( lLastWidth <= 16L ) ? lLastWidth : 16L;
             lLastWidth = ( lLastWidth > 0L ) ? lLastWidth : 1L;

             sLastP = sCurrP;      /* set the last pressure to the current pressure */

             /*********************************************/
             /* Begins a figure that has  geometric width */
             /*********************************************/
             GpiBeginPath ( hpsTClient, 1L );
       
             /*************************************************/
             /* Set the current geometric line-width.         */
             /* This width is only used in the GpiStrokePath  */
             /*************************************************/
             GpiSetLineWidthGeom ( hpsTClient, lLastWidth );
       
             /************************/
             /* The figure is a line */
             /************************/
             GpiLine ( hpsTClient, &pxyCurStroke[i] );
       
             /********************************************/
             /* Ends the figure that has geometric width */
             /********************************************/
             GpiEndPath ( hpsTClient );
       
             /***************************************************/
             /* draws the figures with the geometric line-width */
             /* and fills it in                                 */
             /***************************************************/
             GpiStrokePath ( hpsTClient, 1L, 0L );
           } /* endfor */
         } else       /* the Locator does not support SCREENZ */
         {
           GpiPolyLine( hpsTClient,
                          (LONG)(psdCurStroke->ulNumPoints - 1L ),
                          &pxyCurStroke[1] );
         } /* endif */
         WinReleasePS ( hpsTClient );
         free( psdCurStroke );
      }
      break;
    default:
    {
      return( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
    }
  } /* endswitch */
  return( (MRESULT) FALSE );
}
