Back to PC page

Wacom Windows Developer FAQ

Version 1.0.1
Last Updated: 09/08/05

1.1 What is the purpose of this FAQ?

This FAQ describes details and common problems with adding tablet support for Wacom tablets. It is primarily concerned with discussing issues related how to use the Wintab tablet application programming interface (API) to acquire data from Wacom's currently shipping tablet series. Some of the information in this FAQ is applicable to all Wintab applications in general.

1.2 Who is responsible for this FAQ?

This FAQ is maintained and copyrighted by Wacom Technology. It may be freely copied and distributed. If you have questions concerning it, contact kenl@Wacom.com.

1.3 What tablet models does Wacom make and what do I have to know about differences between them to support them in my code?

Currently, Wacom ships a higher-end, professional tablet series called Intuos and a consumer tablet series named Graphire. Wacom's web site at http://www.wacom.com describes in detail the models that Wacom currently sells.

There is very little you must do to support virtually all Wacom's tablet models, from those that are over five years old to the most recent. Once you have added Wintab support for one tablet, your program should work with virtually any Wacom tablets if the user has a recent version of our driver software. Except for a few features, such as two-handed input (DualTrack), your code should also work without change with other tablet manufacturer's tablets too, if they use Wintab.

The main issue you must account for to support all tablets is that some tablets will not support some data items (such as tilt or rotation) and the ranges of data items differ between tablet models. You must use the Wintab function WTInfo( WTI_DEVICES, wIndexOfData, pData ) to determine if a tablet supports a feature and the values which will be returned for that feature.

1.4 Why do Wacom tablets require using the Wintab tablet API to program the tablet?

Wintab is the industry standard for acquiring data from a graphics tablet on Intel machines and has been the standard for a number of years.

Unfortunately, there is no cross-platform graphics tablet API.

You can get a copy of the Wintab specification and the Wintab SDK from the downloads page.

1.5 What resources are available help me write code to support Wacom tablets using Wintab?

Here are some resources which hopefully will help you:

  • The RULE2 and SYSPRESS examples in the Wintab SDK work well as templates to getting tablet support working in your application.

  • The tilttest example program from the downloads page shows how to get tilt data from Wacom tablets.

  • The DualTrack example program from the downloads page shows how to acquire data from two cursors for Wacom Intuos tablets. The source code has many comments about how to use Wintab.

  • Wacom will be more than happy to answer any questions concerning using Wintab with Wacom tablets. Contact kenl@Wacom.com.

1.6 With the older Wacom tablets, my program didn't use Wintab to acquire tablet data and instead read data directly from the tablet. Can I use data directly from the newer Intuos tablets or do I have to use Wintab?

In almost all cases, you should use Wintab. Unlike the older tablets, our newer Intuos tablets were designed so that the only way applications would communicate with the tablet would be through whatever tablet API is supported by the operating system underwhich the tablet is running. In the case of Windows, this API is the industry standard called Wintab. You can get a copy of the Wintab spec and the Wintab SDK from the downloads page.

A very few individuals doing such things as university research have signed nondisclosure agreements (NDAs) with Wacom to get the data format and other information needed to communicate directly with the tablet. The data packets for Intuos are considerably more complex than the data format for the older tablets and may well change in the future. There is generally no good reason to directly communicate with the tablet instead of using Wintab, but if you have a unique situation, you can contact Wacom's Product Management to see about signing an NDA.

1.7 How does the Wacom Wintab manage the context overlap order differently than other Wintabs?

Wintab manages an overlap order of tablet contexts. Only one context can receive a given tablet event. In general, if context A is above context B in the overlap order, context B will not get any tablet events. The Wacom Wintab manages the context overlap order differently than other Wintabs. The two differences are:

  1. In other Wintabs, events fall-through to an underlying context if the overlying context does not handle the event. In the Wacom Wintab, events only fall-through to the next, underlying context if the underlying context is owned by the same application as the context above it. For example in other Wintabs, a context might not handle an event if the cursor is outside the context's tablet input area (lcInOrg and lcInExt).

  2. In other Wintabs, applications must manage their overlap order themselves. The problem is that many applications do not properly manage their overlap order, so two Wintab applications (even two instances of the same application) often do not work correctly in these Wintabs. The Wacom Wintab automatically rearranges the overlap order of the contexts when the foreground application changes.

1.8 Are there any Wintab features which are not supported by the Wacom Wintab?

