Intuos, Cintiq, and Business Tablets

Intuos, Cintiq, and Business Tablets

  • Overview
  • Docs
  • FAQs
  • Support
  • GitHub

›Driver Request Interface

Intuos, Cintiq, and Business Tablets

  • Intuos, Cintiq, and Business Tablets

Windows

    Wintab

    • Overview
    • Basics
    • Reference
    • FAQs

    Windows Ink

    • Overview
    • Basics
    • Reference
    • FAQs

    Windows Native Touch

    • Overview
    • Basics
    • Reference
    • FAQs

    Wacom Feel Multi-Touch

    • Overview
    • Basics
    • Reference
    • FAQs

    Sample Code

    • Multi-Touch Windows .NET
    • Multi-Touch Windows C++
    • Wintab .NET
    • Wintab CAD Test
    • Wintab Pressure Test
    • Wintab ScribbleDemo
    • Wintab Tablet Controls
    • Wintab TiltTest

MacOS

    NS Events

    • Overview
    • Basics
    • Reference
    • FAQs

    Driver Request Interface

    • Overview
    • Basics
    • Reference
    • FAQs

    Multi-Touch Framework

    • Overview
    • Basics
    • Reference
    • FAQs

    Sample Code

    • Multi-Touch
    • Tablet Controls
    • Tablet Mapping
    • ScribbleDemo

Linux

    Building the Driver

    • Overview
    • Basics
    • Reference
    • FAQs

    GTK+

    • Overview
    • Basics
    • Reference
    • FAQs

    Kernel Events

    • Overview
    • Basics
    • Reference
    • FAQs

    Wayland

    • Overview
    • Basics
    • Reference
    • FAQs

    X Events

    • Overview
    • Basics
    • Reference
    • FAQs

    Sample Code

    • GTK+
    • Kernel Events
    • X Events

QT

  • Overview
  • Basics
  • Reference
  • FAQs

Web API

  • Overview
  • Basics
  • Reference
  • FAQs
  • Sample Code

    • ScribbleDemo Using Pointer Events

Basics

Overview

This page provides the developer with a basic overview of how to make requests of the macOS Wacom tablet driver.

Target Platforms

macOS-5based systems.

Target Tablets

Wacom tablets supported by the installed tablet driver.

Communicating with the Tablet Driver

All communication with the tablet driver should be done with Apple Events. The target of these Apple Events should be the TabletDriver application.

Generic Communication with the Tablet Driver

The Generic set of Apple Events allows you to programmatically look at settings in the tablet driver. Although you can modify settings with these events, these changes would affect the global operation of the tablet. In general, you should not change these settings. The most common use of these events would be to get the version number of the driver, the number of tablets, and the size of each tablet.

Application Specific Communication with the Tablet Driver

The Application Specific Apple Events are composed of a Wacom Apple Event SendTabletEvent and a Context class.

#define cTabletEvent     'TblE'
#define kAEWacomSuite    'Wacm'
#define eSendTabletEvent 'WSnd'
#define eEventProximity  'WePx'
#define eEventPointer    'WePt'
#define kDefaultTimeOut 15  //Timeout value in ticks Approx 1/4 second


//////////////////////////////////////////////////////////////////////////////
// resendLastTabletEventOfType:
//
// Purpose:    Send an Apple Event to the tablet driver to resend an event.
//
// Parameters: tabletEventType - eEventProximity, eEventPointer
//
+ (void) resendLastTabletEventOfType:(DescType)tabletEventType
{
    NSAppleEventDescriptor  *event      = nil;
    NSAppleEventDescriptor  *reply      = nil;
    // create the apple event for object count
    event = [NSAppleEventDescriptor appleEventWithEventClass:kAEWacomSuite
                                                     eventID:eSendTabletEvent
                                            targetDescriptor:[self driverAppleEventTarget]
                                                    returnID:kAutoGenerateReturnID
                                               transactionID:kAnyTransactionID];
                                              
    // set object class to tablet to indicate that we want tablet count
    [event setDescriptor:[NSAppleEventDescriptor descriptorWithEnumCode:tabletEventType]
              forKeyword:keyAEData];


    // send the event
    reply = [event sendExpectingReplyWithPriority:kAEHighPriority
                                       andTimeout:kTabletDriverAETimeout];
}

