1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

UPDDMultitouch: Implement multi-touch in macOS using the UPDD API

This commit is contained in:
Brian Kendall 2024-05-07 14:00:32 -04:00
parent eac95d5905
commit cf2057c2eb
4 changed files with 1480 additions and 2 deletions

View file

@ -156,6 +156,7 @@
#else
#include "native/accessibility/juce_Accessibility_mac.mm"
#include "native/juce_PerScreenDisplayLinks_mac.h"
#include "native/juce_UPDDMultitouch_mac.mm"
#include "native/juce_NSViewComponentPeer_mac.mm"
#include "native/juce_WindowUtils_mac.mm"
#include "native/juce_Windowing_mac.mm"

View file

@ -176,6 +176,8 @@ public:
isSharedWindow (viewToAttachTo != nil),
lastRepaintTime (Time::getMillisecondCounter())
{
UPDDManager::getInstance()->ensureConnected();
appFocusChangeCallback = appFocusChanged;
isEventBlockedByModalComps = checkEventBlockedByModalComps;
@ -2945,9 +2947,16 @@ bool KeyPress::isKeyCurrentlyDown (int keyCode)
//==============================================================================
bool detail::MouseInputSourceList::addSource()
{
if (sources.size() == 0)
auto numSources = sources.size();
if (numSources == 0)
{
addSource (0, MouseInputSource::InputSourceType::mouse);
if (UPDDManager::getInstance()->isUPDDAvailable()) {
addSource (1, MouseInputSource::InputSourceType::touch);
}
return true;
}
@ -2956,7 +2965,7 @@ bool detail::MouseInputSourceList::addSource()
bool detail::MouseInputSourceList::canUseTouch() const
{
return false;
return UPDDManager::getInstance()->isUPDDAvailable();
}
//==============================================================================

View file

@ -0,0 +1,501 @@
#include "juce_UPDDMultitouch_upddapi.h"
namespace juce
{
class UPDDManager : public DeletedAtShutdown
{
public:
#ifndef DOXYGEN
JUCE_DECLARE_SINGLETON(UPDDManager, true)
#endif
typedef void (*TBApiOpenType)(void);
typedef void (*TBApiCloseType)(void);
typedef void (*TBApiRegisterEventType)(HTBDEVICE, unsigned long long, unsigned long, TB_EVENT_CALL);
typedef void (*TBApiUnregisterEventType)(TB_EVENT_CALL);
typedef HTBDEVICE (*TBApiGetRelativeDeviceType)(int);
typedef TBBOOL (*TBApiGetSettingAsIntType)(HTBDEVICE, const TBCHAR *, int32_t *);
enum class TouchState {
Unknown, Began, Moved, Released, Stationary
};
struct TouchIdentifier {
HTBDEVICE hDevice = 0;
TBSTYLUS hStylus = 0;
unsigned char hidReportid = 0;
unsigned char usbInterface = 0;
bool isPen = false;
bool operator==(const TouchIdentifier &other) const {
return hDevice == other.hDevice && hStylus == other.hStylus && hidReportid == other.hidReportid
&& usbInterface == other.usbInterface && isPen == other.isPen;
}
bool operator<(const TouchIdentifier &other) const {
if (hDevice != other.hDevice) {
return hDevice < other.hDevice;
}
if (hStylus != other.hStylus) {
return hStylus < other.hStylus;
}
if (hidReportid != other.hidReportid) {
return hidReportid < other.hidReportid;
}
if (usbInterface != other.usbInterface) {
return usbInterface < other.usbInterface;
}
return isPen < other.isPen;
}
static TouchIdentifier none;
};
struct TouchData {
Point<int> screenPosition;
Point<int> prevScreenPosition;
TouchState state = TouchState::Unknown;
TouchState prevState = TouchState::Unknown;
float pressure = 0;
int id = -1;
};
struct UPDDDeviceData {
std::map<TouchIdentifier, TouchData> touches;
bool touchesChangedSinceLastUpdate = false;
uint32_t minZ = 0;
uint32_t maxZ = 127;
};
struct JUCEDeviceData {
std::map<TouchIdentifier, WeakReference<Component>> touchWindows;
};
private:
CriticalSection lock;
void *libupddapi = nullptr;
TBApiOpenType dTBApiOpen = nullptr;
TBApiCloseType dTBApiClose = nullptr;
TBApiRegisterEventType dTBApiRegisterEvent = nullptr;
TBApiUnregisterEventType dTBApiUnregisterEvent = nullptr;
TBApiGetRelativeDeviceType dTBApiGetRelativeDevice = nullptr;
TBApiGetSettingAsIntType dTBApiGetSettingAsInt = nullptr;
std::atomic_bool opened{false};
std::atomic_bool connected{false};
std::atomic_bool registered{false};
std::atomic_bool unloaded{false};
std::map<HTBDEVICE, UPDDDeviceData> upddDeviceDataByHandle; // NB: will be accessed by multiple threads
std::map<HTBDEVICE, JUCEDeviceData> JUCEDeviceDataByHandle; // NB: must only be accessed in main thread
public:
void ensureConnected()
{
const ScopedLock sl(lock);
if (!isUPDDAvailable() || unloaded || opened) {
return;
}
dTBApiRegisterEvent(0, 0, _EventConfiguration, upddConfigurationEventStatic);
dTBApiOpen();
opened = true;
}
bool isUPDDAvailable()
{
return libupddapi && dTBApiOpen && dTBApiClose && dTBApiRegisterEvent && dTBApiUnregisterEvent
&& dTBApiGetRelativeDevice && dTBApiGetSettingAsInt;
}
private:
UPDDManager()
{
loadUPDDAPI();
}
~UPDDManager()
{
shutdown();
if (libupddapi) {
dlclose(libupddapi);
}
clearSingletonInstance();
}
void loadUPDDAPI()
{
if (!File("/Library/Application Support/UPDD").exists()) {
// UPDD v7 is not installed, nothing to do here
return;
}
dlerror(); // Clear any existing errors, just in case
String errorString;
// First try finding libupddapi on RPATH:
libupddapi = dlopen("@rpath/libupddapi.7.0.0.dylib", RTLD_LAZY);
if (!libupddapi) {
errorString << dlerror();
// Failing that, try absolute path:
libupddapi = dlopen("/Library/Application Support/UPDD/libupddapi.7.0.0.dylib", RTLD_LAZY);
}
if (!libupddapi) {
errorString << "; " << dlerror();
DBG("Failed to load libupddapi: " << errorString);
DBG("Multi-touch will not work");
return;
}
dTBApiOpen = (TBApiOpenType)dlsym(libupddapi, "TBApiOpen");
if (!dTBApiOpen) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
dTBApiClose = (TBApiCloseType)dlsym(libupddapi, "TBApiClose");
if (!dTBApiClose) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
dTBApiRegisterEvent = (TBApiRegisterEventType)dlsym(libupddapi, "TBApiRegisterEvent");
if (!dTBApiRegisterEvent) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
dTBApiUnregisterEvent = (TBApiUnregisterEventType)dlsym(libupddapi, "TBApiUnregisterEvent");
if (!dTBApiUnregisterEvent) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
dTBApiGetRelativeDevice = (TBApiGetRelativeDeviceType)dlsym(libupddapi, "TBApiGetRelativeDevice");
if (!dTBApiGetRelativeDevice) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
dTBApiGetSettingAsInt = (TBApiGetSettingAsIntType)dlsym(libupddapi, "TBApiGetSettingAsInt");
if (!dTBApiGetSettingAsInt) {
DBG("Failed to load libupddapi: " << dlerror());
DBG("Multi-touch will not work");
return;
}
}
void shutdown()
{
if (!isUPDDAvailable()) {
return;
}
const ScopedLock sl(lock);
if (registered) {
dTBApiUnregisterEvent(upddTouchEventStatic);
registered = false;
}
if (opened) {
dTBApiUnregisterEvent(upddConfigurationEventStatic);
dTBApiClose();
opened = false;
}
}
static void upddConfigurationEventStatic(UPDD_CONTEXT, _PointerEvent *event)
{
// Being careful just in case this function executes after UPDDManager
// has been deleted during shutdown. Will follow this pattern wherever
// we schedule call to a method of UPDDManager
if (UPDDManager *shared = UPDDManager::getInstance()) {
shared->upddConfigurationEvent(event);
}
}
void upddConfigurationEvent(_PointerEvent *event)
{
switch(event->pe.config.configEventType) {
case CONFIG_EVENT_CONNECT:
connected = true;
DBG("Connected to UPDD");
dispatch_async(dispatch_get_main_queue(), ^{
if (UPDDManager *shared = UPDDManager::getInstance()) {
shared->onUPDDConnected();
}
});
break;
case CONFIG_EVENT_DISCONNECT:
DBG("Disconnected from UPDD");
connected = false;
break;
case CONFIG_EVENT_UNLOAD:
DBG("UPDD is unloading");
unloaded = true;
shutdown();
break;
case CONFIG_EVENT_DEVICE:
case CONFIG_EVENT_DEVICE_BIND:
dispatch_async(dispatch_get_main_queue(), ^{
if (UPDDManager *shared = UPDDManager::getInstance()) {
shared->updateDevices();
}
});
break;
}
}
void onUPDDConnected()
{
if (!registered) {
dTBApiRegisterEvent(0, 0, _EventTypeDigitiserEvent, upddTouchEventStatic);
registered = true;
}
}
void updateDevices()
{
const ScopedLock sl(lock);
int deviceIndex = 0;
HTBDEVICE device = dTBApiGetRelativeDevice(deviceIndex);
while(device != TB_INVALID_HANDLE_VALUE) {
UPDDDeviceData &deviceData = upddDeviceDataByHandle[device];
getPressureRangeFromUPDD(deviceData.minZ, deviceData.maxZ, device);
device = dTBApiGetRelativeDevice(deviceIndex);
}
}
int32_t upddGetSettingAsIntWithDefault(HTBDEVICE device, const char *name, int32_t defaultValue)
{
int32_t result;
bool success = dTBApiGetSettingAsInt(device, name, &result);
if (success) {
return result;
} else {
return defaultValue;
}
}
void getPressureRangeFromUPDD(uint32_t &minPressure, uint32_t &maxPressure, HTBDEVICE deviceHandle)
{
minPressure = 0;
maxPressure = 127; // Default max pressure value, probably is not correct
if (upddGetSettingAsIntWithDefault(deviceHandle, "ignore_maxz", 0) == 1) {
return;
}
int32_t minp = upddGetSettingAsIntWithDefault(deviceHandle, "minpressure", 0);
int32_t maxp = upddGetSettingAsIntWithDefault(deviceHandle, "maxpressure", 0);
if (minp > 0) {
minPressure = (uint32_t)minp;
}
if (maxp > 0) {
maxPressure = (uint32_t)maxp;
}
}
static void upddTouchEventStatic(UPDD_CONTEXT, _PointerEvent *event)
{
if (UPDDManager *shared = UPDDManager::getInstance()) {
shared->upddTouchEvent(event);
}
}
void upddTouchEvent(_PointerEvent *event)
{
if (event->type != _EventTypeDigitiserEvent || event->pe.digitiserEvent.digitizerType != DIGITIZER_TYPE_TOUCH
|| event->calibrating || unloaded) {
return;
}
const ScopedLock sl(lock);
UPDDDeviceData &deviceData = upddDeviceDataByHandle[event->hDevice];
TouchIdentifier touchId;
touchId.hDevice = event->hDevice;
touchId.hStylus = event->hStylus;
touchId.hidReportid = event->hidReportid;
touchId.usbInterface = event->usbInterface;
touchId.isPen = (event->pe.digitiserEvent.digitizerType == DIGITIZER_TYPE_PEN);
bool touching = event->pe.digitiserEvent.de.touchEvent.touchingLeft;
bool prevTouching = (deviceData.touches.count(touchId) == 1);
TouchData &touchData = deviceData.touches[touchId];
touchData.prevScreenPosition = touchData.screenPosition;
touchData.prevState = touchData.state;
touchData.screenPosition = Point((int)event->pe.digitiserEvent.screenx, (int)event->pe.digitiserEvent.screeny);
touchData.pressure = event->pe.digitiserEvent.zSupport
? jmax(jmin((float(event->pe.digitiserEvent.z - deviceData.minZ) / float(deviceData.maxZ)),
1.0f),
0.0f)
: 0.0f;
if (touchData.id == -1) {
touchData.id = findNextUnusedTouchIdForDevice(deviceData);
}
if (touching && !prevTouching) {
// Touch began
deviceData.touchesChangedSinceLastUpdate = true;
touchData.state = TouchState::Began;
} else if (!touching && prevTouching) {
// Touch ended
deviceData.touchesChangedSinceLastUpdate = true;
touchData.state = TouchState::Released;
} else if (touching && prevTouching) {
// Touch updated
if ((touchData.prevState != TouchState::Moved && touchData.prevState != TouchState::Stationary
&& touchData.prevState != TouchState::Began)
|| touchData.screenPosition != touchData.prevScreenPosition) {
deviceData.touchesChangedSinceLastUpdate = true;
touchData.state = TouchState::Moved;
} else {
touchData.state = TouchState::Stationary;
}
} else {
// Received touch released event before touch down event
// Some touch devices do this, in which case we want to ignore that touch event
deviceData.touches.erase(touchId);
}
if (event->pe.digitiserEvent.lastContact && deviceData.touchesChangedSinceLastUpdate) {
deviceData.touchesChangedSinceLastUpdate = false;
{
HTBDEVICE deviceHandle = event->hDevice;
std::map<TouchIdentifier, TouchData> touches = deviceData.touches;
dispatch_async(dispatch_get_main_queue(), ^{
if (UPDDManager *shared = UPDDManager::getInstance()) {
shared->postDeviceTouchesToContainers(deviceHandle, touches);
}
});
}
for(auto it = deviceData.touches.begin(); it != deviceData.touches.end();) {
if (it->second.state == TouchState::Released) {
it = deviceData.touches.erase(it);
} else {
++it;
}
}
}
}
Component * findTopLevelComponentContainingPoint(const Point<int> &p)
{
Component *component = Desktop::getInstance().findComponentAt(p);
if (!component) {
return nullptr;
}
return component->getTopLevelComponent();
}
void postDeviceTouchesToContainers(HTBDEVICE deviceHandle, const std::map<TouchIdentifier, TouchData> &touches)
{
JUCEDeviceData &deviceData = JUCEDeviceDataByHandle[deviceHandle];
for(auto it = touches.begin(); it != touches.end(); ++it) {
const TouchIdentifier &touchId = it->first;
const TouchData &touchData = it->second;
if (touchData.state == TouchState::Unknown || touchData.state == TouchState::Stationary) {
// Ignore degenerate or stationary touch
continue;
}
if (touchData.state == TouchState::Began) {
Component *window = findTopLevelComponentContainingPoint(touchData.screenPosition);
deviceData.touchWindows[touchId] = WeakReference<Component>(window);
}
Component *touchWindow = deviceData.touchWindows[touchId].get();
if (touchData.state == TouchState::Released) {
deviceData.touchWindows.erase(touchId);
}
if (!touchWindow) {
// A window might have been closed or deleted over the course of a touch
continue;
}
ComponentPeer *peer = touchWindow->getPeer();
if (!peer) {
continue;
}
Point<int> localPosition = touchWindow->getLocalPoint(nullptr, touchData.screenPosition);
ModifierKeys modifiers;
if (touchData.state == TouchState::Began || touchData.state == TouchState::Moved) {
modifiers = ModifierKeys::getCurrentModifiers().withoutMouseButtons().withFlags(ModifierKeys::leftButtonModifier);
} else {
modifiers = ModifierKeys::getCurrentModifiers().withoutMouseButtons();
}
peer->handleMouseEvent(MouseInputSource::InputSourceType::touch, localPosition.toFloat(),
modifiers, touchData.pressure, 0.0, Time::currentTimeMillis(), {}, touchData.id);
}
}
int findNextUnusedTouchIdForDevice(UPDDDeviceData &deviceData)
{
SortedSet<int> usedIds;
for(const auto &it : deviceData.touches) {
usedIds.add(it.second.id);
}
int id = 0;
while(usedIds.contains(id)) {
++id;
}
return id;
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UPDDManager)
};
JUCE_IMPLEMENT_SINGLETON (UPDDManager)
}

View file

@ -0,0 +1,967 @@
#ifndef TBAPI_H
#define TBAPI_H
#define UPDD_API_VERSION 7
#include "stdint.h"
#include <stddef.h> //https://stackoverflow.com/questions/49990753/xcode-7-unknown-type-name-size-t
#undef TBAPIDLLPFX
#ifndef TBCHAR
#ifdef UNDER_CE
#define TBCHAR wchar_t
#define _TBT(x) L ## x
#else
#define TBCHAR char
#define _TBT
#endif
#endif
#ifndef t_string
#ifdef UNDER_CE
#define t_string wstring
#else
#define t_string string
#endif
#endif
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__ || __aarch64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
#ifdef __APPLE__
#define ENVIRONMENT64
#endif
#ifdef ENVIRONMENT64
#define UPDD_CONTEXT unsigned long long
#else
#define UPDD_CONTEXT unsigned long
#endif
#ifdef INTERNALAPI
// this mode is for internal touch-base use
#ifdef _WIN32
//#pragma comment(linker,"/nodefaultlib:libcmt")
//#pragma comment(linker,"/nodefaultlib:libcmtd")
#pragma comment(linker,"/nodefaultlib:msvcrtd")
#pragma comment(linker,"/nodefaultlib:msvcrt")
#pragma comment(lib,"setupapi.lib")
#endif
#endif
#ifdef _WIN32
#define TBCALL _stdcall
#else
#define TBCALL
#endif
#ifdef TBAPIDLL_EXPORTS
#ifdef _WIN32
#define TBAPI __declspec(dllexport) TBCALL
#pragma warning(disable:4518)
#endif
#else
#ifdef _WIN32
#define TBAPI __declspec(dllimport) TBCALL
#pragma warning(disable:4518)
#endif
//#define TBAPIDLLPFX
#endif
#ifndef TBAPI
#define TBAPI
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#define TBBOOL uint16_t
// constants that define data types to be read
// can be ORed, eg _EventTypeXY | _EventTypeEvent
// to read pointer co-ordinates and button events
#define _EventTypeXY 0x0001 // pointer co-ordinates
#define _EventTypeEval 0x0002 // change in evaluation state
#define _EventTypeRaw 0x0008 // raw data
#define _EventTypeToolbar 0x0010 // toolbar events
#define _EventConfiguration 0x0020 // OBSOLESCENT - typo for _EventTypeConfiguration, this value will be removed in due course
#define _EventTypeConfiguration 0x0020 // notifications of changes to driver configuration and state
//#define _EventTypeZ 0x0080 // notifications of change in Z values OBSOLETE; use _EventTypeDigitiserEvent
#define _EventTypeRelative 0x0100 // notifications of relative movement
#define _EventTypeUnload 0x0200 // the driver is about to attempt an unload
#define _EventTypeXYNoMask 0x1000 // same as _EventTypeXY but not masked by toolbars and surrounds used for calibration -- WAS _EventTypeXYCal prior to V6
#define _EventTypeInteractiveTouch 0x4000 // mouse pointer state events for interactive touch mode
#ifdef UPDD_GESTURES
#define _EventTypeGesture 0x8000
#endif
#define _EventTypePlayUPDDSound 0x800000 // play a sound defined for this device
#define _EventTypeMouseEvent 0x1000000 // raw data sent to mouse port
#define _EventTypeSecBlock 0x2000000 // touch data was received when a security block was in place
#define _EventTypeRawMouse 0x8000000 // internal use only
#define _EventTypeLogicalEvent 0x20000000 // state changes passed to operating system
#define _EventTypePhysicalEvent 0x40000000 // changes in the actual "touching" state OBSOLESCENT
#define _EventTypeDigitiserEvent 0x4000000
#define _EventTypeDigitiserEventTOIP 0x10000000 // for UPDD touch over ip internal use only, do not use in 3rd party software
#define CONFIG_EVENT_SETTINGS 1 // one or more updd settings have been changed
#define CONFIG_EVENT_CONCURRENCY_SIGNAL 2 // a signal was requested by a call to TBApiRegisterProgram
#define CONFIG_EVENT_CONNECT 3 // a client connection to the driver has been established
#define CONFIG_EVENT_DISCONNECT 4 // the client connection to the driver has disconnected
#define CONFIG_EVENT_UNLOAD 5 // the driver has requested termination of this application, typically for uninstallation
#define CONFIG_EVENT_DEVICE 6 // notification of a change in physical device state
#define CONFIG_EVENT_AUTOCONFIGURE 7 // an auto configure operation has been triggered
#define CONFIG_EVENT_CONCURRENCY_CHANGE 8 // a program was registered with TBApiRegisterProgram or deregistered
#define CONFIG_EVENT_MONITOR_DETECT 9 // sent at beginning and end of a monitor detection sequence
#define CONFIG_EVENT_INTERNAL 10 // reserved for internal use
#define CONFIG_EVENT_DEVICE_BIND 11 // notification of a change in logical device state
#define CONFIG_EVENT_INTERNAL_2 12 // reserved for internal use
#define TOUCH_BIT_FLAGS_LEFT 0x1
#define TOUCH_BIT_FLAGS_RIGHT 0x2
#define TOUCH_BIT_FLAGS_IN_RANGE 0x8
#define PEN_BIT_FLAGS_TIP 0x1
#define PEN_BIT_FLAGS_BARREL 0x2
#define PEN_BIT_FLAGS_ERASER 0x4
#define PEN_BIT_FLAGS_IN_RANGE 0x8
#define PEN_BIT_FLAGS_INVERT 0x10
#define PEN_BIT_FLAGS_Z 0x20
#define DIGITIZER_TYPE_PEN 0x2
#define DIGITIZER_TYPE_TOUCH 0x4
#define HTBDEVICE unsigned char
#define HTBTOOLBAR int16_t
#define TBSTYLUS unsigned char
#define TB_INVALID_HANDLE_VALUE 0x00
#define MAXSTYLENAME 32
#define MAXCALPOINTS 25
#define INJECT_FLAG_IGNORE_MP_DISABLED 2
#define INJECT_FLAG_GENERATE_POINTER_EVENTS 4
#define INJECT_FLAG_GENERATE_COMPATIBILITY_EVENTS 8
#define INJECT_FLAG_INTERNAL_COORDINATES 16
#define INJECT_FLAG_RAW_COORDINATES 32
#define INJECT_FLAG_NOT_LAST_CONTACT 64
#define NOTIFY_LEVEL_OTHER 0
#define NOTIFY_LEVEL_CONFIG_WARNINGS 1
#define NOTIFY_LEVEL_EVAL_AND_CRITICAL 2
#ifndef TBAPIDEFNS_H
#define TBAPIDEFNS_H
#pragma pack (push, 1)
#ifndef __cplusplus
typedef struct _PointerEvent _PointerEvent;
#endif
struct _PointerEvent // was PointerData prior to V6
{
HTBDEVICE hDevice; // device handle that this event relates to or 0 if it is not device specific
TBSTYLUS hStylus; // stylus number, (also known as contact number or touch number) was HTBSTYLUS prior to V6
uint64_t type; // data type of the event, indicates which of the items in the union below is populated
uint64_t length; // length of data (currently only raw data)
unsigned char touchDelegated; // set to true (1) if this app should act as the primary provider of touch.
unsigned char usbConfiguration;
unsigned char usbInterface;
unsigned char hidEndpoint;
unsigned char hidReportid;
unsigned char calibrating; // set to true (1) if calibration is active; most client apps (ie non calibration apps) should ignore events with this set
uint8_t monitor_number;
uint32_t timestamp;
uint8_t priority; // for internal use only
uint8_t reserved_byte[2];
uint32_t reserved[14];
// unsigned long reserved[16];
// unsigned long tick; // indicates relative time data was read
union _pe // only one of the following is used, as indicated by the "type" member
{
struct _digitiserEvent
{
union _de
{
struct _penEvent
{
uint8_t tipSwitch : 1; // bit flags relating to pen devices, relates to PEN_BIT_FLAGS_XXX above
uint8_t barrelSwitch : 1;
uint8_t invert : 1;
uint8_t inrange : 1;
uint8_t eraser : 1;
uint8_t reserved2 : 1;
uint8_t reserved3 : 1;
uint8_t reserved4 : 1;
uint32_t reserved5;
}penEvent;
struct _touchEvent
{
uint8_t touchingLeft : 1; // bit flags relating to regular touch devices, relates to TOUCH_BIT_FLAGS_XXX above
uint8_t touchingRight : 1;
uint8_t unused : 1;
uint8_t inrange : 1;
}touchEvent;
}de;
uint8_t deltaBits; // a bit mask to indicate which bits are changed since last _digitiserEvent
uint8_t validBits; // a bit mask to indicate which bits are supported by the originating hardware
int32_t screenx; // screen co-ordinate values, these values are in screen pixels and take account of the co-ordinate range of the associated monitors
int32_t screeny; // so for example with 2 monitors, resolution 1024 x 768 side by side; with the left monitor being the primary,
// touching the centre of the right gives about 1536, 384
int32_t internalx; // the corresponding windows co-ordinate value, the primary monitor has the range 0xffff, and other monitors are scaled from that
int32_t internaly; // so in the example given above the result is 0x17fee, 0x7fff
int32_t calx; // the calibrated co-ordinates values; a value from 0 - 0xffff, giving the absolute position of touch in the range of the originating hardware
int32_t caly; // so for example touching the centre of a screen will give around 0x7fff regardless of the associated monitor
TBBOOL zSupport; // set to TRUE (1) if the originating hardware supports z values
uint32_t z; // the raw z value reported by the controller, typically this is used to indicate pressure
TBBOOL isTimed; // set to TRUE (1) if the event is triggered by a timeout (eg liftoff time)
TBBOOL isToolbar; // set to TRUE (1) if the event is for a touch start started in a toolbar
TBBOOL stylusSupport; // set to TRUE (1) if the originating hardware supports stylus values
uint8_t digitizerType; // see DIGITIZER_TYPE_xxx
TBBOOL lastContact; // set to TRUE (1) if the event is triggered by the last contact in a touch event from the source device
int32_t internal_event_number; // for internal use only
uint32_t contact_width;
uint32_t contact_height;
int8_t xtilt;
int8_t ytilt;
int32_t rawx; // the raw X value from the controller
int32_t rawy; // the raw Y value from the controller
}digitiserEvent;
struct _xy // co-ordinate data
{
int32_t rawx; // the raw X value from the controller
int32_t rawy; // the raw Y value from the controller
int32_t calx; // the corresponding calibrated value
int32_t caly; // --- ditto ---
int32_t calx_rotated; // the corresponding calibrated unrotated value (for toolbars)
int32_t caly_rotated; // --- ditto ---
int32_t screenx; // the corresponding screen co-ordinate value
int32_t screeny; // --- ditto ---
int32_t internalx; // the corresponding windows co-ordinate value
int32_t internaly; // --- ditto ---
}xy;
struct _z // pressure data
{
uint32_t rawz; // the raw z value from the controller
}z;
struct _logicalEvent
{
TBBOOL left; // does this represent a left mouse button action
TBBOOL state; // the value that the state changed to
TBBOOL timed; // whether the change is triggered by a timeout (eg liftoff time)
// TBBOOL wasToolbarTouch; // was the touch in a toolbar area when the state change to true
}logicalEvent;
struct _physicalEvent
{
TBBOOL state; // the value that the state changed to
TBBOOL timed; // whether the change is triggered by a timeout (eg liftoff time)
// TBBOOL wasToolbarTouch; // was the touch in a toolbar area when the state change to true
}physicalEvent;
// following structure is obsolescent; you should use _touchEvent instead
// but currently still supported in the api so you can uncomment this if needed; however we recommend converting to _touchEvent
//struct _flagsEvent
//{
// TBBOOL hasEVNN; // true if the evnn field has valid data
// uint32_t evnn; // value of the EVNN bits in the data packet
// TBBOOL hasLBit; // true if the lBit field has valid data
// TBBOOL lBit; // value of the L bit in the data packet
// TBBOOL hasRBit; // true if the rBit field has valid data
// TBBOOL rBit; // value of the R bit in the data packet
//}flagsEvent;
struct _raw // raw data
{
uint8_t byte[64];
}raw;
struct _toolbar // a toolbar area was touched
{
int16_t htoolbar; // tooolbar handle
int16_t row; // row # of cell
int16_t column; // column # of cell
uint8_t touching; // true (1) if a physical touch is active
uint8_t on; // true (1) if the cell is "on"
// for a non-latched toolbar a cell is on while it is being touched
// a latched toolbar' cell toggles between the on & off states with each touch
}toolbar;
struct _interactiveTouch // co-ordinate data
{
uint32_t ticks; // ticks since touch
uint32_t maxTicks; // tick count at which icon change will occur
}interactiveTouch ;
struct _sound
{
uint32_t fileIndex;
uint32_t reserved1;
uint32_t reserved2;
}sound;
struct _eval
{
uint16_t clicksRemaining;
uint32_t packageExpired;
}eval;
//struct _mouseEvent mouseEvent;
//struct _rawMouseEvent rawMouseEvent;
#ifdef UPDD_GESTURES
#include "gestures_event.inl"
#endif
struct _config
{
uint16_t configEventType;
uint16_t configEventLevel;
union _ce
{
uint8_t configText[64 - sizeof(uint32_t)];
uint32_t signalValue;
}ce;
struct _internal
{
uint32_t v1;
uint32_t v2;
uint32_t v3;
}internal;
int64_t originatingPID;
}config;
}pe;
};
#ifndef __cplusplus
typedef struct _HIDPacket _HIDPacket;
#endif
#define UPDD_VHID_REPORT_ID_TOUCH 1
#define UPDD_VHID_REPORT_ID_KEYBOARD 2
#define UPDD_VHID_REPORT_ID_TOUCH_MOUSE 3
#define UPDD_VHID_REPORT_ID_PEN 6
#define UPDD_VHID_REPORT_ID_REGULAR_MOUSE 4
#define UPDD_VHID_MAX_X 32767
#define UPDD_VHID_MAX_Y 32767
struct _HIDPacket
{
uint8_t report_id;
union _h
{
struct _touch
{
struct _contact
{
uint8_t touching : 1;
uint8_t unused:2;
uint8_t contact_number:5;
uint16_t x;
uint16_t unused_2;
uint16_t y;
uint16_t w;
uint16_t h;
}contact[5];
uint8_t scan_rate;
uint8_t unused;
uint8_t contact_count;
}touch;
struct _pen
{
uint8_t in_range : 1;
uint8_t invert : 1;
uint8_t unused : 1;
uint8_t eraser : 1;
uint8_t barrel : 1;
uint8_t tip : 1;
uint16_t x;
uint16_t y;
uint16_t z;
uint16_t unused_2;
uint8_t dummy[10];
}pen;
struct _touch_mouse
{
uint8_t button_left : 1;
uint8_t button_right : 1;
uint8_t button_middle : 1;
uint8_t unused : 5;
uint16_t x;
uint16_t y;
}touch_mouse;
struct _regular_mouse
{
uint8_t button_left : 1;
uint8_t button_right : 1;
uint8_t button_middle : 1;
uint8_t unused : 5;
int8_t x;
int8_t y;
}regular_mouse;
struct _keyboard
{
uint8_t modifier_lctrl : 1;
uint8_t modifier_lshift : 1;
uint8_t modifier_lalt : 1;
uint8_t modifier_lmeta : 1;
uint8_t modifier_rctrl : 1;
uint8_t modifier_rshift : 1;
uint8_t modifier_ralt : 1;
uint8_t modifier_rmeta : 1;
uint8_t unused;
uint8_t key[6];
uint8_t unused2[50];
}keyboard;
}h;
};
#pragma pack (pop)
#endif // TBAPIDEFNS_H
#ifndef DRIVERSTRINGS
//function pointer definition for data callback
#ifdef ENVIRONMENT64
typedef void (TBCALL *TB_EVENT_CALL)(unsigned long long context, _PointerEvent* aEvent);
#else
typedef void (TBCALL* TB_EVENT_CALL)(unsigned long context, _PointerEvent* aEvent);
#endif
//function pointer definition for event source
typedef void (TBCALL* TB_EVENT_CALL_SOURCE)(_PointerEvent* aEvent);
// V6 Migration note TBApiInit, TBApiInitEx, TBApiTerminate and TBApiDefaultSettingsPath are no longer used
//void TBAPI TBApiOpen(int argc, char* argv[]);
void TBAPI TBApiOpen();
// Establishes a connection to the device driver
// most API functions require an open connection
// NB only call this once in your program, typically at startup
// note that the connection to the driver is performed asynchronously
// use TBApiIsDriverConnected to check the status of the connection
void TBAPI TBApiClose();
// Closes the connection to the device driver
// NB only call this once in your program, typically at termination
TBBOOL TBAPI TBApiIsDriverConnected();
// Returns a TBBOOL indication of whether a driver connection is in place
// ie has TBApiOpen been sucessfully actioned.
// NB because this API dispatches Qt events, this should only be used in a Qt application before
// any signal / slot connections are made, non-Qt applications are not subject to this limitation
// to get the same functionality in a Qt application after any signal / slot connections are made
// use TBApiIsDriverConnectedNoDispatch
TBBOOL TBAPI TBApiIsDriverConnectedNoDispatch();
// funtionally identical to TBApiIsDriverConnected but implemented to be safe to use
// in Qt applications after any signal / slot connections are made
TBBOOL TBAPI TBApiGetDriverVersion(TBCHAR* aVersion);
// returns -- 0 = fail, 1 = OK
// aVersion must point to an address to receive the version number of the driver, 16 bytes should be allocated
void TBAPI TBApiGetApiVersion(TBCHAR* aVersion);
// aVersion must point to an address to receive the version number of the API, 16 bytes should be allocated
// --------------------------------------------------------------- //
// a number of functions require a device id //
// the following family of functions provide valid device id's //
// --------------------------------------------------------------- //
//
HTBDEVICE TBAPI TBApiGetRelativeDevice(int o);
// this api simply gets the device by it's order in the internal device list
// typically used to get the only device in a single device system eg
//
// HTBDEVICE device = TBApiGetRelativeDevice(0);
//
// or to enumerate all devices eg
//
// HTBDEVICE device = TBApiGetRelativeDevice(0);
// for(int i=0; device != TB_INVALID_HANDLE_VALUE;)
// {
// DoSomethingWithDevice(device);
// device = TBApiGetRelativeDevice(++i);
// }
//
// a return value of TB_INVALID_HANDLE_VALUE means that the requested device does not exist
int TBAPI TBApiGetRelativeDeviceFromHandle( HTBDEVICE aDeviceHandle);
// this api performs the opposite role to TBApiGetRelativeDevice
// Given a Device handle the (zero based) position in the list is returned
// a return value of -1 means that the requested device does not exist
HTBDEVICE TBAPI TBApiGetRelativeDeviceExcludeHidden(int o);
TBBOOL TBAPI TBApiGetRotate(HTBDEVICE aDeviceHandle, int32_t* aRotate);
// returns (in aRotate) the rotation factor associated with the device
// returns -- 0 = fail, 1 = OK
//
TBBOOL TBAPI TBApiMousePortInterfaceEnable(HTBDEVICE UNUSED, TBBOOL aState);
// Enable / disables the mouse port interface
// if the mouse port interface is disabled, the driver functions
// normally, except that the mouse pointer is not moved and
// mouse button clicks are not emulated. Data can be read via the api
// returns -- 0 = fail, 1 = OK
#ifdef ENVIRONMENT64
TBBOOL TBAPI TBApiRegisterEvent(HTBDEVICE aDeviceHandle, unsigned long long aContext, unsigned long aTypes, TB_EVENT_CALL aFunc);
#else
TBBOOL TBAPI TBApiRegisterEvent(HTBDEVICE aDeviceHandle, unsigned long aContext, unsigned long aTypes, TB_EVENT_CALL aFunc);
#endif
// Informs the API that a function is to be used a callback function for
// the specified type(s) of data
// The context value is passed unchanged to the callback function for identification purposes
// All functions registered MUST be unregistered with TBApiUnregisterEvent
// before the program terminates
//
// In the following example CBFunc is called whenever pointer co-ordinates are processed
// by relative device 1 until TBApiUnregisterEvent is called
//
// **USAGE NOTE**
// the callback function is executed in the context of a dedicated thread
// therefore only thread safe (reentrant) functions should be called from the callback function
// many windowing api functions are non-reentrant
// if you need to call non-reentrant functions you need to provide synchronisation management
// a common way to achieve this is to post a message to the primary process thread and perform
// all non-reentrant operations from the primary thread
//
// example 1; register callback for the first device found
//
// HTBDEVICE hd = TBApiGetRelativeDevice(0);
//
// TBApiRegisterEvent(hd,0,_EventTypeXY,CBFunc);
//
// .....
//
// void TBAPI CBFunc(unsigned long context, _PointerData* data)
// {
// printf("device %d generated x=%d y=%d\n",(int)data->device,(int)data->xy->rawx,(int)data->xy->rawy);
// }
//
// To get data for all devices 0
//
// example 2; register callback for all devices
//
// TBApiRegisterEvent(0,0,_EventTypeXY,CBFunc);
//
// returns -- 0 = fail, 1 = OK
TBBOOL TBAPI TBApiRegisterCallbackAsTouchDelegate(TB_EVENT_CALL aFunc);
// Indicate that the specified callback function is to receive delegated touch events only //
// returns -- 0 = fail, 1 = OK
TBBOOL TBAPI TBApiUnregisterEvent(TB_EVENT_CALL aFunc);
// Removes the specified function from the list of registered callbacks.
//
// eg to unregister the callback specified in the above example
//
// TBApiUnregisterEvent(CBFunc);
//
// returns -- 0 = fail, 1 = OK
TBBOOL TBAPI TBApiUnregisterEventContext(unsigned long aContext);
// Removes the specified context from the list of registered callbacks.
//
// eg to unregister the callback specified in the above example
//
// TBApiUnregisterEvent(0);
//
// returns -- 0 = fail, 1 = OK
// a set of functions to set / retrieve UPDD settings
TBBOOL TBAPI TBApiGetSetting(HTBDEVICE aHandle,const TBCHAR* aName, TBCHAR* aSZ, int lBuff);
TBBOOL TBAPI TBApiGetSettingAsInt(HTBDEVICE aHandle,const TBCHAR* aName, int32_t* val);
TBBOOL TBAPI TBApiSetSetting(HTBDEVICE aHandle, const TBCHAR* aName, const TBCHAR* aSZ, TBBOOL aDeviceSpecific);
TBBOOL TBAPI TBApiSetSettingFromInt(HTBDEVICE aHandle, const TBCHAR* aName, int32_t val, TBBOOL aDeviceSpecific);
// set the default value of a setting for a specified controller handle
// controller handle can be "*" for all controllers
// any non-default value is cleared,IE this value becomes effective for any device instances of this controller type
TBBOOL TBAPI TBApiSetDefault(const TBCHAR* aController, const TBCHAR* aSetting, const TBCHAR* aValue);
// this variant retrieves the default setting for the controller type as opposed to a specific installed instance of the controller
TBBOOL TBAPI TBApiGetControllerSetting(int aControllerHandle, const TBCHAR* aName, TBCHAR* aSZ, int lBuff);
// this variant gets a setting from the bootstrap file updd.ini given the section and setting name
// it is available before a driver connection is available
void TBAPI TBApiGetBootstrapSetting(const TBCHAR* aSection, const TBCHAR* aName, TBCHAR* aSZ, int lBuff);
TBBOOL TBAPI TBApiRemove(HTBDEVICE aHandle, const TBCHAR* aName);
// get the length of buffer needed to hold any setting as a NULL terminated string
TBBOOL TBAPI TBApiGetSettingSize(HTBDEVICE aHandle, const TBCHAR* aName, int* lBuff);
TBBOOL TBAPI TBApiGetControllerSettingSize(HTBDEVICE aHandle, const TBCHAR* aName, int* lBuff);
// add a new controller to the device list
// aControllerID : the handle of the controller definition as, for example returned by upddutils controllers
// aDeviceName : a name to identify the entry, pass NULL to assign an auto generated id
// aNewHandle : address to receive he new device handle, can be NULL
TBBOOL TBAPI TBApiAddDevice(int aControllerID, const TBCHAR* aDeviceName, HTBDEVICE* aNewHandle);
TBBOOL TBAPI TBApiDeleteDevice(HTBDEVICE aDevice);
void TBAPI TBApiEnableApiTrace(TBBOOL aEnable);
TBBOOL TBAPI TBApiPostPacketBytes(HTBDEVICE aDevice, const char* aData);
TBBOOL TBAPI TBApiPostPacketBytesEx(HTBDEVICE aDevice, const char* aData, uint32_t aTimestamp);
// generate a touch on the selected device
// aDevice the handle to the device to be used
// x the x co-ordinate to be posted
// x the y co-ordinate to be posted
// st the sylus or contact number for multi touch
// touching: true to start or continue a touch: false ends a touch if one is active
// the x and y range depends on the controller definition,
// NB this api operates asynchronously
TBBOOL TBAPI TBApiInjectTouch(HTBDEVICE aDevice, int x, int y, int st, TBBOOL touching);
#ifdef UPDD_API_ALPHA // alpha test api's implemented but subject to change do not rely on this being unchanged in a subsequent build
TBBOOL TBAPI TBApiInjectTouchEx(HTBDEVICE aDevice, uint32_t x, uint32_t y, uint32_t st, TBBOOL touching, uint64_t aInjectFlags);
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
/// get the position of the primary monitor
/// and the position and size of a monitor associated with a specified updd device
// ** OBSOLETE
// use the following instead
//int32_t m;
//TBApiGetSettingAsInt(aDevice, "monitor_number", &m);
//TBApiGetMonitorMetricsForMonitor(m,....)
////////////////////////////////////////////////////////////////////////////////////////////////////
//void TBAPI TBApiGetMonitorMetrics(unsigned aDevice,
// long* aPrimaryMonitorWidth, long* aPrimaryMonitorHeight,
// long* aMonitorWidth, long* aMonitorHeight, long* aMonitorLeft, long* aMonitorTop);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// get the position and size of a monitor
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetMonitorMetricsForMonitor(unsigned aMonitor,
long* aMonitorWidth, long* aMonitorHeight, long* aMonitorLeft, long* aMonitorTop);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// get extended info about an api error, currently only applicable to TBApiReadEEPROM / TBApiWriteEEPROM
////////////////////////////////////////////////////////////////////////////////////////////////////
void TBAPI TBApiGetLastError(TBCHAR* aMsg, int aMaxLength);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// record a program as running or check if already running
// mainly used to limit client applications to a single instance
//
// arguments:-
// aProgramName: a name to uniquley identify the program
// aRegisterAsRunning: if true then record the current process along with the specified name in the list of running programs
// aFailIfRunning: if true and another instance of the named program is running the api call is failed
// the api call returns false and the process is not recorded in the running list
// aSignalRunningApps: it true, an event of type _EventConfiguration is sent to existing instancesof the named program
// the field configEventType is set to CONFIG_EVENT_CONCURRENCY_SIGNAL
//
// Example:
// int main(...)
// {
// ...
// if (!TBApiRegisterProgram("UPDD Daemon", true, true, false))
// {
// TBApiClose();
// return(1);
// }
//
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiRegisterProgram(const TBCHAR* aProgramName,TBBOOL aRegisterAsRunning, TBBOOL aFailIfRunning, TBBOOL aSignalRunningApps);
TBBOOL TBAPI TBApiRegisterProgramEx(const TBCHAR* aProgramName, TBBOOL aRegisterAsRunning, TBBOOL aFailIfRunning, TBBOOL aSignalRunningApps, uint8_t aPriority);
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiLicence(const TBCHAR* aLicenceKey);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// pass PointerEvent callback to registered client apps
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiPostPointerEvent(_PointerEvent* aEvent);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// is device connected TRUE / FALSE
/// for RS232 devices this refers to whether the driver has an open connection to the com port
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiIsDeviceConnected(HTBDEVICE aDeviceHandle, TBBOOL* aConnected);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// get the maximum theoretical Z value
////////////////////////////////////////////////////////////////////////////////////////////////////
// obsolete
//TBBOOL TBAPI TBApiGetMaxZ(HTBDEVICE aHandle, int32_t* aMaxZ);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// issue an HID set feature request to the device
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiHidSetFeature(
HTBDEVICE aHandle,
int aInterface,
const void* aReportBuffer,
uint32_t aReportBufferLength
);
////////////////////////////////////////////////////////////////////////////////////////////////////
/// issue an HID get feature request to the device
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiHidGetFeature(
HTBDEVICE aDevice,
int aInterface,
void* aReportBuffer,
uint32_t aReportBufferLength
);
////////////////////////////////////////////////////////////////////////////////////////////////////
// get the names of all settings matching a pattern
// aIncludeUnused: if true (1) indicates that all known matching names are to be returned as opposed to those currently used in the package
// if a null value is passed for aSZ, the return value addressed by lBuff will be set to the required buffer size
// the list of names is returned as a multi line string (separated by '\n' characters)
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetSettings(HTBDEVICE aHandle, TBBOOL aIncludeUnused, const TBCHAR* aPattern, TBCHAR* aSZ, int* lBuff);
////////////////////////////////////////////////////////////////////////////////////////////////////
// get the help text associated with a named setting
// if a null value is passed for aSZ, the return value addressed by lBuff will be set to the required buffer size
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetSettingHelp(const TBCHAR* aName, TBCHAR* aSZ, int* lBuff);
////////////////////////////////////////////////////////////////////////////////////////////////////
// launch the calibration tool
// mode must be one of: calibrate
// identify
// toolbar
// configure
// for calibrate a device handle is required toolbar index is ignored
// for identify device handle and toolbar index are ignored
// for configure device handle and toolbar index are ignored
// for toolbar both are required
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiCalibrate(HTBDEVICE aHandle, int aToolbarIndex, TBCHAR* aMode);
////////////////////////////////////////////////////////////////////////////////////////////////////
// export settings
// aDevices is a comma separate list of device handles to support OR * for all real (non zero) devices OR ** for all devices + NODEVICE
// aNames is a comma separated list of setting names to export; can use standard wildcard characters * or ?
// aTargetFileName is the path to the export file
// aFailIfExists if true and the target file exists the API call will fail (return false)
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiExportSettings(const TBCHAR* aDevices, const TBCHAR* aNames, const TBCHAR* aTargetFileName, TBBOOL aFailIfExists);
////////////////////////////////////////////////////////////////////////////////////////////////////
// import settings previouly exported by TBApiExportSettings
// aSourceFileName is the path to the import file
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiImportSettings(const TBCHAR* aSourceFileName);
////////////////////////////////////////////////////////////////////////////////////////////////////
// an alternate means to retrieve settings
// this implementation is more performant than TBApiGetSetting and its variants
// all values that match aPattern are retrieved in one call to the driver when aIndex == 0
// the internal storage is released when aIndex >= number of values
// so it is important to always start with aIndex=0
// due to the cached storage this function is NOT thread safe
// a previous cache allocation will be deleted if aIndex == 0
// when aIndex == number of values TRUE is returned and an empty string is given in aName and aValue
// in the event that the buffers passed are too small for a name or value FALSE is returned
// and TBApiGetLastError will give "Error: Insufficient buffer size"
//
// Example:
//
// Prints all nodevice settings starting with "m"
//
// char name[256];
// char value[1024];
// for (unsigned n = 0; ; n++)
// {
// if (!TBApiGetSettingByIndex(0, "m*", n, name, sizeof(name), value, sizeof(value)))
// {
// char msg[1024];
// TBApiGetLastError(msg, sizeof(msg));
// cerr << msg << endl;
// break;
// }
// if (!strlen(name))
// {
// break;
// }
// cout << name << ": " << value << endl;
// }
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetSettingByIndex(HTBDEVICE aHandle, const TBCHAR* aPattern, uint16_t aIndex, TBCHAR* aName, int lName, TBCHAR* aValue, int lValue);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Reset settings to original values excluding reserved values such as registration, device binding
// internal (private.*) and device counts
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiResetSettings();
TBBOOL TBAPI TBApiGetSettingByIndex(HTBDEVICE aHandle, const TBCHAR* aPattern, uint16_t aIndex, TBCHAR* aName, int lName, TBCHAR* aValue, int lValue);
////////////////////////////////////////////////////////////////////////////////////////////////////
// get a toolbar based on it's (zero based) index
// a return value of TB_INVALID_HANDLE_VALUE means that a toolbar does not exist at the
// specified index
////////////////////////////////////////////////////////////////////////////////////////////////////
HTBTOOLBAR TBAPI TBApiGetRelativeToolbar(int o);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Create a new toolbar, default values are use for the required fields not found in the argument
// list, to provide values for these fields use TBApiSetToolbarSetting
// note that, unlike earlier implementations, the returned handle is immutable
// so can be used as a permanent reference to this toolbar
//
// the default values applied are
// columns=1
// rows=1
// off_screen=0
// enabled=1
// monitor_number=1
// latched=0
// hold_touch=1
// active_whilst_calibrating=0
//
////////////////////////////////////////////////////////////////////////////////////////////////////
HTBTOOLBAR TBAPI TBApiAddToolbar(const TBCHAR* aName, uint16_t x, uint16_t y, uint16_t width, uint16_t height);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Delete a toolbar
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiRemoveToolbar(HTBTOOLBAR aToolbarHandle);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Get a named setting for a toolbar as a string
// the string buffer (aSZ) must be large enough to hold the returned value + a terminating null byte
// this size of this buffer must be specified in lBuff
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetToolbarSetting(HTBTOOLBAR aToolbarHandle, const TBCHAR* aName, TBCHAR* aSZ, int lBuff);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Get a named setting for a toolbar as a signed int
// note, this is a convenience function only, all settings are held internally as strings
// and can be retrieved with TBApiGetToolbarSetting
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiGetToolbarSettingAsInt(HTBTOOLBAR aToolbarHandle, const TBCHAR* aName, int32_t* val);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Set a named setting for a toolbar
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiSetToolbarSetting(HTBTOOLBAR aToolbarHandle, const TBCHAR* aName, const TBCHAR* aSZ);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Enable a toolbar based on the passed handle or pass 0 to enable all toolbars
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiEnableToolbars(HTBTOOLBAR aToolbarHandle);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Enable a toolbar based on the passed handle or pass 0 to disable all toolbars
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiDisableToolbars(HTBTOOLBAR aToolbarHandle);
////////////////////////////////////////////////////////////////////////////////////////////////////
// A pair of functions to simply dispatching of api callback events to the primary thread
// This is particularly useful in more complicated applications and allows this logic to
// implemented on a per application basis wihout losing the flexibility of the api's
// dispatching features
// Create a callback function of type TB_EVENT_CALL_SOURCE and pass its address to TBApiRegisterEventSource
// This function should post every received event for processing in the application's primary thread
// using a client appropriate method.
// The receiving handler in the primary thread should pass the received values to TBApiEventSink
// Having done so, callbacks registered with TBApiRegisterEvent will execute in the primary thread context
////////////////////////////////////////////////////////////////////////////////////////////////////
TBBOOL TBAPI TBApiRegisterEventSource(TB_EVENT_CALL_SOURCE aFunc);
#ifdef ENVIRONMENT64
TBBOOL TBAPI TBApiEventSink(unsigned long long context, _PointerEvent* aEvent);
#else
TBBOOL TBAPI TBApiEventSink(unsigned long context, _PointerEvent* aEvent);
#endif
TBBOOL TBAPI TBApiPostHIDPacket(HTBDEVICE aHandle, TBBOOL aDirect, _HIDPacket* aPacket);
#endif // DRIVERSTRINGS
#ifdef __cplusplus
} // extern "C"
#endif
#ifdef TBAPIDLL_EXPORTS
#ifdef _WIN32
#pragma warning(default:4518)
#endif
#endif
#endif