Extended GHOST to support WinTab, in order to better support graphic tablets on Windows
authorAndrea Weikert <elubie@gmx.net>
Sun, 5 Nov 2006 21:55:28 +0000 (21:55 +0000)
committerAndrea Weikert <elubie@gmx.net>
Sun, 5 Nov 2006 21:55:28 +0000 (21:55 +0000)
Basic support for normal pressure sensitivity is implemented, adding other features like tilt etc. shouldn't be too difficult, now that basic support is there.
Tested with WACOM Volito on Windows XP using the pressure sensitivity with texture paint to change size of the brush .

Added additional include dir to scons, and MSVC 7 project files - other build systems might have to be updated.

intern/ghost/SConscript
intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h
intern/ghost/intern/GHOST_WindowWin32.cpp
intern/ghost/intern/GHOST_WindowWin32.h
intern/ghost/make/msvc_7_0/ghost.vcproj

index 9002dca21e84cf1c9c4a73ab8804b3e80c82b84e..c2b9a59bca31e39d9bd84205b3d99e5be626510a 100644 (file)
@@ -27,4 +27,6 @@ else:
     Exit()
 
 incs = '. ../string ' + env['BF_OPENGL_INC']
+if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross'):
+       incs = '../../../../lib/windows/wintab/INCLUDE ' + incs
 env.BlenderLib ('bf_ghost', sources, Split(incs), [], libtype=['core','player'], priority = [25,15] ) 
index f381b8f6b0b423152ed667b3d1f1d6d295f70d3a..ec6d0d355b59977a22b786a088a5411c64fa4086 100644 (file)
@@ -627,7 +627,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                                         * a dead key that is pressed while holding down the alt key. 
                                         */
                                        break;
-
+                               ////////////////////////////////////////////////////////////////////////
+                               // Tablet events, processed
+                               ////////////////////////////////////////////////////////////////////////
+                               case WT_PACKET:
+                                       ((GHOST_WindowWin32*)window)->processWin32TabletEvent(wParam, lParam);
+                                       break;
+                               case WT_CSRCHANGE:
+                               case WT_PROXIMITY:
+                                       ((GHOST_WindowWin32*)window)->processWin32TabletInitEvent();
+                                       break;
                                ////////////////////////////////////////////////////////////////////////
                                // Mouse events, processed
                                ////////////////////////////////////////////////////////////////////////
index a6798ee7109c15d8afef29b183bcc5542560b18c..218fc5794eb38fce41ab1509fc45230673a016f5 100644 (file)
@@ -274,6 +274,7 @@ protected:
        bool m_seperateLeftRight;
        /** Stores the initialization state of the member m_leftRightDistinguishable. */
        bool m_seperateLeftRightInitialized;
+       
 };
 
 inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