Context events are how some of the more advanced techniques are accomplished, such as automatic scaling, disconnecting the tablet events from the mouse, and more. Your application can ask the tablet driver to create one or more contexts per tablet and then modify the properties of these contexts as you see fit. These contexts are specific to the instance of your application that created them. Keep in mind that your contexts are only valid while your application is in the foreground. Your contexts will cease to function while your application is in the background. When your application returns as the foreground application, your contexts will return as well. When your application quits, the contexts go away permanently. (Though please be nice and destroy any created contexts before quitting.) When your application is re-launched, it must create its contexts all over again.

To create a context, send to the tablet driver an Apple Event of class / type {kAECoreSuite, kAECreateElement} with the keyAEObjectClass Param of the Apple Event filled with a DescType of cContext and the keyAEInsertHere Param filled with an object specifier of the index of the tablet (cTablet) you want to create a context for.

To set and get properties of a context, send to the tablet driver an Apple Event of class / Type {kAECore, kAESetData or kAEGetData} with the keyDirect Apple Event Parameter filled with an object specifier of the context’s (cContext) uniqueID (formUniqueID) and the property’s (cProperty) ID (formPropertyID of type DescType).

Context PropertyValueTypeDescription
pContextMapScreenArea'Smap'typeQDRectangleThis is the area of the Desktop, in pixels, that this context's tablet area will map to.
pContextMapTabletOutputArea'Tomp'typeLongRectangleThis is the rectangle that this context will map the Tablet Input Area to. (i.e. the location of the pen on the tablet input area will be scaled to this range and the result is returned in the absX, and absY tablet pointer event fields).
pContextMapTabletInputArea'Tmap'typeLongRectangleThis is the area of the tablet, in tablet counts, that this context is valid for. When a pen is in this rectangle on the tablet, it will obey the rules of this context.
pContextMovesSystemCursor'Mvsc'typeBooleanShould events generated from this context move the system cursor? If false, then all tablet events will be sent as pure tablet events.
pContextEnabled'Cenb'typeBooleanIs this context enabled? You can enable and disable the contexts you create at any time.

To destroy a context, send to the tablet driver an Apple Event of class / Type {kAECore, kAEDelete} with the keyDirect Apple Event Parameter filled with an object specifier of the context's (cContext) uniqueID (formUniqueID).

Tip:

The WacomTabletDriver class located in the Tablet Mapping sample code contains functions to Create, Destroy, Read, and Modify Contexts and their attributes. Their use is even demonstrated with the “Constrain to Window” menu command.

Scaling

To get the tablet driver to scale its output to a specific section on the screen, create a context and modify the pContextMapScreenArea attribute to a rectangle on the screen.

To get the tablet driver to scale it's absX, and absY data, create a context and modify the pContextMapTabletOutputArea to the output rectangle you would like.

Note that changing the output rectangle does not modify the screen area that the tablet driver moves the cursor and vice versa. So, for example, you can modify the pContextMapScreenArea of your context to force the cursor to remain inside your window. Then you can modify the pContextMapTabletOutputArea of the same context so that the absolute range is 0 – 1000 in both axes. Why would you want to do this? I don't know, but you can!

Overriding Tablet Controls

WacomTabletDriver provides a set of Apple Events that enable applications to take control of tablet controls. There are three types of tablet controls: ExpressKeys, TouchStrip, and TouchRing. Each control has one or more functions associated with it. Do not make an assumption of the number of controls of a specific tablet or the number of functions associated with a control. Always use the APIs to query for the information.