Currently, the following Wintab features are not supported by the Wacom Wintab:

  • The WTMgrDeviceConfig() function.
  • The WTMgrConfigReplace() function.
  • The WTMgrConfigReplaceEx() function.
  • Packet hooks.
  • The WTINFO_CHANGE message.
  • The DVC_PNPID WTInfo index.
  • Linking with WINTABX.LIB is not supported.

2.1 How can I tell if the user is using the tablet as the current pointing device or if she is using a mouse?

By processing the WT_PROXIMITY message you receive each time a tablet cursor enters or leaves the proximity of one of your context, you can tell if she is using the tablet. The low word of the lParam parameter of the WT_PROXIMITY message is nonzero when the cursor is entering your context and zero when the cursor is exiting your context. WT_PROXIMITY messages are also sent to your context when a cursor enters or leaves your context because your context's status changed. For example, if the pen is in proximity of the tablet when your context is opened, then you will receive a WT_PROXIMITY for the pen.

2.2 How do I tell when I am getting tablet data from a particular cursor, for example an airbrush?

In general, the steps are:

  1. Tell Wintab you want to know which cursor generated each tablet packet.

  2. Watch for the WT_CSRCHANGE message which is generated when a new cursor enters your context. When you receive a WT_CSRCHANGE message, one of the parameters is the packet serial number of the packet with the new cursor. Read or peek that packet to get the cursor number of the new cursor.

  3. Use the cursor number to call WTInfo() to get detailed information about the new cursor to determine if it is the desired cursor. If this cursor number is the desired cursor, then you can be sure all packets in that context with this cursor number will be packets from the desired cursor until your context receives a WT_PROXIMITY leaving message.

A variation of this algorithm is to not use WT_CSRCHANGE or WT_PROXIMITY messages to watch for cursors entering and exiting and instead just watch the cursor numbers in the packets to see when a cursor enters or leaves your context.

In detail, the steps are:

1. Tell Wintab you want to know which cursor generated each tablet packet. Add the pkCursor field to the tablet packets your context receives by adding PK_CURSOR to the PACKETDATA symbol:

	#include < wintab.h >
	#define	PACKETDATA	
	( PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE 
	| PK_ORIENTATION | PK_CURSOR )
	#define	PACKETMODE	0
	#include < pktdef.h >

and using the PACKETDATA for the value of the lcPktData field of your Wintab context:

	wWTInfoRetVal = WTInfo( WTI_DEFSYSCTX, 0, &logicalContext );

	logicalContext.lcPktData = PACKETDATA;

	hWintabContext = WTOpen( hWnd, &logicalContext, TRUE);

The pkCursor field of each tablet packet will now contain the cursor index of the cursor which generated the packet.

2. Watch for the WT_CSRCHANGE message which is generated when a new cursor enters your context. To get the WT_CSRCHANGE message, you must set the CXO_CSRMESSAGES bit of the lcOptions field of your logical context before you open it. Use the packet serial number in the wParam parameter of this message to peek or read the packet and get the value of the packet's pkCursor field, which contains the cursor number for the new packet.

	bRetVal = WTDataPeek( hWintabContext, lParam, lParam, 1, &packet, &nNumPacketsCopied );

3. Use the cursor number to call WTInfo() to get detailed information about the new cursor to determine if it is the desired cursor. Get the CSR_TYPE and CSR_PHYSID for the new cursor. The CSR_TYPE is a bitfield which identifies the type of cursor (pen, airbrush, etc). CSR_TYPE is not defined in the current Wintab SDK, so you must define it. See the Intuos SDK for which bits identify which cursors. CSR_PHYSID is a serial number for the cursor. CSR_TYPE and CSR_PHYSID together comprise a completely unique id for the cursor.

	#define CSR_TYPE ( ( UINT ) 20 )

	wWTInfoRetVal = WTInfo( WTI_CURSORS + packet.pkCursor, CSR_TYPE, wCsrType );
	wWTInfoRetVal = WTInfo( WTI_CURSORS + packet.pkCursor, CSR_PHYSID, wCsrPhysId );

	// 0x0F06 is the bitmask used to find the specific cursor type. 0x0902 is the bit value identifing an airbrush
	if ( ( wCsrType & 0x0F06 ) == 0x0902 )
	{
		//Cursor is an airbrush 
	}

As in all discussions in this FAQ, this example is for the first tablet on the system.

2.3 The Wintab SDK examples won't run without Wintab installed on the system. How can I make my program work if there is no tablet (no Wintab) on the system?

