ELO WINCE API MANUAL
eloApiCe.doc
Updated: 2009-02-12
Synopsis: Describes the Elo WINCE API for applications to communicate directly with Elo serial and USB touchscreen drivers.
Topics:
Touchscreen drivers normally do not communicate directly with application programs but translate touch events to mouse events, which they send to the OS (function mouse_event) to pass on to applications. The OS determines which application will receive a message based on its video coordinates.
Most application programs do not need to communicate directly with touchscreen drivers any more than they need to communicate with a mouse driver. However, as with a mouse, while the standard behavior of a touchscreen may be adequate, configuring it to more precisely meet the needs of an application can produce a better user experience.
When a CE system boots, Elo touchscreen drivers configure themselves from information contained in the registry, affording the system developer a means to configure the touchscreen according to the needs of the application if those needs are static. To accommodate changing needs, applications communicate directly with drivers through the Elo API. The most obvious situations requiring this facility are calibration, where touch events are reported directly to the application, and system development, where driver operation is modified immediately without rebuilding the system. These represent complex situations involving direct driver communication over an extended period. System developers need not concern themselves with these because Elo's eloVa and eloTalk programs afford complete capability in these areas.
System developers will typically find the API useful for configuration changes of more limited scope, such as rotating the display or putting the touchscreen into cleaning mode. However, there is only one API and it does not distinguish functions by expected usage but by program structure. This document points out the functions that are most likely to be generally useful.
TYPICALLY USEFUL API FUNCTIONS
This is an operational description of functions that many applications may find useful. Structural details are described elsewhere in this document.
All of these functions require eloApi.dll to be included in the CE system. The application source code requires eloCodes.h, eloIoctl.h, and eloApi.h. It is only necessary to include eloApi.h, which includes the other two header files.
Most of these functions are called with at least two parameters, the device number and device name. Device number is required. Elo touchscreen devices are normally numbered consecutively, starting at 1. Device name is optional. Including it speeds up execution. In most systems, the name and number of a device are synchronized, for example device number 1 and "Elo1:" (note the required ':' in the name).
The touchscreen can be rotated to the 0, 90, 180, and 270 degree (counter-clockwise) orientation by a registry setting and/or dynamically through the IOCTL_ELO_ROTATE command. Recalibration is not required and calibration performed at any orientation produces results applicable to all other orientations. Calibration results are stored in the registry and/or controller (depending on each touchscreen's "CalStore" registry value) normalized to 0 orientation. Consequently, the stored parameters are compatible with older drivers that do not afford the flexibility of this new CE driver and a precalibrated touchscreen may be attached to a system in any orientation.
By default, the driver initializes each touchscreen with its 0-degree parameters. If the driver's root key (HKLM\HARDWARE\DEVICEMAP\TOUCH\USB or SER) contains the value "Orient" assigned 1, 2, or 3, touchscreens are initialized to 90-, 180-, or 270-degree orientation. Unless "Orient" bit 10 (ORIENT_NO_VIDEO) is set, the driver additionally rotates the video display by invoking the OS function ChangeDisplaySettingsEx. For CE5.0, this is more convenient than the alternative:
[HKEY_LOCAL_MACHINE\System\GDI\Rotation]
"Angle"=dword:5A ; 0=0, 5A=90, B4=180, 10E=270
For CE6.0, calling ChangeDisplaySettingsEx instead of using the Rotation registry key is essential. Because of an error in the GWES code, when "Angle" is 0, subsequent interactive rotation works just as it does under CE5.0. However, when "Angle" is any other value, rotation by ChangeDisplaySettingsEx may fail, possibly crashing the system.
In previous Elo CE releases, the registry value "SWAPXY" (or "XySwapped") required adjustment to match video rotation. It no longer serves in this capacity and should not be adjusted for any reason. It is now strictly a calibration parameter, indicating the relationship between the touchscreen and video panel, irrespective of video orientation.
The IOCTL_ELO_ROTATE command can be invoked at any time to rotate the touchscreen. The one argument to this command performs similarly to the "Orient" data. Values 0, 1, 2, and 3 select 90-, 180-, or 270-degree orientation. "Orient" bits 9 and 8 define the driver's default behavior when processing IOCTL_ELO_ROTATE. Bit 9 (ORIENT_WRITEREG) tells to write Orient changes to the registry and bit 8 (ORIENT_FLUSHREG) tells to flush the registry after writing. The rotate command flags ROTATE_WRITEREG, ROTATE_NO_WRITEREG, ROTATE_NO_VIDEO, and ROTATE_VIDEO can be used to enforce particular behavior regardless of the "Orient" defaults but only at the time they are used. This command can only change the orientation portion of "Orient" in the registry. There is no argument flag for flushing, which is done only if Orient's ORIENT_FLUSHREG flag is set. An additional argument flag is ROTATE_FORCE, which tells the driver to process the command even if the orientation is not changing. An application might use this to update "Orient" in the registry after a series of changes without updating.
Although it is possible to directly pass this command to the driver, it is more convenient to call one of the related EloApi functions. For example, to rotate the first or only screen to 270-degrees, ensuring that the video is rotated regardless of "Orient" flags,
EloApi::rotate( rotate_270 + rotate_video, 1, _T("Elo1:"));
More conveniently, especially if the system has multiple screens:
EloApi::rotateAll(rotate_270 + rotate_video );
The touch lockout facility is used to prevent inadvertent activation during cleaning or when the touchscreen is not in use. A touchscreen can be put into cleaning mode only by sending it an IOCTL_ELO_ON_TOUCH command with appropriate arguments. While in cleaning mode, the touchscreen does not respond to touches. However, it responds to touch-hold in the same manner as it would right-click-on-hold. While the touch is being held, an expanding reverse-video circle around the touch point informs the user that the touch is recognized. If the touch is held for the programmable hold event time, the indicator disappears and cleaning mode ends. To prevent inadvertent activation at this point, the touchscreen continues to ignore touch events until after the next untouch.
All parameters of the unlocking means are controlled by the touch hold parameters. These can be set by registry values for each touchscreen.
"HoldTick" is hold timer resolution. e.g. 0x64 = 100 msec per tick.
"HoldJiggle" is the hold perimeter in absolute touch units. Movement inside this is ignored.
"TicksToEvent" is the tick count to unlock.
"TicksToShow" is the tick count before showing hold visual feedback. 0 = immediate feedback. >= TicksToEvent = no feedback.
"HoldShowStep" is hold visual feedback step size in video pixels.
These parameters can also be set via the IOCTL_ELO_HOLD_PARMS command directly or through the EloApi::HoldParms send function.
A touchscreen can be put into cleaning mode by calling the EloApi function setCleaningMode.
EloApi::setCleaningMode( 1, _T("Elo1:"));
There is no complementary function to stop cleaning mode, as the user's touch-hold is expected to do this. There is no function to put all touchscreens into cleaning mode.
RIGHT-CLICK-ON-HOLD GLOBAL CONTROL
When right-click-on-hold (RCOH) is enabled for a touchscreen, touch-hold causes an expanding reverse-video circle to appear around the touch point and, after a delay, a right-click mouse event to be generated. Properly configuring "TicksToShow" and "TicksToEvent" for the type of application prevents annoying false triggering of these events on normal touches. However, if the user interface contains controls that are normally pressed and held, such as scroll buttons, the RCOH mechanism is activated. The driver cannot avoid this because only the application knows when such a control is being touched.
An application can detect when a control that should not experience RCOH is being touched and could disable the touchscreen's RCOH mechanism until the control is untouched. The application could use the IOCTL_ELO_ON_HOLD command or EloApi:: setOnHold function for this purpose but there are several problems with this approach. One is that the application would have to record the existing configuration in order to restore it. Another is that it is difficult to cover all possible code paths that might interfere with recognizing that RCOH should be restored, leaving it inappropriately disabled. Further, if the system contains multiple touchscreens, RCOH would have to be disabled and reenabled for each one individually.
The EloApi::disableHold, disableHoldTemp, and allowHold functions afford an easier and more reliable means of temporarily disabling RCOH for all touchscreens.
EloApi::disableHold( 1, _T("Elo1:") );
EloApi::disableHoldTemp( 1, _T("Elo1:") );
EloApi::allowHold( 1, _T("Elo1:") );
These functions require a device to be identified in order to access the driver but the effect occurs on all touchscreens attached to the driver (USB and serial are independent). After disableHold executes, RCOH is disabled until allowHold executes. With disableHoldTemp, RCOH is disabled until the next untouch. An application calls disableHold to temporarily disable RCOH for a group of controls or an entire dialog. It calls disableHoldTemp to disable RCOH when a particular control is touched. DisableHold and DisableHoldTemp abort the hold process that has already started so there is no race between the application and the driver.
For mixed serial and USB touchscreen systems, the EloApi.dll function emitCmd should be used to affect all devices. Even if the system contains only serial or only USB touchscreens, this command is a bit simpler to use and is no less efficient than sending the commands to a specific one. EloApi.h defines inline function wrappers over emitCmd for global hold operations. These are distinguished from their sendCmd counterparts by taking no arguments, whereas the sendCmd wrappers require at least a device number.
inline ULONG disableHold( void )
{ return emitCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL ); }
inline ULONG disableHoldTemp( void )
{ return emitCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_TEMP ); }
inline ULONG allowHold( void )
{ return emitCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_EVENT ); }
The disableHold function disables RCOH for all applications, which may be inappropriate unless the application occupies the entire display. Typically, RCOH should at least continue to function on the desktop. To achieve this, disableHold and allowHold can be called in response to WM_ACTIVATE messages.
if( LOWORD( wParam ) == WA_INACTIVE )
EloApi::allowHold();
else
EloApi::disableHold();
EloTalk's touch dialog illustrates the use of disableHoldTemp. To see the effect, if RCOH is not enabled, touch the Right Click on Hold enable checkbox. Touch a blank area of the dialog to see the RCOH response. Then touch and hold the Auto Untouch Tick to Event increase (>) button. The value steadily increases but there is no RCOH response. Touch-hold just outside the button perimeter evokes RCOH. The button is a subclassed pushbutton. It sends a user-defined message to the dialog function when it receives WM_LBUTTONDOWN (i.e. touch). The dialog function responds by calling EloApi::disableHoldTemp. No further action is required by either the button or dialog. When the user untouches, the driver automatically reverts to the allow hold state.
The touchscreen drivers can produce various sounds associated with touch, untouch, drag, and right click (RCOH) by calling functions in the eloBeep driver or the OS function PlaySound. EloBeep works only in X86 systems that provide a PC beep emulator. PlaySound requires a sound card or sound card emulator.
All USB touchscreens have the same sound configuration as all serial touchscreens. The touchscreen drivers take their sound parameters from registry values under the key [HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\TOUCH\SOUND]. The API affords no direct means of changing these parameters. However, it affords turning the sound off and on and commanding the driver to reload its sound parameters from the registry, thereby supporting indirect parameter change.
The API's sound control command is IOCTL_ELO_SOUND. The single argument is the enum TOUCH_SOUND_OFF, TOUCH_SOUND_ON, TOUCH_SOUND_UPDATE, IS_TOUCH_SOUND_ON. Usually, EloApi::setSound is invoked to send this command to the driver. As with the global RCOH control, sending this to any touchscreen changes all devices (USB and serial are independent).
EloApi::setSound( TOUCH_SOUND_OFF, 1, _T("Elo1:") );
To change sound parameters, an application can modify one or more registry values ("DownBeep", "UpBeep", "RightBeep", "DownWav", "UpWav", "RightWav", "DragTone", "DragStepPost") and then call setSound to update the driver.
EloApi::setSound( TOUCH_SOUND_UPDATE, 1, _T("Elo1:") );
Most API functions operate on only one touch device at a time, RCOH global control being a notable exception. If the CE system contains multiple touchscreens, an operation can be applied to each one by calling the EloApi forEach function. The one argument to forEach is the address of a callback function, which will subsequently be called for every touchscreen device unless the callback returns false.
The control panel applet cleaning function illustrates the use of forEach. There are three stages to this operation: all touchscreens are locked for cleaning; all touchscreens are periodically probed to see if any one has been unlocked by touch-hold; when one becomes unlocked, the others are unlocked for the user. A different callback function is used at each stage.
// ----------------------------------------------------------------------------
// Function: cleanCallback
// Purpose: ForEach callback to set cleaning mode. Each iteration puts one
// touch device into cleaning mode.
// Returns: bool true to continue.
// Arguments: UCHAR devNum, TCHAR *name identify device for API.
// ............................................................................
bool cleanCallback( UCHAR devNum, TCHAR *name )
{
EloApi::setCleaningMode( devNum, name );
return true;
}
// ----------------------------------------------------------------------------
// Function: checkCleanCallback
// Purpose: ForEach callback to determine whether any touchscreen has been
// taken out of cleaning mode (by touch-hold).
// Returns: bool true if this unit is still in cleaning mode; false to stop
// iterating because this one is no longer cleaning.
// Arguments: UCHAR devNum, TCHAR *name identify device for API.
// ............................................................................
bool checkCleanCallback( UCHAR devNum, TCHAR *name )
{
USHORT onTouch = EloApi::getOnTouch( devNum, name );
if(( onTouch & ON_TOUCH_CLEANING ) == 0 )
cleaning = false;
return cleaning; // If this one is unlocked, return false to abort forEach.
}
// ----------------------------------------------------------------------------
// Function: endCleanCallback
// Purpose: ForEach callback to undo cleaning mode.
// Returns: bool true to continue iterating through all touchscreens.
// Arguments: UCHAR devNum, TCHAR *name identify device for API.
// ............................................................................
bool endCleanCallback( UCHAR devNum, TCHAR *name )
{
USHORT onTouch = EloApi::getOnTouch( devNum, name );
EloApi::setOnTouch( onTouch & ~( ON_TOUCH_CLEANING + ON_TOUCH_IGNORENEXT ),
devNum, name );
return true;
}
The applet dialog responds to the clean request by locking all touchscreens and starting a timer to invoke the period status check.
EloApi::forEach( cleanCallback );
cleaning = true;
SetTimer( hDlg, 1, 250, 0 );
At each timer message, the dialog calls forEach, passing a pointer to checkCleanCallback, which probes each device. All devices are probed unless one of them has been unlocked, in which case checkCleanCallback aborts forEach by returning false. It also clears the cleaning flag to let the dialog know that the second phase is done. When the dialog sees this, it kills the timer and then invokes forEach one more to unlock all touchscreens.
EloApi::forEach( checkCleanCallback );
if( !cleaning )
{
KillTimer( hDlg, 1 );
EloApi::forEach( endCleanCallback );
}
As explained in IOCTL_ELO_CFGITEM Command, the operating characteristics of each Elo device in a system can be uniquely set by setting data in its own registry key. Not all of values under the key can be accessed through the IOCTL_ELO_CFGITEM command. The most efficient way for an application to read or write more than one of these other values is to get the key name from the driver using the getDevRegKeyName function and then use standard Win32 registry functions for reading and writing. To read or write single items or to conveniently (but less efficiently) access multiple items, EloApi provides getDevRegDw and setDevRegDw functions to read or write one DWORD value under the device's registry key. These functions can also be used to access the values that can be accessed through IOCTL_ELO_CFGITEM but this is discouraged, as it bypasses potentially important driver involvement.
Examples
DWORD edgeOffset = EloApi::getDevRegDw( 40, ELOREG_EdgeOffset, 1 );
EloApi::setDevRegDw( 40, ELOREG_EdgeOffset, 1 );
All API communication between applications and touchscreen drivers occurs through the OS function DeviceIoControl. The basic process is as follows:
All commands are performed synchronously; the application thread that calls DeviceIoControl is suspended until the driver finishes processing the command.
An application can communicate with the driver by performing all of the application-level steps of this process, but it is easier to let the EloApi library (eloApi.dll) perform most of the operations. Given just the Elo device number and optional name, it opens the interface, calls DeviceIoControl, and closes the interface, with appropriate error detection, recovery, and reporting. In most situations, an application has nothing to gain from taking on this responsibility. However, the library sacrifices some performance for reliability. For example, an application willing and able to open the device interface once instead of opening and closing it at every command could improve performance while reducing CPU bandwidth.
The API comprises two parts, definitions shared by applications and drivers and application-level functions to simplify the task of communicating with drivers. The former are required. The latter are convenient but not essential.
The shared files are:
The application-only files are:
To communicate directly with the driver an application must be built with eloCodes.h and eloIoctl.h. It requires eloRegNames.h only if it invokes the IOCTL_ELO_CFGITEM and a few obscure functions. It requires smartSetCmd.h only to talk directly to a touchscreen controller.
EloIoctl.h and eloApi.h contain the following code:
#ifdef EloApi_Static
#define T_EloApi
#else
#ifdef EloApi_Export
#define T_EloApi __declspec(dllexport)
#else
#define T_EloApi __declspec(dllimport)
#endif
#endif
By not defining EloApi_Static or EloApi_Export, an application project automatically sees EloApi function prototypes as dllimport. Since eloIoctl.h doesn't define EloApi functions it should not need to define dllimport. However, because structures declared in eloIoctl.h are included in EloApi functions, the compiler otherwise issues confusing warnings.
The EloApi contains three basic types of IOCTL commands: simple, configuration item, and complex. All types pass an IOCTL code and one argument to the driver. For simple commands, the argument is an unsigned long (ULONG). For all other commands, the argument is a structure defined in eloIoctl.h. A few commands can only read or only write to the driver and a few can write and read in the same invocation. Most commands write and read but can only do one or the other in one invocation, the direction being determined by an argument in the command structure. In no case does the IOCTL code or structure imply direction unless the command only writes or only reads to the driver. For example, IOCTL_ELO_GETLINKTYPE indicates that the command reads from the driver, whereas the bi-directional command IOCTL_ELO_CFGITEM gives no indication of direction.
Except for the simple commands, the payload (argument structure) passed between the application and driver follows a standard pattern,
class T_EloApi IocClass : public IocHdr
{
data and inline function members of IocClassName
where IocClass is an IOCTL command-specific class, for example IocCfgItem for the IOCTL_ELO_CFGITEM command.
IocHdr comprises only a status return member and the inline constructor that initializes it.
class T_EloApi IocHdr
{
ELO_ERR mEloErr;
IocHdr( void ) { mEloErr = EloErrSuccess; }
};
If the driver encounters a general error, it will assign mEloErr one of the ELO_ERR values defined in eloCodes.h, such as EloErrInvalidCommand. Some of the IocClasses contain members for reporting errors that are more specific.
The IocClass always constitutes a complete container for passing data between applications and the drivers. In the one case where data size can vary, IocEdgeCal for IOCTL_ELO_EDGECAL, the structure is extensible.
Most of the IocClasses contain an mOp member, which tells the operation that the application wants the driver to perform. For many, this simply tells whether to write to the driver or read from it, for which the enum IocGet, IocSet supplies the mOp data range.
enum { IocGet, IocSet };
For each IocClass defined in eloIoctl.h, eloApi.h defines an application interface class. API classes afford a uniform and simplified means for applications to communicate with the drivers. Except for the "simple" commands, all API command classes follow a standard pattern,
class T_EloApi CmdApiClass : public EloDevId
{
IocClass mIoc;
GenConEloDevId( CmdApiClass );
member functions (prototypes and inline)
IocClass is an IOCTL argument class defined in eloIoctl.h. All API classes are derived from EloDevId. GenConEloDevId is a macro that defines the constructor for CmdApiClass. The constructor serves only as a means to pass arguments to the EloDevId constructor. EloDevId comprises the device number and name, such as "Elo1:", the link type (unknown, serial, or USB), and function declarations.
{
TCHAR mDevName[ MAX_ELO_NAME_LEN + 1 ];
UCHAR mDevNum;
DevLink mLink;
EloDevId( UCHAR devNum = 0, TCHAR *name = 0 );
void makeNameFromNum( void );
void setDevice( UCHAR devNum, TCHAR *name );
};
The EloDevId constructor (and, therefore, the CmdApiClass constructor) serves only to identify the device by number and/or name. Instantiating a CmdApiClass object does not produce any side-effects other than memory allocation for the object. Typically, a CmdApiClass is instantiated with the device number and name, although it can be created nameless and subsequently identified by calling its member function setDevice. More often, setDevice is called to select a different device without having to create a new object.
Many IOCTL commands have only one option, to read or write. The declaration (in eloApi.h) of API classes for invoking these is simplified by the macro, GenSetGet, which generates a standard setGet prototype and inline set and get function definitions for the command types that fit this exact pattern. For example see CmdCfgItem, the API class for invoking IOCTL_ELO_CFGITEM.
#define GenSetGet \
bool setGet( void ); \
bool set( void ) { mIoc.mOp = IocSet; return setGet(); } \
bool get( void ) { mIoc.mOp = IocGet; return setGet(); }
Each CmdApiClass is essentially a shell wrapped around an IOCTL command object (mIoc). Instantiating a CmdApiClass creates the command payload and the means to send it to the driver. Most CmdApiClass objects are small and can be instantiated as automatics. The application assigns values to the embedded IocClass and then invokes a member function of the CmdApiClass to communicate with the driver. All of these functions perform some variation of the process flow described above. When data is read from the driver, the results remain available to the application as long as the CmdApiClass remains in scope.
By shaping commands with arguments, relatively few actual functions produce a wide range of operations, but even the simplest require the extra step of initializing arguments. EloApi.h defines inline functions to simplify common operations. For example, all of the commands that provide simple symmetrical read and write define a setGet class function, which simply sends the IocClass to the driver. The application could assign IocSet or IocGet to the IocClass object's mIoc.mOp and call the setGet function but eloApi can do this for the application by set and get inline functions. Thus,
EloApi::CmdCal3Dat cmd( 1, _T("Elo1:"));
cmd.mIoc.mOp = IocGet;
cmd.setGet();
and
EloApi::CmdCal3Dat cmd( 1, _T("Elo1:"));
cmd.get();
are equivalent.
Operations that read or write a single value to the driver are especially encumbered by having to create a CmdApiClass and initialize arguments. For most of these, eloApi.dll contains functions that instantiate the CmdApiClass, while eloApi.h defines related inline functions to initialize the arguments. For example, eloApi.h defines setCleaningMode as:
inline ULONG setCleaningMode( UCHAR devNum, TCHAR *name = 0 )
{ return setOnTouch( ON_TOUCH_SYSMOUSE | ON_TOUCH_CLEANING, devNum, name ); }
But setOnTouch is itself an inline function that invokes the sendCmd function which actually exists in eloApi.dll.
inline USHORT setOnTouch( USHORT onTouch, UCHAR devNum, TCHAR *name = 0 )
{ return (USHORT)sendCmd( IOCTL_ELO_ON_TOUCH, onTouch + ( ON_TOUCH_SET << 16 ),
devNum, name ); }
ULONG T_EloApi sendCmd( DWORD ioctl, ULONG arg, UCHAR devNum, TCHAR *name = 0 );
"Simple" commands exchange a single unsigned long between the application and the driver. Except for the IOCTL code and mEloErr member of the IocHdr base class, there is no other information source. To read or write the full range of ULONG values to the driver, the IOCTL code would have to define a read or write or both (write the given value and return something else, such as the previous value). However, many of the commands split the ULONG into command and data portions. Simple commands do not use an IocClass.
To effect simple commands, EloApi.h defines the class Command, derived from EloDevId and, therefore, able to open the device interface and send the driver a command. Command affords only one real function, send, but it contains many inline functions to invoke send with various arguments. To use Command directly, an application creates a Command object and invokes its send, for example (see [Right-Click-On-Hold Global Control]).
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.send( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_TEMP );
Because Command defines an inline onHold function, this could also be written
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.onHold( ON_HOLD_GLOBAL+ON_HOLD_TEMP );
The inline function appears to afford little advantage until using a smart editor to write a program. After typing "cmd." the editor shows a list of functions, including onHold. After typing or selecting "cmd.onHold" the editor shows additional relevant information, which it would not otherwise provide.
EloApi.dll simplifies sending simple commands by defining the sendCmd function, which creates an automatic Command object, sends the given IOCTL code and ULONG value and returns the ULONG returned by the driver.
ULONG T_EloApi sendCmd( DWORD ioctl, ULONG arg, UCHAR devNum, TCHAR *name = 0 );
EloApi.h defines inline functions for sendCmd similar to those defined as members of the Command class. For example, the previous example can be replaced by
EloApi::disableHoldTemp( 1, _T("Elo1:"));
Some commands should only be sent to a specific touchscreen while others can or should be sent to all touchscreens. Certain commands, such as for global hold configuration, affect all touchscreens handled by a particular driver. If a system contains both USB and serial touchscreens, sending one of these commands to a serial touchscreen will not affect the USB devices and vice versa. One way to ensure that all devices are affected is to send the command to all of them (for example by using EloApi::forEach) but this is excessive. The command only needs to be sent to one of each type. For this purpose, EloApi.dll defines the emitCmd function.
ULONG T_EloApi emitCmd( DWORD ioctl, ULONG arg );
This function is similar to sendCmd but sends the command to the first serial device if there is one and then to the first USB device if there is one. It returns the return value from the last command invocation, i.e. from the USB device if there is one or from the serial device. For example:
emitCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL );
IOCTL code: IOCTL_ELO_ROTATE
EloApi functions: rotate, rotateAll
See Typically Useful Api Functions [Rotate]
This reorients the touchscreen to 90-, 180-, or 270-degree orientation. By default, unless changed by the registry value "Orient" ORIENT_NO_VIDEO flag, the driver sets matching video orientation. The application can prevent this by setting the command's ROTATE_NO_VIDEO flag. However, if the application does this and doesn't reorient the display itself (usually by calling the OS function ChangeDisplaySettingsEx) touch will be severely out of calibration. Rotating the touchscreen remaps all of its bulk and edge calibration parameters. The command argument is assigned an enumerated orientation plus optional flags.
enum rotateCmd { // Argument to IOCTL_ELO_ROTATE
ROTATE_0,
ROTATE_90,
ROTATE_180,
ROTATE_270,
// The following flags override "Orient" flags ORIENT_WRITEREG, ORIENT_NO_VIDEO
ROTATE_WRITEREG = 0x200, // Write registry "Orient"
ROTATE_NO_VIDEO = 0x400, // Don't rotate video display
ROTATE_NO_WRITEREG = 0x800, // Don't write registry "Orient"
ROTATE_VIDEO = 0x1000, // Rotate video display
ROTATE_FORCE = 0x2000, // Process even if orientation is not changed.
};
inline ULONG rotate( ULONG rotateCmd, UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_ROTATE, rotateCmd, devNum, name ); }
int T_EloApi rotateAll( USHORT rotateCmd );
EXAMPLES
The inline function rotate calls sendCmd in eloApi.dll:
EloApi::rotate( ROTATE_270, 3, _T("Elo3:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_ROTATE, ROTATE_270 + ROTATE_VIDEO, 3, _T("Elo3:"));
Inline Command function rotate calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 3, _T("Elo3:"));
cmd.rotate( ROTATE_270 + ROTATE_VIDEO );
cmd.send( IOCTL_ELO_ROTATE, ROTATE_270 + ROTATE_VIDEO + ROTATE_WRITEREG );
IOCTL code: IOCTL_ELO_ON_TOUCH
EloApi functions: setOnTouch, getOnTouch, setCleaningMode
See Typically Useful Api Functions [Touch Lockout (Cleaning Mode)]
This tells the driver how to report a touch event. Normally, the coordinates of a touch are adjusted according to various schemes including edge acceleration and linearity correction and then translated to mouse system coordinates and then the event is reported to the OS as a mouse event. However, the event may be reported though the API for the purpose of calibration or ignored entirely or filtered so that only certain type of events are reported. One-half of the command argument (ULONG) is a bitmap composed from the OnTouch flags and the other contains a get/set argument.
enum OnTouch { // Bitmap for IOCTL_ELO_ON_TOUCH
ON_TOUCH_NOTHING = 0x0000,
ON_TOUCH_SYSMOUSE = 0x0001, // Fully adjusted mouse event to system
ON_TOUCH_APIMOUSE = 0x0002, // Fully adjusted mouse event through API
ON_TOUCH_APIADJ = 0x0004, // Touchscreen domain (not translated) with adjustments.
ON_TOUCH_APITRANS = 0x0008, // Translated to mouse but not adjusted
// (acceleration and linearity)
ON_TOUCH_APIRAW = 0x0010, // Raw touchscreen coordinates
ON_TOUCH_CLEANING = 0x0020, // No response until wakeup on hold.
ON_TOUCH_IGNORENEXT = 0x0040, // Ignore all touch stream events up to and
// including the next new touch or untouch. Auto-clear at event.
// Event filters. These apply only to API. All events are passed to system if ON_TOUCH_SYSMOUSE
ON_TOUCH_DOWN = 0x2000,
ON_TOUCH_STREAM = 0x4000,
ON_TOUCH_UP = 0x8000,
// EloTch.mOnTouch is USHORT LOWORD of the ULONG API argument. HIWORD is used for
// API commands.
};
enum { ON_TOUCH_SET, ON_TOUCH_GET }; // IOCTL_ELO_ON_TOUCH HIWORD( ULONG ) commands.
Most applications would only be interested in the cleaning mode option.
inline USHORT setOnTouch( USHORT onTouch, UCHAR devNum, TCHAR *name = 0 )
{ return (USHORT)sendCmd( IOCTL_ELO_ON_TOUCH, onTouch + ( ON_TOUCH_SET << 16 ),
devNum, name ); }
inline ULONG setCleaningMode( UCHAR devNum, TCHAR *name = 0 )
{ return setOnTouch( ON_TOUCH_SYSMOUSE | ON_TOUCH_CLEANING, devNum, name ); }
inline USHORT getOnTouch( UCHAR devNum, TCHAR *name = 0 )
{ return (USHORT)sendCmd( IOCTL_ELO_ON_TOUCH, ON_TOUCH_GET << 16, devNum, name ); }
EXAMPLES
The inline function setCleaningMode invokes the inline function setOnTouch, which calls sendCmd in eloApi.dll:
EloApi::setCleaningMode( 2, _T("Elo2:"));
The inline function setOnTouch calls sendCmd:
EloApi::setOnTouch( ON_TOUCH_SYSMOUSE + ON_TOUCH_CLEANING + ( ON_TOUCH_SET << 16 ), 2, _T("Elo2:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_ON_TOUCH, ON_TOUCH_SYSMOUSE + ON_TOUCH_CLEANING + ( ON_TOUCH_SET << 16 ), 2, _T("Elo2:"));
Inline Command function setOnTouch calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 2, _T("Elo2:"));
cmd.setOnTouch( ON_TOUCH_SYSMOUSE + ON_TOUCH_CLEANING + ( ON_TOUCH_SET << 16 ));
cmd.send( IOCTL_ELO_ON_TOUCH, ON_TOUCH_SYSMOUSE + ON_TOUCH_CLEANING + ( ON_TOUCH_SET << 16 ));
IOCTL code: IOCTL_ELO_ON_HOLD
EloApi functions: disableHold, disableHoldTemp, allowHold
See Typically Useful Api Functions [Right-Click-On-Hold Global Control]
This defines what the driver will do in response to touch hold. It does not define parameters, such as the time required for hold to be recognized. Those are defined by the hold parameters (IOCTL_ELO_HOLD_PARMS) command. The command argument is a bitmap composed from the following flags:
enum OnHold { // Bitmap for IOCTL_ELO_ON_HOLD
ON_HOLD_EVENT = 1,
ON_HOLD_NO_EVENT = 2,
ON_HOLD_SHOW = 4,
ON_HOLD_NO_SHOW = 8,
ON_HOLD_AUTOUNTOUCH = 0x10,
ON_HOLD_NO_AUTOUNTOUCH = 0x20,
ON_HOLD_GLOBAL = 0x40,
ON_HOLD_TEMP = 0x80,
};
Each of the three onHold features-- event (right-click-on-hold), show, and untouch-- is turned off/on or no change according to two flags. The current onHold condition (after any changes due to this command) is returned by set flags, i.e. ON_HOLD_EVENT, ON_HOLD_SHOW, and ON_HOLD_AUTOUNTOUCH. To just read the current state, pass an argument of 0.
ON_HOLD_GLOBAL disables hold event for all touchscreens without changing each one's individual setting. ON_HOLD_GLOBAL+ON_HOLD_EVENT removes this. ON_HOLD_GLOBAL+ON_HOLD_TEMP disables hold event for all until the next untouch (or ON_HOLD_GLOBAL+ON_HOLD_EVENT). Although an individual device must be identified in order to access the driver, all devices sharing that driver are affected by ON_HOLD_GLOBAL commands.
inline ULONG setOnHold( ULONG onHold, UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_ON_HOLD, onHold, devNum, name ); }
inline ULONG disableHold( UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL, devNum, name ); }
inline ULONG disableHoldTemp( UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_TEMP, devNum, name ); }
inline ULONG allowHold( UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_EVENT, devNum, name ); }
EXAMPLES
The inline functions disableHold, disableHoldTemp, and allowHold call sendCmd in eloApi.dll. Note that allowHold only removes the global block. It does not enable hold, which is determined individually for each device.
EloApi::disableHold( 1, _T("Elo1:"));
EloApi::disableHoldTemp( 1, _T("Elo1:"));
EloApi::allowHold( 1, _T("Elo1:"));
The equivalent direct calls to sendCmd are:
EloApi::sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL, 1, _T("Elo1:")); /* disable */
EloApi::sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_TEMP, 1, _T("Elo1:")); /* disable temporarily */
EloApi::sendCmd( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_EVENT, 1, _T("Elo1:")); /* allow */
The equivalent (functionally) inline Command function calls are:
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.onHold( ON_HOLD_GLOBAL ); /* disable */
cmd.onHold( ON_HOLD_GLOBAL+ON_HOLD_TEMP ); /* disable temporarily */
cmd.onHold( ON_HOLD_GLOBAL+ON_HOLD_EVENT ); /* allow */
The equivalent direct calls to Command.send are:
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.send( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL );
cmd.send( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_TEMP );
cmd.send( IOCTL_ELO_ON_HOLD, ON_HOLD_GLOBAL+ON_HOLD_EVENT );
IOCTL code: IOCTL_ELO_SOUND
EloApi functions: setSound
See Typically Useful Api Functions [Touch Sound]
This command is used to turn the sound off or on or to update its working sound parameters from new values written directly into the registry by an application. It can also ask whether the touch sound is currently (enabled).
enum TouchSound { // For IOCTL_ELO_SOUND
TOUCH_SOUND_OFF,
TOUCH_SOUND_ON,
TOUCH_SOUND_UPDATE,
IS_TOUCH_SOUND_ON,
};
inline ULONG setSound( ULONG touchSound, UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_SOUND, touchSound, devNum, name ); }
EXAMPLES
All of these can also query status by passing IS_TOUCH_SOUND_ON.
The inline function rotate calls sendCmd in eloApi.dll:
EloApi::setSound( TOUCH_SOUND_OFF, 1, _T("Elo1:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_SOUND, TOUCH_SOUND_OFF, 1, _T("Elo1:"));
Inline Command function sound calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.sound( TOUCH_SOUND_OFF );
cmd.send( IOCTL_ELO_SOUND, TOUCH_SOUND_OFF );
IOCTL code: IOCTL_ELO_GETLINKTYPE
EloApi functions: getLinkType
Apart from a configuration program, such as EloTalk or a control panel, most applications should not care whether the touchscreen link is serial or USB. However, an application might adjust its behavior according to the link, knowing that USB is considerably faster than serial. The value returned is one of three defined by enum DevLink.
enum DevLink { LINK_UNKNOWN, LINK_SERIAL, LINK_USB }; // IOCTL_ELO_GETLINKTYPE
inline USHORT getLinkType( UCHAR devNum, TCHAR *name = 0 )
{ return (USHORT)sendCmd( IOCTL_ELO_GETLINKTYPE, 0, devNum, name ); }
EXAMPLES
The inline function getLinkType calls sendCmd in eloApi.dll:
EloApi::getLinkType( 1, _T("Elo1:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_GETLINKTYPE, 0, 1, _T("Elo1:")); /* dummy DWORD arg */
Inline Command function getLinkType calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.getLinkType();
cmd.send( IOCTL_ELO_GETLINKTYPE, 0 ); /* dummy DWORD arg */
IOCTL code: IOCTL_ELO_GETCONTROLLER
EloApi functions: getController
Retrieve the type of controller in the touchscreen for diagnostic purposes. The command argument GETCONTROLLER_NOFRESH gets the information from the driver. GETCONTROLLER_FRESH tells the driver to send a SmartSet query to the controller to get this information, simultaneously refreshing its own record. For a USB device, there should be no difference but there may be a difference for a serial device that has been removed or replaced. The return value is a USHORT whose LSByte tells the controller's ID, which is the same as its USB-HID PID, for example 0x20 is the 2701 and 0x50 is the 2216. The next more significant byte tells the status of the controller. If bit 0 is set, the controller has responded and the ID is valid. If bit 1 is set, the controller supports precalibration.
enum { GETCONTROLLER_NOFRESH, GETCONTROLLER_FRESH }; // IOCTL_ELO_GETCONTROLLER
enum { CONTROLLER_OK = 0x100, CONTROLLER_NV = 0x200 }; // Controller status flags.
inline USHORT getController( ULONG fresh, UCHAR devNum, TCHAR *name = 0 )
{ return (USHORT)sendCmd( IOCTL_ELO_GETCONTROLLER, fresh, devNum, name ); }
EXAMPLES
The inline function getController calls sendCmd in eloApi.dll:
EloApi::getController( GETCONTROLLER_FRESH, 1, _T("Elo1:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_GETCONTROLLER, GETCONTROLLER_FRESH, 1, _T("Elo1:"));
Inline Command function getController calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 1, _T("Elo1:"));
cmd.getController( GETCONTROLLER_FRESH );
cmd.send(IOCTL_ELO_GETCONTROLLER, GETCONTROLLER_FRESH );
IOCTL code: IOCTL_ELO_SAVECAL
EloApi functions: saveCal
This is only used by a calibration program, such as elova. Note that three-point calibration parameters can be written to the registry and/or the touchscreen (if its controller is one of the types with accessible nonvolatile memory) but edge calibration parameters can only be written to the registry. See EloRegIdxCalStore.
enum SaveCalTo { // Bitmap for IOCTL_ELO_SAVECAL
SAVECAL_DEFAULT = 1, // Driver read CalStore to determine registry and/or controller.
SAVECAL_REG = 2, // Write to registry.
SAVECAL_CONTROLLER = 4, // Write to controller.
SAVECAL_EDGES = 8, // Write edge calibration parameters to registry (no controller option).
};
inline ULONG saveCal( ULONG saveCalTo, UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_SAVECAL, saveCalTo, devNum, name ); }
EXAMPLES
The inline function rotate calls sendCmd in eloApi.dll:
EloApi::saveCal( SAVECAL_REG + SAVECAL_CONTROLLER, 3, _T("Elo3:"));
The eloApi.dll function sendCmd can be called directly:
EloApi::sendCmd( IOCTL_ELO_SAVECAL, SAVECAL_REG + SAVECAL_CONTROLLER, 3, _T("Elo3:"));
Inline Command function saveCal calls Command.send in eloApi.dll or Command.send can be called directly:
EloApi::Command cmd( 3, _T("Elo3:"));
cmd.saveCal( SAVECAL_REG + SAVECAL_CONTROLLER );
cmd.send( IOCTL_ELO_SAVECAL, SAVECAL_REG + SAVECAL_CONTROLLER );
IOCTL code: IOCTL_ELO_APIDEVID
EloApi functions: setApiDevId, writeApiDevId, readApiDevId, resetApiDevId
This defines a private identification means, independent of device number and name, between an application and the device used by the driver when responding to certain API commands, notably IOCTL_ELO_GETPOINT. Typically, this is used when one or more touchscreens is disabled, leaving gaps in the active device number range, and the remaining active ones are synchronized to a fully populated array. Elova, the calibration program, uses this.
inline USHORT setApiDevId( ULONG devIdCmd, UCHAR devNum, TCHAR *name = 0 )
{ return LOWORD( sendCmd( IOCTL_ELO_APIDEVID, devIdCmd, devNum, name )); }
inline USHORT writeApiDevId( USHORT id, UCHAR devNum, TCHAR *name = 0 )
{ return LOWORD( sendCmd( IOCTL_ELO_APIDEVID, (DEVIDCMD_WR << 16) + id, devNum, name )); }
inline USHORT readApiDevId( UCHAR devNum, TCHAR *name = 0 )
{ return LOWORD( sendCmd( IOCTL_ELO_APIDEVID, DEVIDCMD_RD << 16, devNum, name )); }
inline USHORT resetApiDevId( UCHAR devNum, TCHAR *name = 0 )
{ return LOWORD( sendCmd( IOCTL_ELO_APIDEVID, DEVIDCMD_RESET << 16, devNum, name )); }
IOCTL code: IOCTL_ELO_DEBUGVAL
EloApi functions: debugVal
This exchanges a single ULONG value with the driver for debugging and testing. The driver must be modified for this facility to serve any useful purpose. This is intended for Elo internal use but might also be used to help diagnose a customer problem that Elo cannot recreate.
inline ULONG debugVal( ULONG toDvr, UCHAR devNum, TCHAR *name = 0 )
{ return sendCmd( IOCTL_ELO_DEBUGVAL, toDvr, devNum, name ); }
Much of the operation of Elo drivers is configurable through DWORD registry values. These can be assigned data in the source reg files, such as eloUsb.reg and eloSer.reg, used to build the OS image. They can also be modified dynamically by sending the IOCTL_ELO_CFGITEM to the driver. Configuration item commands comprise this one command, parameterized by an enumerated ordinal of DWORD registry values. The ordinals are defined by the EloRegItemId enum in eloRegNames.h. EloRegItemId defines ordinals for nearly all registry values used by Elo. Only a subset of these can be used with IOCTL_ELO_CFGITEM. An application may access the others directly in the registry using the EloApi function getDevRegKeyName and Win32 functions or the EloApi functions getDevRegDw and setDevRegDw.
Each invocation of the IOCTL_ELO_CFGITEM command reads or writes one registry value. This is not the same action as reading or writing the registry directly. When reading, the driver returns the data that the device is currently using. This data may not match that of the registry value, which is only used to initialize the driver. When writing, the driver guards against bad data, substituting limits for over range data; updates the driver's working data, including other dependent data; and performs required side-effect operations. For example, when the driver processes IOCTL_ELO_CFGITEM to change its priority, in addition to common actions, it calls CeSetThreadPriority to effect the change.
The IOCTL argument to IOCTL_ELO_CFGITEM is the class IocCfgItem.
class T_EloApi IocCfgItem : public IocHdr
{
USHORT mOp; // IocSet/Get
int mId; // registry ordinal
DWORD mDat;
};
If mId is outside of the range of EloRegItemId that supports this command, the driver assigns EloErrInvalidCommand to mEloErr (member of base class IocHdr) and immediately returns. If mOp is IocGet the driver returns the current working data corresponding to the registry value identified by mId. If mOp is IocSet the driver validates the mDat data according to the requirements of the mId item, substituting legal data where appropriate; stores the data in the working values for itself or this device; writes the data to the registry under the proper key; and takes whatever additional actions are required for the change to take effect. If the driver changes the data, the mDat member of the IocCfgItem will be changed upon return.
EloApi.h defines a standard API class CmdCfgItem for sending an IOCTL_ELO_CFGITEM command to the driver.
class T_EloApi CmdCfgItem : public
EloDevId{
IocCfgItem
mIoc;GenConEloDevId( CmdCfgItem );
GenSetGet
};
EloApi.dll contains two functions, setCfgItem and getCfgItem, which create a local CmdCfgItem using device number and name arguments and then send the IOCTL_ELO_CFGITEM command with the given item and dat arguments to the driver.
void T_EloApi setCfgItem( int item, DWORD dat, UCHAR devNum, TCHAR *name = 0 );
DWORD T_EloApi getCfgItem( int item, UCHAR devNum, TCHAR *name = 0 );
EXAMPLES
EloApi::CmdCfgItem cmd( 1, _T("Elo1:"));
cmd.mIoc.mId = EloRegIdxAntiBounce;
DWORD dat = cmd.get();
cmd.mIoc.mDat = 10;
cmd.set();
DWORD dat = EloApi::getCfgItem( EloRegIdxAntiBounce, 1, _T("Elo1:"));
EloApi::setCfgItem( EloRegIdxAntiBounce, 10, 1, _T("Elo1:"));
#define ELOREG_Priority _T("Priority256")
This sets the normal priority accorded the driver by the OS task scheduler. The OS accepts 0 to 256 with 0 being the highest priority but Elo drivers do not allow priority lower than 3. The default priority is 109 for both serial and USB, as Microsoft recommends for touchscreens. Although this registry value has the same name as the standard for native touchscreens, it is under a different key and is not used by the OS automatically. The driver calls CeSetThreadPriority when it first loads and whenever called to change the priority.
The default priority of 109 works well in most systems. A serial touchscreen may exhibit a slow response under certain circumstances. For example, if right-click-on-hold is enabled and a desktop icon is double-touched, the RCOH feedback indicator may continue operating as the UI shell responds to the event because the shell increases its own priority so much that the untouch message is significantly delayed or lost entirely. In this case, increasing the touchscreen driver's priority may help but it may be more effective to increase the priority of the serial port driver. If this problem cannot be corrected by priority control, it can still be ameliorated using the touchscreen driver's forced untouch mechanism.
#define ELOREG_HighPriority _T("HighPriority256")
This is not currently used.
#define ELOREG_AntiBounce _T("AntiBounce")
An untouch may occur inadvertently in certain situations, most notably when the finger or stylus momentarily loses contact with the screen while dragging. The driver can be configured to ignore such an event. "AntiBounce" is the period of time (in msec) that an untouch must persist without a subsequent touch event for it to be recognized. At the minimum value of 0, no untouch is ignored. At the maximum of 775, any untouch followed by a touch within 775 msec will be ignored. Although this can make dragging easier, it has two undesirable side effects. One is that the response to untouch must be delayed by the AntiBounce time in all circumstances. The other is that a rapid touch-untouch may stick in the touched state.
#define ELOREG_MouseMode _T("MouseMode")
The touchscreen driver translates touch events into apparent mouse events. There are three basic ways that it can do this, click on touch, click on untouch, and emulate mouse. In click on touch mode, touch generates left button down followed immediately by left button up; steam and untouch events are ignored. In click on untouch mode, touch and stream events are ignored; untouch generates left button down followed immediately by left button up. In mouse emulation mode, touch generates left button down; stream events generate mouse move; and untouch generates left button up. The data values for MouseMode are defined by enum.
enum { ELOMM_CLICK_ON_TOUCH, ELOMM_CLICK_ON_UNTOUCH, ELOMM_EMULATE_MOUSE };
#define ELOREG_OnTouch _T("OnTouch")
This uses the IOCTL_ELO_CFGITEM to read the current working value of OnTouch or to set the registry value without affecting the current working mode. This is used in certain test situations. Normally, the IOCTL_ELO_ON_TOUCH command, which causes the working mode to change as well as writing to the registry, should be used.
The drivers can simulate a right mouse button click by the user pressing in one place for a specified length of time. This time and other parameters controlling this feature are established by registry values individually for each touch monitor in the system. This mechanism, with the same parameters, is also used to unlock the touchscreen after being put into cleaning mode.
If communication with the touch monitor fails, for example due to cable disconnect, while in the touched state, the system may never receive an untouch. To prevent such a hung touch, the driver can force an untouch after a specified time without any messages from the touchscreen.
In most cases, the forced untouch timeout can be quite short because the facility does not simply count the time from the initial touch but is reset at every stream touch message. Thus, even a setting that detects cable disconnect within milliseconds allows unlimited touch time. This is especially useful for the 2500U and 3000U controllers, which occasionally lose an untouch message when the system is very busy. For these controllers, an untouch timeout of 300 msec prevents missing untouches without causing false untouches. The 2216 controller will cause false untouches with such a short timeout. Other controllers can operate with this timeout but they only need cable disconnect detection, which could be considerably longer. The circumstances of the application dictate the ideal range of timeouts but good starting points are 300 msec for the 2500 and 3000 controllers and one second for all others.
#define ELOREG_HoldTick _T("HoldTick")
The timing for right-click-on-hold and forced untouch is provided by one timer (per touchscreen device) whose period is defined (in milliseconds) by the registry value "HoldTick". If this value is not defined, all touch timer functions are disabled, regardless of whether related values are defined. The value of HoldTick is normally 0x64, providing 100 msec resolution. Higher resolution (smaller period) may be defined but will consume more CPU bandwidth. Bandwidth consumption can be reduced at the expense of resolution by defining a larger period.
#define ELOREG_HoldJiggle _T("HoldJiggle")
If the user moves the touch point before the TicksToEvent timeout, right-click-on-hold is disabled until an untouch occurs, allowing drag operations to proceed without interference. A small amount of touch position change is not interpreted as deliberate movement. The amount of movement required to indicate a real drag is defined by the "Hold Jiggle" value. This is in normalized (to remove technology differences) touch screen position units, which are of higher resolution than most video screens. A typical value of 0x400 provides a jiggle area of about 10 by 10 pixels on most screens.
#define ELOREG_HoldShowStep _T("HoldShowStep")
"HoldShowStep" is the touch hold visual feedback step size in display pixel units. At each HoldTick after TicksToShow, the feedback circle diameter increases by HoldShowStep pixels.
#define ELOREG_TicksToShow _T("TicksToShow")
"TicksToShow" defines the number of HoldTick counts to trigger visual feedback reminding the user that continued holding will result in a right click. If TicksToShow is 0, feedback begins immediately upon touch. Any value larger than TicksToEvent disables visual feedback and the user will have no indication that a right click is imminent. If bit 15 of the assigned data is 1, the function is disabled with the remainder providing the default value if the function is subsequently enabled.
If visual feedback is enabled, the driver displays a hollow (i.e. only the perimeter) reverse video circle around the touch point. At each count of HoldTick, this expands by the number of pixels specified by "HoldShowStep".
#define ELOREG_TicksToEvent _T("TicksToEvent")
"TicksToEvent" defines the number of HoldTick counts to trigger a right-click. For example, if this is 8 and HoldTick is 0x64, the resulting hold time requirement is 800 msec. If TicksToEvent is 0, the function is disabled. If bit 15 of the assigned data is 1, the function is disabled with the remainder providing the default value if the function is subsequently enabled.
#define ELOREG_TicksToUntouch _T("TicksToUntouch")
" TicksToUntouch " is the number of ticks to count before simulating untouch to protect against lost untouch and cable disconnect. Not defining TicksToUntouch or defining it as 0 disables forced untouch. If bit 15 of the assigned data is 1, the function is disabled with the remainder providing the default value if the function is subsequently enabled.
#define ELOREG_CalStore _T("CalStore" )
"CalStore" tells the driver where to get calibration parameters when it boots and where to write them after calibrating. The low nibble (4 bits) of the LSByte of CalStore tells the read source while the high nibble tells the write destination. In both cases, the touchscreen controller is selected by 1, the registry by 2, and both by 3. Bit 8 of CalStore, if set, tells the driver to flush the registry by calling RegFlushKey after writing (applies only to writing calibration parameters). For example, x131 says to read from the controller and write to the registry with flush and to the controller.
At boot time, the driver first initializes calibration parameters to default values that work reasonably well with many common touchscreen types. It then always reads the registry values. Then, if indicated by the low nibble of the LSByte of CalStore being 1 or 3, reads from the controller. Therefore, missing values at one stage are supplied by a previous stage and none remain uninitialized.
The driver writes calibration parameters in response to IOCTL_ELO_SAVECAL simple IOCTL command. If the SAVECAL_DEFAULT flag is set in the argument to IOCTL_ELO_SAVECAL, the driver will act in accordance with CalStore, specifically the high nibble of the MSByte and bit 8. The argument can override the destination by clearing SAVECAL_DEFAULT and setting SAVECAL_CONTROLLER and/or SAVE_CAL_REG. However, whether to flush the registry after writing is determined strictly by bit 8 of CalStore; the command cannot override this. Whether to write edge calibration parameters is strictly determined by the command's SAVECAL_EDGES flag. Whether to read edge calibration parameters at boot time is determined by the "LinCor" registry value, which is not written by any Elo API command.
IOCTL code: IOCTL_ELO_REGKEYNAME
EloApi Functions: getDevRegKeyName
Although all aspects of touch device operation are controlled by registry settings, applications generally do not need to directly read or write these settings. In most cases, it is more reliable and easier to invoke an IOCTL command, notably Simple Ioctl and Configuration Item, which manage the registry as well as ensure the correct and immediate operational response. However, the API cannot anticipate every possible configuration facility and assumes that some characteristics, especially those involving calibration procedures, such as LinCor, would not be changed by a general application (EloTalk manipulates nearly everything in the registry).
A few configuration options, such as setting touch sound parameters, require an application to directly access an invariant registry key. An application can safely embed this key. Configuration settings for individual touch devices are under keys that may depend on the MultiMon value and the device attachment history (especially for USB). To access the key for a particular device, it is easier and more reliable for an application to get the key path-name from the driver by invoking IOCTL_ELO_REGKEYNAME. This command returns the (Unicode) path-name under HKLM, for example
"\HARDWARE\DEVICEMAP\TOUCH\USB\T2"
The IOCTL argument to IOCTL_ELO_REGKEYNAME is the class IocRegKeyName.
#define MAX_ELOREGKEYNAME 100
class T_EloApi IocRegKeyName : public IocHdr
{
bool mOp; // IocSet/Get
TCHAR mName[ MAX_ELOREGKEYNAME + 1 ];
};
The mOp is IocSet or IocGet. Set is used only for testing.
The API class is CmdRegKeyName.
class T_EloApi CmdRegKeyName : public EloDevId
{
IocRegKeyName mIoc;
GenConEloDevId( CmdRegKeyName );
GenSetGet
};
Applications usually invoke this command through the API function getDevRegKeyName.
// Purpose: Writes the full name of the registry key (under HKLM) for the
// given device to the given destination. This queries the driver to determine
// the key currently in use and it may also manipulate the return value to
// produce the full key name.
// Returns: true if able to produce the key name.
// Arguments:
//- TCHAR *outName is the destination supplied by the caller. This must contain
// MAX_ELOREGKEYNAME + 1 elements.
//- UCHAR devNum is the device number. Any value > 0 is legal but may not
// necessarily refer to an attached device.
//- TCHAR *devName is optional name, e.g. "ELO1:", which overrides devNum.
bool T_EloApi getDevRegKeyName( TCHAR *outName, UCHAR devNum, TCHAR *devName = 0 );
EXAMPLE
TCHAR gRegKeyName[ MAX_ELOREGKEYNAME + 1 ];
EloApi::getDevRegKeyName( gRegKeyName, 1, _T("Elo1:") );
IOCTL code: IOCTL_ELO_HOLD_PARMS
The on hold command tells how to respond to touch hold but it doesn't specify touch hold parameters. The IOCTL_ELO_HOLD_PARMS command reads and writes these parameters for a touch device.
The IOCTL argument is the class IocHoldParms.
enum {
// Individual feature indices. These index mParms.
HPIDX_TICK, // Hold timer tick period in ms
HPIDX_JIGGLE, // Hold perimeter in absolute touch units.
HPIDX_SHOW_STEP, // Feedback step size in video pixels.
HPIDX_SHOW_TICKS, // Tick count at which begin to provide hold visual feedback.
HPIDX_EVENT_TICKS, // Tick count at which to generate hold event (RCOH or other)
HPIDX_UNTOUCH_TICKS, // Number of ticks until forced untouch.
// Command pseudo-indices. Produce mCmd flags but no elements of mParms.
HPIDX_GET // Get all current parameters and flags.
};
class T_EloApi HoldParms
{
USHORT mP[6];
USHORT& tick( void ) { return mP[ HPIDX_TICK ]; }
USHORT& jiggle( void ) { return mP[ HPIDX_JIGGLE ]; }
USHORT& showStep( void ) { return mP[ HPIDX_SHOW_STEP ]; }
USHORT& showTicks( void ) { return mP[ HPIDX_SHOW_TICKS ]; }
USHORT& eventTicks( void ) { return mP[ HPIDX_EVENT_TICKS ]; }
USHORT& untouchTicks( void ) { return mP[ HPIDX_UNTOUCH_TICKS ]; }
};
const HoldParms DefaultHoldParms = {
100, // TICK
1000, // JIGGLE
10, // SHOW_STEP
1, // SHOW_TICKS
8, // EVENT_TICKS
0, // UNTOUCH_TICKS
};
class T_EloApi IocHoldParms : public IocHdr
{
HoldParms mParms;
USHORT mCmd; // Bit-mapped flags IdxFlag[ HPIDX_TICK...HPIDX_UNTOUCH_TICKS].
};
The mCmd member contains is a bitmap of the parameters to be changed when writing to the driver. Each bit from 0 to 5 of mCmd, tells whether to write the corresponding element of the mP array of parameter values. Bit 0 corresponds to index HPIDX_TICK, 1 to HPIDX_JIGGLE, 2 to HPIDX_SHOW_STEP, 3 to HPIDX_SHOW_TICKS, 4 to HPIDX_EVENT_TICKS, and 5 to HPIDX_UNTOUCH_TICKS. Bit 6 corresponds to HPIDX_GET, which, if set, tells to read the values from the driver instead of writing them.
The API class is HoldParms.
class T_EloApi HoldParms : public EloDevId
{
IocHoldParms mIoc;
GenConEloDevId( HoldParms );
bool send( void );
};
This class contains only one function, send. Reading vs. writing is determined by the HPIDX_GET flag of IocHoldParms.mCmd.
IOCTL code: IOCTL_ELO_MOUSELIMITS
The IOCTL argument is the class IocMouseLimits.
enum { EloLimitGet, EloLimitSetRel, EloLimitSetAbs };
class T_EloApi MouseLimits
{
long edge[4]; // Index by VID_LEFT, VID_TOP, VID_RIGHT, VID_BOTTOM
};
class T_EloApi IocMouseLimits
{
USHORT mOp; // EloLimitGet, EloLimitSetRel, EloLimitSetAbs
MouseLimits limit;
};
The API class is CmdMouseLimits.
class T_EloApi CmdMouseLimits : public EloDevId
{
bool setOrGet( void );
public:
IocMouseLimits mIoc;
GenConEloDevId( CmdMouseLimits );
bool get( void ) { mIoc.mOp = EloLimitGet; return setOrGet(); }
bool setRel( void ) { mIoc.mOp = EloLimitSetRel; return setOrGet(); }
bool setAbs( void ) { mIoc.mOp = EloLimitSetAbs; return setOrGet(); }
};
IOCTL code: IOCTL_ELO_SMARTSET
The IOCTL argument is the class IocSmartSet.
enum { SS_TRANSFER_NORMAL, SS_TRANSFER_NOWAIT,
SS_TRANSFER_SHORTWAIT, SS_TRANSFER_LONGWAIT, SS_TRANSFER_WAITFOREVER
}; // TransferStatus.mCmd
typedef struct {
short mCnt;
USHORT mCmd; // SS_TRANSFER_x
DWORD mErr; // return from communication function.
} TranStat;
class T_EloApi EloTrans
{
UCHAR mBuf[10];
TranStat mStat;
};
class T_EloApi IocSmartSet : public IocHdr
{
EloTrans mIn;
EloTrans mOut;
};
The API class is CmdSmartSet.
class T_EloApi CmdSmartSet : public EloDevId
{
IocSmartSet mIoc;
GenConEloDevId( CmdSmartSet );
bool mDo( void );
};
EXAMPLE
CmdSmartSet cmd( 1, _T("Elo1:") );
memset( cmd.mIoc.mOut.mBuf, ' ', 8 );
cmd.mIoc.mOut.mBuf[0] = 'a';
cmd.mIoc.mOut.mStat.mCnt = 8;
cmd.mIoc.mIn.mStat.mCnt = 8;
cmd.mDo();
The Api function canDevTalk tests communication with the given touchscreen by sending a SmartSet ACK query. It returns true if the touchscreen responds and false if not. This is used mainly with serial touchscreens that might be disconnected. Usually, if a USB touchscreen disconnects or fails, the driver automatically removes its application interface. For example, elova uses this function to determine whether any serial touchscreens defined in the registry are not actually connected and not wait for these to be calibrated before automatically closing.
EXAMPLE
if( EloApi::canDevTalk( 1, _T("Elo1:"))
IOCTL code: IOCTL_ELO_DEVCFG
The IOCTL argument is the class IocDevCfg.
class T_EloApi DevCfg
{
EdgeCal mEdgeCal;
EloAcc mAcc;
CornerAcc mCornerAcc;
LinCor mLinCor;
MouseLimits mMouseLimits; // long edge[4] index by VID_LEFT, VID_TOP,
// VID_RIGHT, VID_BOTTOM
DWORD mPriority;
DWORD mHighPriority;
DWORD mMouseMode;
DWORD mAntiBounce;
TCHAR mPortName[13]; // "USB" or serial name specified in Registry, e.g. "COM1:"
};
class T_EloApi IocDevCfg
{
USHORT mOp; // IocSet/Get
DevCfg mDevCfg;
};
The API class is CmdDevCfg.
class T_EloApi CmdDevCfg : public EloDevId
{
IocDevCfg mIoc;
GenConEloDevId( CmdDevCfg );
GenSetGet
};
These functions are used only by calibrating programs, such as eloVa. They are included in this document only for completeness.
IOCTL code: IOCTL_ELO_GETPOINT
The IOCTL argument is the class IocGetPt.
enum { TCH_FAIL, TCH_DISCONNECT, TCH_NOEVENT, TCH_TOUCH, TCH_CLICK, TCH_HOLD };
class T_EloApi ApiTchEvent
{
USHORT mTch; // TCH_FAIL, TCH_DISCONNECT, TCH_NOEVENT, etc.
USHORT mX;
USHORT mY;
USHORT mZ;
long mTransX;
long mTransY;
USHORT mApiDevId;
ApiTchEvent() { mTch = TCH_NOEVENT; }
void reset( void ) { mTch = TCH_NOEVENT; }
bool isError( void ) { return mTch < TCH_NOEVENT; }
bool isTouch( void ) { return mTch > TCH_NOEVENT; }
};
class T_EloApi IocGetPt : public IocHdr
{
bool mBlock; // In. If true then block in device driver waiting for event.
ApiTchEvent mEvent;
};
The API class is CmdGetPt.
class T_EloApi CmdGetPt : public EloDevId
{
IocGetPt mIoc;
GenConEloDevId( CmdGetPt );
bool get( void );
};
IOCTL code: IOCTL_ELO_CAL3DAT
The IOCTL argument is the class IocCal3Dat.
typedef long T_CAL;
enum { ORIENT_INVX = 1, ORIENT_INVY = 2, ORIENT_SWAPXY = 4 };
typedef struct {
T_CAL mOffX; // Touchscreen offset from video normalized to 65536 in video X axis.
T_CAL mOffY; // " Y axis.
T_CAL mVidDx; // Video calibration distance in X axis normalized to 65536.
T_CAL mVidDy; // " in Y axis.
// mTsDx and mTsDy are relative to the video X and Y axes during calibration. They
// may not match the touchscreen controller's orientation sense.
T_CAL mTsDx; // Touchscreen calibration distance in TS units in video X axis.
T_CAL mTsDy; // " in video Y axis.
USHORT mSwapXy;
USHORT mCalcTvRel( void ) { return ( mSwapXy ? ORIENT_SWAPXY : 0 ) |
( mTsDy < 0 ? ORIENT_INVY : 0 ) | ( mTsDx < 0 ? ORIENT_INVX : 0 ); }
} Cal3Data;
typedef struct {
USHORT mTvRelation; // Index/selector indicating touch to video orientation.
USHORT mBorder[4]; // TSEDGE_XLO, TSEDGE_YLO, TSEDGE_XHI, TSEDGE_YHI
} Cal3Ex;
class T_EloApi Cal3DatEx
{
Cal3Data mData;
Cal3Ex mEx;
};
class T_EloApi IocCal3Dat : public IocHdr
{
USHORT mOp; // IocSet/Get
Cal3DatEx dat;
};
The API class is CmdCal3Dat.
class T_EloApi CmdCal3Dat : public EloDevId
{
IocCal3Dat mIoc;
GenConEloDevId( CmdCal3Dat );
GenSetGet
};
IOCTL code: IOCTL_ELO_EDGECAL
The IOCTL argument is the class IocEdgeCal.
typedef short T_ACC_RATE;
typedef USHORT T_ACC_POS;
enum { LINCOR_UNKNOWN, LINCOR_NOTREQUIRED, LINCOR_SEGMENTED }; // EdgeCal.mType
class T_EloApi EdgeCal
{
USHORT mType;
T_ACC_RATE mLcAcc[4]; // Portion of linearity compensation represented by acceleration.
USHORT mCntPts[4]; // Number of inflection points each edge list.
};
class T_EloApi IocEdgeCal : public IocHdr
{
static int mByteCnt( int ptCnt ) { return
sizeof( IocEdgeCal ) + ( ptCnt - 1 ) * sizeof( RawPoint ); }
USHORT mSize; // The total size of this IocEdgeCal instance
// includes mSize through extensible mPts. Calculate by
// sizeof( IocEdgeCal ) + ( count points - 1 ) * sizeof( RawPoint ).
EdgeCal mEdgeCal;
USHORT mOp; // IocGet/Set
USHORT mPtsByteCnt; // Size of mPts
RawPoint mPts[1]; // First element of extensible array of inflection points.
};
The API class is CmdEdgeCal.
class T_EloApi CmdEdgeCal : public EloDevId
{
IocEdgeCal *mIoc; // Pointer because IocEdgeCal is extensible.
GenConEloDevId( CmdEdgeCal );
bool set( void );
bool get( void );
bool getNoPts( IocEdgeCal *ec ) {
mIoc = ec; mIoc->mSize = sizeof( CmdEdgeCal ); return get(); }
};
IOCTL code: IOCTL_ELO_LINCOR
The IOCTL argument is the class IocLinCor.
class T_EloApi LinCor
{
UCHAR mOn[4]; // TSEDGE_XLO,...
T_ACC_RATE mLcAdj[4]; // TSEDGE_XLO,... acceleration adjustment.
// See CornerAcc.mXoff and mYoff for edge calibration ideal position.
};
enum {
LINCOR_GET = 0,
LINCOR_SET_ON = 1,
LINCOR_SET_ADJ = 2
}; // IocLinCor.mOp Get or bit-mapped set.
class T_EloApi IocLinCor
{
USHORT mOp; // LINCOR_GET, LINCOR_SET_ON, LINCOR_SET_ADJ
LinCor mLinCor;
};
The API class is CmdLinCor.
class T_EloApi CmdLinCor : public EloDevId
{
bool setOrGet( void );
public:
IocLinCor mIoc;
GenConEloDevId( CmdLinCor );
bool get( void ) { mIoc.mOp = LINCOR_GET; return setOrGet(); }
bool setOn( void ) { mIoc.mOp = LINCOR_SET_ON; return setOrGet(); }
bool setAdj( void ) { mIoc.mOp = LINCOR_SET_ADJ; return setOrGet(); }
bool setOnAdj( void ) { mIoc.mOp = LINCOR_SET_ON+LINCOR_SET_ADJ;
return setOrGet(); }
};
IOCTL code: IOCTL_ELO_ACCEL
The IOCTL argument is the class IocAcc.
enum { ACC_OFF, ACC_ON, ACC_DEFAULT }; // EloAcc.mMethod
#define ACC_MULT 256
class T_EloApi EloAcc
{
// All arrays indexed in TS domain: TSEDGE_XLO, TSEDGE_YLO, TSEDGE_XHI, TSEDGE_YHI
UCHAR mMethod[4]; // ACC_NONE, ACC_DEFAULT, ACC_ON.
T_ACC_POS mPos[4];
T_ACC_RATE mRate[4];
};
enum { GET_ACCEL = 0,
SET_ACCEL_METHOD = 1,
SET_ACCEL_RATE = 2,
SET_ACCEL_POS = 4 }; // IocAccel.mOp
class T_EloApi IocAcc
{
public:
USHORT mOp; // GET_ACCEL...SET_ACCEL_POS
EloAcc mAcc;
};
The API class is CmdAccel.
class T_EloApi CmdAccel : public EloDevId
{
IocAcc mIoc;
GenConEloDevId( CmdAccel );
bool setOrGet( void );
bool get( void ) { mIoc.mOp = GET_ACCEL; return setOrGet(); }
bool set( void ) { mIoc.mOp =
SET_ACCEL_METHOD + SET_ACCEL_RATE + SET_ACCEL_POS; return setOrGet(); }
bool setMethod( void ) { mIoc.mOp = SET_ACCEL_METHOD; return setOrGet(); }
bool setRate( void ) { mIoc.mOp = SET_ACCEL_RATE; return setOrGet(); }
bool setPos( void ) { mIoc.mOp = SET_ACCEL_POS; return setOrGet(); }
};