An application needs to do the following to override tablet controls:

  1. Create a context for the tablet of interest.
  2. Register with the distributed notification center to receive the overridden controls' data from user actions.
  3. Query for number of controls by control type (ExpressKeys, TouchStrip, or TouchRing).
  4. Query for number of functions of each control.
  5. Enumerate the functions to find out which are available for override.
  6. Set override flag for a control function that's available.
  7. Handle the control data notifications to implement functionality that the application desires for the control function.
  8. Must destroy the context upon the application's termination or when the application is done with it.

To create an override context for a tablet, send to the tablet driver an Apple Event of class / type {kAECoreSuite, kAECreateElement} with the keyAEObjectClass Param of the Apple Event filled with a DescType of cContext, the keyAEInsertHere Param filled with an object specifier of the index of the tablet (cWTDTablet) and the keyASPrepositionFor Param filled with a DescType of pContextTypeBlank.

To destroy a context, send to the tablet driver an Apple Event of class / Type {kAECore, kAEDelete} with the keyDirect Apple Event Parameter filled with an object specifier of the context's (cContext) uniqueID (formUniqueID).

Cocoa Sample Code:

#define kWacomDriverSig             'WaCM' 
#define cContext                    'CTxt' 
#define pContextTypeBlank           'Blnk' 
  
   
/////////////////////////////////////////////////////////////////////////////// 
// Helper function that returns Apple Event descriptor of the tablet driver. 
// 
+ (NSAppleEventDescriptor *)driverAppleEventTarget 
{ 
   OSType tdSig = kWacomDriverSig; 
   return [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplSignature length:sizeof(tdSig)]; 
}
/////////////////////////////////////////////////////////////////////////////// 
// Create a blank context for the tablet with index tabletIndex 
// 
+ (UInt32)makeContextForTablet:(UInt32)tabletIndex 
{ 
   UInt32 context = 0; 
   NSAppleEventDescriptor *response = nil; 
   NSAppleEventDescriptor *event = [NSAppleEventDescriptor
            appleEventWithEventClass:kAECoreSuite 
            eventID:kAECreateElement 
            targetDescriptor:[self driverAppleEventTarget] 
            returnID:kAutoGenerateReturnID 
            transactionID:kAnyTransactionID]; 
  
   [event setDescriptor:[NSAppleEventDescriptor descriptorWithTypeCode:cContext] 
            forKeyword:keyAEObjectClass]; 
         
   [event setDescriptor:[NSAppleEventDescriptor descriptorForObjectOfType:cWTDTablet 
            withKey:[NSAppleEventDescriptor descriptorWithUInt32:tabletIndex] 
            ofForm:formAbsolutePosition] 
            forKeyword:keyAEInsertHere]; 
              
   [event setDescriptor:[NSAppleEventDescriptor descriptorWithTypeCode:pContextTypeBlank] 
            forKeyword:keyASPrepositionFor]; 
   
   response = [event sendExpectingReplyWithPriority:kAEHighPriority 
            andTimeout:kWtcTabletDriverAETimeout]; 
  
   context = [[response descriptorForKeyword:keyDirectObject] int32Value]; 
  
   return context;    
} 

/////////////////////////////////////////////////////////////////////////////// 
// Destroy context 
// 
+ (void)destroyContext:(UInt32)context 
{ 
   NSAppleEventDescriptor *event = [NSAppleEventDescriptor 
            appleEventWithEventClass:kAECoreSuite 
            eventID:kAEDelete 
            targetDescriptor:[self driverAppleEventTarget] 
            returnID:kAutoGenerateReturnID 
            transactionID:kAnyTransactionID]; 
  
   [event setDescriptor:[NSAppleEventDescriptor descriptorForObjectOfType:cContext 
            withKey:[NSAppleEventDescriptor descriptorWithUInt32:context] 
            ofForm:formUniqueID] 
            forKeyword:keyDirectObject]; 
   
   [event sendWithPriority:kAEHighPriority andTimeout:kWtcTabletDriverAETimeout]; 
} 

To Get or Set properties of a control function, send to the tablet driver an Apple Event of class / Type {kAECore, kAESetData or kAEGetData} with the keyDirect Apple Event Parameter that specifies the override context, index of the control and function to override. The structure of the descriptor filled looks like this:

cContext

--- cWTDExpressKey (cWTDTouchRing, or cWTDTouchStrip)

--- cWTDControlFunction

The table below lists the properties that an application can Get and/or Set for a tablet control or its functions.

PropertyValueTypeDescriptionNotes
pFunctionAvailable'FunA'typeBooleanThis indicates whether the control function is available for an application to override.Read only.
pControlMinValue'CMin'typeUInt32The minimum value of the control.Read only. Function index ignored.
pControlMaxValue'CMax'typeUInt32The maximum value of the controlRead only. Function index ignored.
pControlLocation'CLoc'typeUInt32The physical location of the control on the tablet.Read only. Function index ignored. 0 - left; 1 - right; 2 – top; 3 – bottom.
pOverrideFlag'OvrF'typeBooleanGet or set the override flag for a control function.Read/Write

Cocoa Sample Code:


#define kInavlidAppleEventIndex     0 
  
#define cContext                    'CTxt' 
#define cWTDTouchRing               'WRnG' 
#define cWTDExpressKey              'WExK' 
#define cWTDTouchStrip              'WTcS' 
#define cWTDControlFunction         'WCtF' 
  
#define pFunctionAvailable          'FunA' 
#define pOverrideFlag               'OvrF' 
#define pOverrideName               'ONme' 
  
typedef enum eAETabletControlType 
{ 
   eAETouchRing = 0, 
   eAETouchStrip, 
   eAEExpressKey 
} eAETabletControlType; 
  
/////////////////////////////////////////////////////////////////////////////// 
// Helper function for translating tablet control type to Apple Event class. 
// 
+ (DescType)descTypeFromControlType:(SInt32)controlType 
{ 
   if (controlType == eAETouchStrip) 
   { 
      return cWTDTouchStrip; 
   } 
   else if (controlType == eAEExpressKey) 
   { 
      return cWTDExpressKey; 
   } 
   return cWTDTouchRing;                                         
} 
  
/////////////////////////////////////////////////////////////////////////////// 
// Helper function for querying the tablet driver for a tablet control property. 
// 
+ (NSAppleEventDescriptor*)dataForAttribute:(DescType)attribute ofType:(DescType)dataType 
         ofFunction:(UInt32)function ofControl:(UInt32)control 
         ofContext:(UInt32)context forControlType:(SInt32)controlType 
{ 
   NSAppleEventDescriptor *reply = nil; 
   NSAppleEventDescriptor *event = [NSAppleEventDescriptor 
         appleEventWithEventClass:kAECoreSuite 
         eventID:kAEGetData 
         targetDescriptor:[self driverAppleEventTarget] 
         returnID:kAutoGenerateReturnID 
         transactionID:kAnyTransactionID]; 
              
   // context descriptor 
   NSAppleEventDescriptor *contextDesc = [NSAppleEventDescriptor 
         descriptorForObjectOfType:cContext 
         withKey:[NSAppleEventDescriptor descriptorWithUInt32:context] 
         ofForm:formUniqueID]; 
               
   // control descriptor 
   NSAppleEventDescriptor *controlDesc = [NSAppleEventDescriptor 
         descriptorForObjectOfType:[self descTypeFromControlType:controlType] 
         withKey:[NSAppleEventDescriptor descriptorWithUInt32:control] 
         ofForm:formAbsolutePosition from:contextDesc]; 
  
   // function descriptor 
   NSAppleEventDescriptor *functionDesc = (kInavlidAppleEventIndex != function) ? 
     [NSAppleEventDescriptor 
            descriptorForObjectOfType:cWTDControlFunction 
            withKey:[NSAppleEventDescriptor descriptorWithUInt32:function] 
            ofForm:formAbsolutePosition from:controlDesc] : nil; 
  
   // attribute descriptor 
   NSAppleEventDescriptor *attribDesc = [NSAppleEventDescriptor  
         descriptorForObjectOfType:formPropertyID 
         withKey:[NSAppleEventDescriptor descriptorWithTypeCode:attribute] 
         ofForm:formPropertyID from:functionDesc ? functionDesc : controlDesc]; 
  
   [event setDescriptor:attribDesc forKeyword:keyDirectObject]; 
   
   [event setDescriptor:[NSAppleEventDescriptor descriptorWithTypeCode:dataType] 
         forKeyword:keyAERequestedType]; 
   
   // send 
   reply = [event sendExpectingReplyWithPriority:kAEHighPriority 
         andTimeout:kWtcTabletDriverAETimeout]; 
   
   return [reply descriptorForKeyword:keyDirectObject]; 
} 
  