The Wintab SDK examples implicitly link to Wintab using a LIB file. When you implicitly link to Wintab, Windows resolves the references to Wintab functions for you when the user runs your program. If Wintab is not present on the system, the OS can't resolve the references and won't load your application. To solve this, you want to explicitly link to Wintab with your own code. How to explicitly link to a DLL is described in detail in MSDN if you search titles for 'Link Explicitly'. Here is how you would explicitly link to WTInfo().

1. Define a function pointer for WTInfo.

 

	typedef UINT ( API * WTINFO ) ( UINT, UINT, LPVOID );

2. Call LoadLibrary to load Wintab32.dll

	ghWintab = LoadLibrary( "Wintab32.dll" );
	if ( !ghWintab )
	{
		return FALSE;
	}

3. Find the address of WTInfo(). Wintab functions which return strings have both an ASCII and UNICODE version. We want the ASCII version.

	WTINFO pWTInfo; 
	pWTInfo = ( WTINFO ) GetProcAddress( ghWintab, "WTInfoA" );
	if ( !pWTInfo )
	{
		return FALSE;
	}

Now you can use the function pointer to call WTInfo

	wWTInfoRetVal = = pWTInfo( WTI_INTERFACE, IFC_SPECVERSION, &wSpecVersion );

4. Unload Wintab32.dll when your program quits.

	if ( ghWintab )
	{
		FreeLibrary( ghWintab );
	}

2.4 How do I get data for the airbrush fingerwheel?

The airbrush fingerwheel data is returned as tangent pressure . The data is returned in the pkTangentPressure field of the tablet data packets. You can tell Wintab to add tangent pressure to your packets by adding PK_TANGENTPRESSURE as one of the data items to your PACKETDATA definition. The range of values which will be returned by tangent pressure can be obtained by calling WTInfo( WTI_DEVICES, DVC_TPRESSURE, &axis );

2.5 How do I support the Intuos tablet DualTrack feature, which allows two-handed input from the user?

One way to support two-handed input is to use the Wintab CSRMASK extension and two Wintab contexts, one which moves the system pointer and one which does not. See the DualTrack example from the downloads page for an example of how to use these Wintab features to support two handed input. It is also possible to implement two handed input without these Wintab features.

2.6 How can I improve the performance of my tablet-aware code?

Keep in mind that Wintab function calls are expensive. To improve performance of your application, minimize the number of Wintab calls you make, especially the number of packet functions such as WTPacket() and WTPacketsGet(). The best strategy is to use WTPacketsGet() to retrieve the maximum number of packets your context queue can hold. The return value of WTPacketsGet() is the number of packets returned. You can find-out the size of your queue by calling WTQueueSizeGet(). It is not necessary and very expensive to call WTQueuePacketsEx() to discover the number of packets waiting in your queue.

When you call Wintab functions there is a task switch. Your WndProc can easily go reentrant if you do much tablet processing in it. You might want to test for rentrancy in your code and synchronize access to global or shared resources which would be effected by reentrancy.

3.1 Why am I only getting Z coordinates of zero from the thumbwheel of the 4D mouse?

The thumbwheel of the 4D mouse can have several functions. The user sets the function of the thumbwheel in the Thumbwheel tab of the Wacom Intuos control panel applet. The default function of the thumbwheel is Intellimouse emulation. To receive Z coordinates from the thumbwheel, the user must go to the thumbwheel tab and set the function to 'Application Defined'. There is no way to change the function from your program.

3.2 Why doesn't the screen cursor move when my Wintab program is running and the user is using the tablet?

The CXO_SYSTEM bit of the lcOptions field of your logical context controls whether Wintab moves the system pointer when your context receives tablet data. If this bit is not set, then Wintab will not move the system cursor when your application is active. If you use WTInfo( WTI_DEFCONTEXT, … ) to get context information with which to create your own context, CXO_SYSTEM will be clear unless you set it before calling WTOpen.

 
	LOGCONTEXT wintabLogicalContext;
	wWTInfoRetVal = WTInfo( WTI_DEFSYSCTX, 0, &wintabLogicalContext );
	wintabLogicalContext.lcOptions |= CXO_SYSTEM;
	hWintabContext = WTOpen( hWnd, &wintabLogicalContext, TRUE );

If you use WTInfo( WTI_DEFDEFSYSCTX,...) to get context information with which to create your own context, CXO_SYSTEM will be set and the cursor will move when your application is active.

3.3 Why do I suddenly stop receiving WT_PACKET messages from the tablet or seem to only get some of the tablet packets?

