Improved tablet support on Windows. Nice deep queue for input points. Much more is being captured now. WT_PACKET events are disabled until I can revisit in a day or two.

Also added Wacom's driver wrappers, with their permission. These won't live here very long, but the WindowWin32 tablet code uses it for now.
This commit is contained in:
Mike Erwin 2010-07-15 12:12:52 +00:00
parent 56b287bfe6
commit 5b1925afba
4 changed files with 325 additions and 40 deletions

@ -39,6 +39,10 @@
#include "GHOST_SystemWin32.h" #include "GHOST_SystemWin32.h"
#include "GHOST_DropTargetWin32.h" #include "GHOST_DropTargetWin32.h"
//#include "wintab.h" // for tablets, naturally
#include "Utils.c" // that's right, .c, with permission from Wacom
#include <stdio.h> // for debug, remove soon [mce]
// Need glew for some defines // Need glew for some defines
#include <GL/glew.h> #include <GL/glew.h>
#include <GL/wglew.h> #include <GL/wglew.h>
@ -122,7 +126,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(
m_hasMouseCaptured(false), m_hasMouseCaptured(false),
m_nPressedButtons(0), m_nPressedButtons(0),
m_customCursor(0), m_customCursor(0),
m_wintab(NULL), m_wintab(false),
m_tabletData(NULL), m_tabletData(NULL),
m_tablet(0), m_tablet(0),
m_maxPressure(0), m_maxPressure(0),
@ -238,14 +242,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(
} }
} }
m_wintab = ::LoadLibrary("Wintab32.dll"); m_wintab = LoadWintab();
if (m_wintab) { 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 // let's see if we can initialize tablet here
/* check if WinTab available. */ /* check if WinTab available. */
if (fpWTInfo && fpWTInfo(0, 0, NULL)) { if (gpWTInfoA(0, 0, NULL)) {
// Now init the tablet // Now init the tablet
LOGCONTEXT lc; LOGCONTEXT lc;
AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */ AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
@ -253,26 +254,27 @@ GHOST_WindowWin32::GHOST_WindowWin32(
// Open a Wintab context // Open a Wintab context
// Get default context information // Get default context information
fpWTInfo( WTI_DEFCONTEXT, 0, &lc ); gpWTInfoA( WTI_DEFCONTEXT, 0, &lc );
// Open the context // Open the context
lc.lcPktData = PACKETDATA; lc.lcPktData = PACKETDATA;
lc.lcPktMode = PACKETMODE; lc.lcPktMode = PACKETMODE;
lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM; lc.lcOptions |= /* CXO_MESSAGES | */ CXO_SYSTEM;
lc.lcOptions &= ~CXO_MESSAGES;
/* Set the entire tablet as active */ /* Set the entire tablet as active */
fpWTInfo(WTI_DEVICES,DVC_X,&TabletX); gpWTInfoA(WTI_DEVICES,DVC_X,&TabletX);
fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY); gpWTInfoA(WTI_DEVICES,DVC_Y,&TabletY);
/* get the max pressure, to divide into a float */ /* get the max pressure, to divide into a float */
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); BOOL pressureSupport = gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
if (pressureSupport) if (pressureSupport)
m_maxPressure = Pressure.axMax; m_maxPressure = Pressure.axMax;
else else
m_maxPressure = 0; m_maxPressure = 0;
/* get the max tilt axes, to divide into floats */ /* get the max tilt axes, to divide into floats */
BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); BOOL tiltSupport = gpWTInfoA(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
if (tiltSupport) { if (tiltSupport) {
/* does the tablet support azimuth ([0]) and altitude ([1]) */ /* does the tablet support azimuth ([0]) and altitude ([1]) */
if (Orientation[0].axResolution && Orientation[1].axResolution) { if (Orientation[0].axResolution && Orientation[1].axResolution) {
@ -285,12 +287,16 @@ GHOST_WindowWin32::GHOST_WindowWin32(
} }
} }
if (fpWTOpen) { m_tablet = gpWTOpenA( m_hWnd, &lc, TRUE );
m_tablet = fpWTOpen( m_hWnd, &lc, TRUE ); if (m_tablet) {
if (m_tablet) { m_tabletData = new GHOST_TabletData();
m_tabletData = new GHOST_TabletData(); m_tabletData->Active = GHOST_kTabletModeNone;
m_tabletData->Active = GHOST_kTabletModeNone;
} // request a deep queue, to capture every pen point
int tabletQueueSize = 128;
while (!gpWTQueueSizeSet(m_tablet, tabletQueueSize))
--tabletQueueSize;
printf("tablet queue size: %d\n", tabletQueueSize);
} }
} }
} }
@ -300,14 +306,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(
GHOST_WindowWin32::~GHOST_WindowWin32() GHOST_WindowWin32::~GHOST_WindowWin32()
{ {
if (m_wintab) { if (m_wintab) {
GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" ); if (m_tablet)
if (fpWTClose) { gpWTClose(m_tablet);
if (m_tablet) if (m_tabletData)
fpWTClose(m_tablet); delete m_tabletData;
if (m_tabletData) m_tabletData = NULL;
delete m_tabletData; UnloadWintab();
m_tabletData = NULL;
}
} }
if (m_customCursor) { if (m_customCursor) {
DestroyCursor(m_customCursor); DestroyCursor(m_customCursor);
@ -912,20 +916,16 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
void GHOST_WindowWin32::processWin32TabletInitEvent() void GHOST_WindowWin32::processWin32TabletInitEvent()
{ {
if (m_wintab) { if (m_wintab) {
GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
// let's see if we can initialize tablet here // let's see if we can initialize tablet here
/* check if WinTab available. */
if (fpWTInfo) {
AXIS Pressure, Orientation[3]; /* The maximum tablet size */ AXIS Pressure, Orientation[3]; /* The maximum tablet size */
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure); BOOL pressureSupport = gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
if (pressureSupport) if (pressureSupport)
m_maxPressure = Pressure.axMax; m_maxPressure = Pressure.axMax;
else else
m_maxPressure = 0; m_maxPressure = 0;
BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation); BOOL tiltSupport = gpWTInfoA(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
if (tiltSupport) { if (tiltSupport) {
/* does the tablet support azimuth ([0]) and altitude ([1]) */ /* does the tablet support azimuth ([0]) and altitude ([1]) */
if (Orientation[0].axResolution && Orientation[1].axResolution) { if (Orientation[0].axResolution && Orientation[1].axResolution) {
@ -938,17 +938,22 @@ void GHOST_WindowWin32::processWin32TabletInitEvent()
} }
m_tabletData->Active = GHOST_kTabletModeNone; m_tabletData->Active = GHOST_kTabletModeNone;
}
} }
} }
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
{ {
PACKET pkt; // PACKET pkt;
if (m_wintab) { if (m_wintab) {
GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" ); printf("tablet event ");
if (fpWTPacket) { PACKET pkt_buffer[128];
if (fpWTPacket((HCTX)lParam, wParam, &pkt)) { int n = gpWTPacketsGet((HCTX)lParam, 128, pkt_buffer);
printf("(%d in queue) ", n);
for (int i = 0; i < n; ++i) {
PACKET& pkt = pkt_buffer[i];
// "while" not "if" -- drain the queue!
// while (gpWTPacket((HCTX)lParam, wParam, &pkt)) {
putchar('.');
if (m_tabletData) { if (m_tabletData) {
switch (pkt.pkCursor) { switch (pkt.pkCursor) {
case 0: /* first device */ case 0: /* first device */
@ -1008,7 +1013,7 @@ void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
} }
} }
} }
} putchar('\n');
} }
} }

@ -39,9 +39,10 @@
#include "GHOST_Window.h" #include "GHOST_Window.h"
#define _WIN32_WINNT 0x501 // require Windows XP or newer
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <wintab.h> #include <wintab.h>
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) #define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
#define PACKETMODE PK_BUTTONS #define PACKETMODE PK_BUTTONS
@ -50,11 +51,13 @@
class GHOST_SystemWin32; class GHOST_SystemWin32;
class GHOST_DropTargetWin32; class GHOST_DropTargetWin32;
/*
// typedefs for WinTab functions to allow dynamic loading // typedefs for WinTab functions to allow dynamic loading
typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID ); typedef UINT (API * GHOST_WIN32_WTInfo) ( UINT, UINT, LPVOID );
typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL); typedef HCTX (API * GHOST_WIN32_WTOpen) (HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX); typedef BOOL (API * GHOST_WIN32_WTClose) (HCTX);
typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID); typedef BOOL (API * GHOST_WIN32_WTPacket) (HCTX, UINT, LPVOID);
*/
/** /**
* GHOST window on M$ Windows OSs. * GHOST window on M$ Windows OSs.
@ -328,7 +331,8 @@ protected:
static const int s_maxTitleLength; static const int s_maxTitleLength;
/** WinTab dll handle */ /** WinTab dll handle */
HMODULE m_wintab; // HMODULE m_wintab;
bool m_wintab;
/** Tablet data for GHOST */ /** Tablet data for GHOST */
GHOST_TabletData* m_tabletData; GHOST_TabletData* m_tabletData;

182
intern/ghost/intern/Utils.c Normal file

@ -0,0 +1,182 @@
/*----------------------------------------------------------------------------
NAME
Utils.c
PURPOSE
Some general-purpose functions for the WinTab demos.
COPYRIGHT
Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved
All rights reserved.
---------------------------------------------------------------------------- */
#include "Utils.h"
#ifdef WACOM_DEBUG
void WacomTrace( char *lpszFormat, ...);
#define WACOM_ASSERT( x ) assert( x )
#define WACOM_TRACE(...) WacomTrace(__VA_ARGS__)
#else
#define WACOM_TRACE(...)
#define WACOM_ASSERT( x )
#endif // WACOM_DEBUG
//////////////////////////////////////////////////////////////////////////////
HINSTANCE ghWintab = NULL;
WTINFOA gpWTInfoA = NULL;
WTOPENA gpWTOpenA = NULL;
WTGETA gpWTGetA = NULL;
WTSETA gpWTSetA = NULL;
WTCLOSE gpWTClose = NULL;
WTPACKET gpWTPacket = NULL;
WTENABLE gpWTEnable = NULL;
WTOVERLAP gpWTOverlap = NULL;
WTSAVE gpWTSave = NULL;
WTCONFIG gpWTConfig = NULL;
WTRESTORE gpWTRestore = NULL;
WTEXTSET gpWTExtSet = NULL;
WTEXTGET gpWTExtGet = NULL;
WTQUEUESIZESET gpWTQueueSizeSet = NULL;
WTDATAPEEK gpWTDataPeek = NULL;
WTPACKETSGET gpWTPacketsGet = NULL;
// TODO - add more wintab32 function pointers as needed
char* pszProgramName = NULL;
#define GETPROCADDRESS(type, func) \
gp##func = (type)GetProcAddress(ghWintab, #func); \
if (!gp##func){ WACOM_ASSERT(FALSE); UnloadWintab(); return FALSE; }
//////////////////////////////////////////////////////////////////////////////
// Purpose
// Find wintab32.dll and load it.
// Find the exported functions we need from it.
//
// Returns
// TRUE on success.
// FALSE on failure.
//
BOOL LoadWintab( void )
{
ghWintab = LoadLibraryA( "Wintab32.dll" );
if ( !ghWintab )
{
DWORD err = GetLastError();
WACOM_TRACE("LoadLibrary error: %i\n", err);
ShowError("Could not load Wintab32.dll");
return FALSE;
}
// Explicitly find the exported Wintab functions in which we are interested.
// We are using the ASCII, not unicode versions (where applicable).
GETPROCADDRESS( WTOPENA, WTOpenA );
GETPROCADDRESS( WTINFOA, WTInfoA );
GETPROCADDRESS( WTGETA, WTGetA );
GETPROCADDRESS( WTSETA, WTSetA );
GETPROCADDRESS( WTPACKET, WTPacket );
GETPROCADDRESS( WTCLOSE, WTClose );
GETPROCADDRESS( WTENABLE, WTEnable );
GETPROCADDRESS( WTOVERLAP, WTOverlap );
GETPROCADDRESS( WTSAVE, WTSave );
GETPROCADDRESS( WTCONFIG, WTConfig );
GETPROCADDRESS( WTRESTORE, WTRestore );
GETPROCADDRESS( WTEXTSET, WTExtSet );
GETPROCADDRESS( WTEXTGET, WTExtGet );
GETPROCADDRESS( WTQUEUESIZESET, WTQueueSizeSet );
GETPROCADDRESS( WTDATAPEEK, WTDataPeek );
GETPROCADDRESS( WTPACKETSGET, WTPacketsGet );
// TODO - don't forget to NULL out pointers in UnloadWintab().
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
// Purpose
// Uninitializes use of wintab32.dll
//
// Returns
// Nothing.
//
void UnloadWintab( void )
{
WACOM_TRACE( "UnloadWintab()\n" );
if ( ghWintab )
{
FreeLibrary( ghWintab );
ghWintab = NULL;
}
gpWTOpenA = NULL;
gpWTClose = NULL;
gpWTInfoA = NULL;
gpWTPacket = NULL;
gpWTEnable = NULL;
gpWTOverlap = NULL;
gpWTSave = NULL;
gpWTConfig = NULL;
gpWTGetA = NULL;
gpWTSetA = NULL;
gpWTRestore = NULL;
gpWTExtSet = NULL;
gpWTExtGet = NULL;
gpWTQueueSizeSet = NULL;
gpWTDataPeek = NULL;
gpWTPacketsGet = NULL;
}
//////////////////////////////////////////////////////////////////////////////
// Purpose
// Display error to user.
//
void ShowError( char *pszErrorMessage )
{
WACOM_TRACE( "ShowError()\n" );
WACOM_ASSERT( pszErrorMessage );
MessageBoxA( NULL, pszErrorMessage, gpszProgramName, MB_OK | MB_ICONHAND );
}
#ifdef WACOM_DEBUG
//////////////////////////////////////////////////////////////////////////////
void WacomTrace( char *lpszFormat, ...)
{
char szTraceMessage[ 128 ];
int nBytesWritten;
va_list args;
WACOM_ASSERT( lpszFormat );
va_start( args, lpszFormat );
nBytesWritten = _vsnprintf( szTraceMessage, sizeof( szTraceMessage ) - 1,
lpszFormat, args );
if ( nBytesWritten > 0 )
{
OutputDebugStringA( szTraceMessage );
}
va_end( args );
}
#endif // WACOM_DEBUG

@ -0,0 +1,94 @@
/*----------------------------------------------------------------------------
NAME
Utils.h
PURPOSE
Defines for the general-purpose functions for the WinTab demos.
COPYRIGHT
Copyright (c) Wacom Company, Ltd. 2010 All Rights Reserved
All rights reserved.
---------------------------------------------------------------------------- */
#pragma once
#include <windows.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include <wintab.h> // NOTE: get from wactab header package
//////////////////////////////////////////////////////////////////////////////
#define WACOM_DEBUG
// Ignore warnings about using unsafe string functions.
#pragma warning( disable : 4996 )
//////////////////////////////////////////////////////////////////////////////
// Function pointers to Wintab functions exported from wintab32.dll.
typedef UINT ( API * WTINFOA ) ( UINT, UINT, LPVOID );
typedef HCTX ( API * WTOPENA )( HWND, LPLOGCONTEXTA, BOOL );
typedef BOOL ( API * WTGETA ) ( HCTX, LPLOGCONTEXT );
typedef BOOL ( API * WTSETA ) ( HCTX, LPLOGCONTEXT );
typedef BOOL ( API * WTCLOSE ) ( HCTX );
typedef BOOL ( API * WTENABLE ) ( HCTX, BOOL );
typedef BOOL ( API * WTPACKET ) ( HCTX, UINT, LPVOID );
typedef BOOL ( API * WTOVERLAP ) ( HCTX, BOOL );
typedef BOOL ( API * WTSAVE ) ( HCTX, LPVOID );
typedef BOOL ( API * WTCONFIG ) ( HCTX, HWND );
typedef HCTX ( API * WTRESTORE ) ( HWND, LPVOID, BOOL );
typedef BOOL ( API * WTEXTSET ) ( HCTX, UINT, LPVOID );
typedef BOOL ( API * WTEXTGET ) ( HCTX, UINT, LPVOID );
typedef BOOL ( API * WTQUEUESIZESET ) ( HCTX, int );
typedef int ( API * WTDATAPEEK ) ( HCTX, UINT, UINT, int, LPVOID, LPINT);
typedef int ( API * WTPACKETSGET ) (HCTX, int, LPVOID);
// TODO - add more wintab32 function defs as needed
//////////////////////////////////////////////////////////////////////////////
extern char* gpszProgramName;
// Loaded Wintab32 API functions.
extern HINSTANCE ghWintab;
extern WTINFOA gpWTInfoA;
extern WTOPENA gpWTOpenA;
extern WTGETA gpWTGetA;
extern WTSETA gpWTSetA;
extern WTCLOSE gpWTClose;
extern WTPACKET gpWTPacket;
extern WTENABLE gpWTEnable;
extern WTOVERLAP gpWTOverlap;
extern WTSAVE gpWTSave;
extern WTCONFIG gpWTConfig;
extern WTRESTORE gpWTRestore;
extern WTEXTSET gpWTExtSet;
extern WTEXTGET gpWTExtGet;
extern WTQUEUESIZESET gpWTQueueSizeSet;
extern WTDATAPEEK gpWTDataPeek;
extern WTPACKETSGET gpWTPacketsGet;
// TODO - add more wintab32 function pointers as needed
//////////////////////////////////////////////////////////////////////////////
BOOL LoadWintab( void );
void UnloadWintab( void );
void ShowError( char *pszErrorMessage );
//////////////////////////////////////////////////////////////////////////////
#ifdef WACOM_DEBUG
void WacomTrace( char *lpszFormat, ...);
#define WACOM_ASSERT( x ) assert( x )
#define WACOM_TRACE(...) WacomTrace(__VA_ARGS__)
#else
#define WACOM_TRACE(...)
#define WACOM_ASSERT( x )
#endif // WACOM_DEBUG