/////////////////////////////////////////////////////////////////////////////// 
// Helper function for setting a tablet control property. 
// 
+ (BOOL)setBytes:(void*)bytes ofSize:(UInt32)size ofType:(DescType)dataType 
         forAttribute:(DescType)attribute 
         ofFunction:(UInt32)function ofControl:(UInt32)control 
         ofContext:(UInt32)context forControlType:(SInt32)controlType 
{ 
   OSErr err = noErr; 
   NSAppleEventDescriptor *data = nil; 
   NSAppleEventDescriptor *event = [NSAppleEventDescriptor 
         appleEventWithEventClass:kAECoreSuite 
         eventID:kAESetData 
         targetDescriptor:[self driverAppleEventTarget] 
         returnID:kAutoGenerateReturnID 
         transactionID:kAnyTransactionID]; 
  
   // context descriptor 
   NSAppleEventDescriptor *contextDesc = [NSAppleEventDescriptor 
         descriptorForObjectOfType:cContext 
         withKey:[NSAppleEventDescriptor descriptorWithUInt32:context] 
         ofForm:formUniqueID]; 
              
   // control descriptor 
   NSAppleEventDescriptor *controlDesc = [NSAppleEventDescriptor 
         descriptorForObjectOfType:[self descTypeFromControlType:controlType] 
         withKey:[NSAppleEventDescriptor descriptorWithUInt32:control] 
         ofForm:formAbsolutePosition from:contextDesc]; 
  
   // function descriptor 
   NSAppleEventDescriptor *functionDesc = (kInavlidAppleEventIndex != function) ? 
     [NSAppleEventDescriptor 
            descriptorForObjectOfType:cWTDControlFunction 
            withKey:[NSAppleEventDescriptor descriptorWithUInt32:function] 
            ofForm:formAbsolutePosition from:controlDesc] : nil; 
  
   // attribute descriptor 
   NSAppleEventDescriptor *attribDesc = [NSAppleEventDescriptor  
         descriptorForObjectOfType:formPropertyID 
         withKey:[NSAppleEventDescriptor descriptorWithTypeCode:attribute] 
         ofForm:formPropertyID 
         from:functionDesc ? functionDesc : controlDesc]; 
  
   [event setDescriptor:attribDesc forKeyword:keyDirectObject]; 
  
   [event setDescriptor:[NSAppleEventDescriptor descriptorWithTypeCode:dataType] 
         forKeyword:keyAERequestedType]; 
   
   data = [NSAppleEventDescriptor descriptorWithDescriptorType:dataType 
         bytes:bytes length:size]; 
  
   [event setDescriptor:data forKeyword:keyAEData]; 
  
   // send 
   err = [event sendWithPriority:kAEHighPriority andTimeout:kWtcTabletDriverAETimeout]; 
  
   return (err == noErr); 
} 
  