You are probably missing tablet packets because your context's packet queue is overflowing. Each Wintab context has a queue of tablet packets. Wintab only adds new packets to the queue and sends your application a WT_PACKET message if the queue is not full. If the queue is full, Wintab discards the packet and does not send your application a WT_PACKET message to tell you that your context received a tablet packet. The default queue size is only eight packets and so overflows very quickly since the Intuos tablet sends between 100 and 200 packets a second.

To prevent your queue from overflowing, increase the size of your context's queue with the WTQueueSizeSet() function to a value between 32 and 128. Memory for packet queues is a limited resource, so be sure check that your call to WTQueueSizeSet() succeeds. If WTQueueSizeSet() fails, request a smaller queue size.

You can also help prevent the queue from overflowing by always removing packets from the queue when you receive a WT_PACKET message and by flushing the queue when you receive WT_PROXIMITY messages. You can flush the queue by calling:

	WTPacketsGet( hWintabContext, VALUE_LARGER_THAN_YOUR_QUEUE_SIZE, NULL);

or

	WTPacket( hWintabContext, wPacketSerialNumber, NULL ) ;

3.4 Why does my application sometimes not receive tablet data if another tablet-aware (Wintab) application is running?

Your application is not receiving tablet data because it is not at the top of the overlap order of Wintab contexts. Wintab contexts are stacked upon one another. In general, only the topmost context in the overlap order receives tablet data.

When an application becomes the active application, it should move its context to the top of the overlap order by calling WTOverlap( hWintabContext, TRUE ). When an application becomes inactive, it should call WTOverlap( hWintabContext, FALSE) to move its context to the bottom of the overlap order. The RULE2 example in the Wintab SDK shows how to appropriately handle context overlap order as a result of a WM_ACTIVATE message.

3.5 How can I tell if an attached tablet is a Wacom tablet?

There is currently no way to tell if an attached tablet is truly a Wacom tablet. Some other tablet manufacturers report their tablets as 'Wacom' tablets when you call WTInfo( WTI_DEVICES, DVC_NAME, ... ).

However, using the WTInfo() function, you can find what data items are supported by the tablet and what their ranges will be.

3.6 How can I tell which Wacom tablet model is being used?

There is currently no way to tell which tablet model is installed on the machine. However, using the WTInfo() function, you can find what data items are supported by the tablet and what their ranges will be.

3.7 If the user uses the Wacom control panel applet to customize my application or a tool (for example, sets only a portion of tablet active), the customized setting always effects my application. Is this a bug, by design, and can I stop it?

This is by design. One of the design goals of Intuos was to give the user maximum flexibility and control over the behavior of the tablet. Part of this control is application and cursor (tool) specific settings. There is, of course, a tension between allowing the user to customize settings for applications or tools and application code needing to set settings so that their applications work as the application vendors intended.

Graphics tablet applications can be generally divided into two categories: Applications which need tablet coordinates mapped to the physical coordinate space they request and those applications which don't. CAD applications, digitizing applications, and template utilities are examples of the first kind of application. Painting and drawing programs are examples of the second kind of application. There are many more applications in the second category than in the first.

In most cases, the Wacom Wintab lets the user's custom settings override the settings the application makes using the Wintab API. However, to accommodate CAD and other applications in the second category, the Wacom Wintab will let the application's Wintab context settings override the user's custom settings if the application opens a Wintab context with any of these characteristics:

  • The context has any bits set in lcLocks.
  • The application changes the tablet input origin (lcInOrgX, lcInOrgY or lcInOrgZ).
  • The application changes the tablet input size (extents) (lcInExtX, lcInExtY or lcInExtZ).
  • The application changes the screen origin (lcSysOrgX or lcSysOrgY).
  • The application changes the screen output size (extents) (lcSysOrgX or lcSysOrgY).
  • The application sets the screen cursor to move in relative mode (sets lcSysMode to non-zero).

3.8 The lens cursor and 4D mouse always move the screen pointer in relative (mouse) mode rather than pen (absolute) mode. How can I change this?

This question is a variation of FAQ 3.7. Please see that FAQ for an answer.

3.9 Why doesn't the lcPktRate field of my logical context show the correct report rate for the tablet?

The lcPcktRate field is not functional in the non-Wacom Wintab which shipped with older Wacom tablets. The Wacom Wintab currently doesn't support lcPktRate either. In both Wintabs, lcPktRate is reported as 100, but the tablet will actually be sending data at the highest rate possible for whatever mode in which the tablet is set.