index 290289201eaae1bbdbd0c4e1929feb06f39fe7ee..b5b89104307c963d11e9b65e66183b0e3e32864a 100644 (file)
@@ -99,7 +99,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(
        m_hGlRc(0),
        m_hasMouseCaptured(false),
        m_nPressedButtons(0),
-       m_customCursor(0)
+       m_customCursor(0),
+       m_tabletData(NULL),
+       m_tablet(0),
+       m_wintab(NULL),
+       m_maxPressure(0)
 {
        if (state != GHOST_kWindowStateFullScreen) {
                        /* Convert client size into window size */
@@ -159,11 +163,67 @@ GHOST_WindowWin32::GHOST_WindowWin32(
                // Force an initial paint of the window
                ::UpdateWindow(m_hWnd);
        }
+
+       m_wintab = ::LoadLibrary("Wintab32.dll");
+       if (m_wintab) {
+               GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
+               GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
+
+               // let's see if we can initialize tablet here
+               /* check if WinTab available. */
+               if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
+                       // Now init the tablet
+                       LOGCONTEXT lc;
+                       AXIS TabletX, TabletY, Pressure; /* The maximum tablet size */
+
+                       // Open a Wintab context
+
+                       // Get default context information
+                       fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
+
+                       // Open the context
+                       lc.lcPktData = PACKETDATA;
+                       lc.lcPktMode = PACKETMODE;
+                       lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
+
+                       /* Set the entire tablet as active */
+                       fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
+                       fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
+                       BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
+                       if (pressureSupport)
+                               m_maxPressure = Pressure.axMax;
+                       else
+                               m_maxPressure = 0;
+               
+                       lc.lcInOrgX = 0;
+                       lc.lcInOrgY = 0;
+                       lc.lcInExtX = TabletX.axMax;
+                       lc.lcInExtY = TabletY.axMax;            
+
+                       if (fpWTOpen) {
+                               m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
+                               if (m_tablet) {
+                                       m_tabletData = new GHOST_TabletData();
+                                       m_tabletData->Active = 0;
+                               }
+                       }
+               }
+       }
 }
 
 
 GHOST_WindowWin32::~GHOST_WindowWin32()
 {
+       if (m_wintab) {
+               GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
+               if (fpWTClose) {
+                       if (m_tablet) 
+                               fpWTClose(m_tablet);
+                       if (m_tabletData)
+                               delete m_tabletData;
+                               m_tabletData = NULL;
+               }
+       }
        if (m_customCursor) {
                DestroyCursor(m_customCursor);
                m_customCursor = NULL;
@@ -563,6 +623,61 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
 
        return GHOST_kSuccess;
 }
+void GHOST_WindowWin32::processWin32TabletInitEvent()
+{
+       if (m_wintab) {
+               GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
+               
+               // let's see if we can initialize tablet here
+               /* check if WinTab available. */
+               if (fpWTInfo) {
+                       AXIS TabletX, TabletY, Pressure; /* The maximum tablet size */
+
+                       BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
+                       if (pressureSupport)
+                               m_maxPressure = Pressure.axMax;
+                       else
+                               m_maxPressure = 0;
+                       m_tabletData->Active = 0;
+               }
+       }
+}
+
+void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
+{
+       PACKET pkt;
+       if (m_wintab) {
+               GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
+               if (fpWTPacket) {
+                       if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {                           
+                               if (m_tabletData) {
+                                       switch (pkt.pkCursor) {
+                                               case 0: /* first device */
+                                               case 3: /* second device */
+                                                       m_tabletData->Active = 0; /* puck - not yet supported */
+                                                       break;
+                                               case 1:
+                                               case 4:
+                                                       m_tabletData->Active = 1; /* stylus */
+                                                       break;
+                                               case 2:
+                                               case 5:
+                                                       m_tabletData->Active = 2; /* eraser */
+                                                       break;
+                                       }
+                                       if (m_maxPressure > 0) {
+                                               m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
+                                       } else {
+                                               m_tabletData->Pressure = 1.0f;
+                                       }
+                                       // tilt data not yet supported
+                                       m_tabletData->Xtilt = 0;
+                                       m_tabletData->Ytilt = 0;
+                               }
+                       }
+               }
+       }
+}
 
 /** Reverse the bits in a GHOST_TUns8 */
 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
index 5a0ff3e2052296d66c89e0f2c60f45186915151e..f2df0072be8d37171ce3e5052bf92a5cf41a7d23 100644 (file)
 #include <windows.h>
 
 
+#include <wintab.h>
+#define PACKETDATA     (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR)
+#define PACKETMODE     PK_BUTTONS
+#include <pktdef.h>
+
+// typedefs for WinTab functions to allow dynamic loading
+typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID );
+typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL);
+typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX);
+typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID);
+
 /**
  * GHOST window on M$ Windows OSs.
  * @author     Maarten Gribnau
@@ -217,7 +228,11 @@ public:
        void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
 
        const GHOST_TabletData* GetTabletData()
-       { return NULL; }
+       { return m_tabletData; }
+
+       void processWin32TabletInitEvent();
+       void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
+
 protected:
        /**
         * Tries to install a rendering context in this window.
@@ -278,6 +293,17 @@ protected:
 
        static LPCSTR s_windowClassName;
        static const int s_maxTitleLength;
+
+       /** WinTab dll handle */
+       HMODULE m_wintab;
+
+       /** Tablet data for GHOST */
+       GHOST_TabletData* m_tabletData;
+
+       /** Stores the Tablet context if detected Tablet features using WinTab.dll */
+       HCTX m_tablet;
+       LONG m_maxPressure;
+
 };
 
 #endif // _GHOST_WINDOW_WIN32_H_
index b39a51b0e92e516899947150a62d10f7ef2994c9..c1e85b05860c989728131b85aba9d42a4c35424d 100644 (file)
@@ -21,7 +21,7 @@
                        <Tool
                                Name="VCCLCompilerTool"
                                InlineFunctionExpansion="1"
-                               AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include"
+                               AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include;..\..\..\..\..\lib\windows\wintab\INCLUDE"
                                PreprocessorDefinitions="WIN32,NDEBUG,_LIB"
                                StringPooling="TRUE"
                                RuntimeLibrary="0"
@@ -78,7 +78,7 @@ ECHO Done
                        <Tool
                                Name="VCCLCompilerTool"
                                Optimization="0"
-                               AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include"
+                               AdditionalIncludeDirectories="..\..;..\..\..\..\..\build\msvc_7\intern\string\include;..\..\..\..\..\lib\windows\wintab\INCLUDE"
                                PreprocessorDefinitions="WIN32,_DEBUG,_LIB"
                                BasicRuntimeChecks="3"
                                RuntimeLibrary="1"