/////////////////////////////////////////////////////////////////////////////// 
// Override touch ring of a tablet associated with the input context. 
//
(void)takeControlOfRingInContext:(UInt32)context  
      withRingCount:(UInt32)ringCount andFunctionCount:(UInt32)functionCount 
{ 
   UInt32 controlIndex; 
   for (controlIndex = 1; controlIndex <= ringCount; controlIndex++) 
   { 
      UInt32 functionIndex; 
      for (functionIndex = 1; functionIndex <= functionCount; functionIndex++) 
      {
         // check if this function is available for override 
         NSAppleEventDescriptor *aeResponse = [[self class]  
            dataForAttribute:pFunctionAvailable  
            ofType:typeBoolean 
            ofFunction:functionIndex  
            ofControl:controlIndex  
            ofContext:context  
            forControlType:eAETouchRing]; 
         if ([aeResponse booleanValue] != 0) 
         { 
            // this ring function is available for override 
            // send apple event to override 
            Boolean overrideFlag = 1; 
            BOOL success = [[self class] setBytes:&overrideFlag 
               ofSize:sizeof(overrideFlag) ofType:typeBoolean  
               forAttribute:pOverrideFlag 
               ofFunction:functionIndex 
               ofControl:controlIndex 
               ofContext:context                       
               forControlType:eAETouchRing]; 
            if (!success) 
            { 
               NSLog(@"Failed to override Ring#%d Function#%d.",  
                         controlIndex, functionIndex); 
            } 
         } 
      } 
   } 
} 

An application that overrides tablet controls needs to register with the distributed notification center to receive overridden controls' data when user performs an action on the controls. The user info dictionary of the notifications contains the value of the control and information that indicates which tablet, control, and function the data is for:

  1. Tablet index - 1-based index for the tablet of interest.
  2. Control type - the type of the tablet control.
  3. Control index - 1-based index for the tablet control.
  4. Function index - 1-based index for the currently active function of the control.
  5. Control value - current value of the control.

Cocoa Sample Code:

#define kWacomNotificationObject           "com.wacom.tabletdriver.hardware" 
#define kWacomTabletControlNotification    "com.wacom.tabletdriver.hardware.controldata" 
 
#define kTabletNumberKey     "Tablet Number"       // 1-based system tablet index 
#define kControlTypeKey      "Control Type"        // eAETouchRing, eAETouchStrip, or eAEExpressKey 
#define kControlNumberKey    "Control Number"      // 1-based index 
#define kFunctionNumberKey   "Function Number"     // 1-based index 
#define kControlValueKey     "Control Value"       // current control value 
 
/////////////////////////////////////////////////////////////////////////////// 
// Register observer for control data notificaations. 
//
(void)observeContext:(UInt32)context 
{ 
  // NOTE: suspend the notifications when the application is in the background 
  // since the overrides are effective only when the application is in the foreground 
  if (context != 0) 
  { 
     [[NSDistributedNotificationCenter notificationCenterForType:NSLocalNotificationCenterType] 
           addObserver:self 
           selector:@selector(tabletControlData
           name:@kWacomTabletControlNotification 
           object:@kWacomNotificationObject 
           suspensionBehavior:NSNotificationSuspensionBehaviorDrop]; 
  } 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// This is where we handle tablet control data notification. 
// 
(void)tabletControlData:(NSNotification*)note 
{ 
  // extract control data from the notification 
  NSDictionary *userInfo = [note userInfo]; 
  SInt32 controlType = [[userInfo objectForKey:@kControlTypeKey] longValue]; 
  UInt32 tabletIndex = [[dict objectForKey:@kTabletNumberKey] unsignedLongValue]; 
  UInt32 controlIndex = [[dict objectForKey:@kControlNumberKey] unsignedLongValue]; 
  UInt32 functionIndex = [[dict objectForKey:@kFunctionNumberKey] unsignedLongValue]; 
  UInt32 controlValue = [[dict objectForKey:@kControlValueKey] unsignedLongValue]; 

  // do something with the data 
  // ... 
} 
← OverviewReference →
  • Overview
  • Target Platforms
  • Target Tablets
  • Communicating with the Tablet Driver
    • Generic Communication with the Tablet Driver
    • Application Specific Communication with the Tablet Driver
  • Scaling
  • Overriding Tablet Controls
Intuos, Cintiq, and Business Tablets
DOCS
IntroductionWindowsMac OSLinuxQtWeb API
COMMUNITY
TwitterLinkedInGitHub
ABOUT
Terms of UsePrivacyCookies
Wacom Developer Relations
Copyright © 2021 Wacom Co., Ltd