Add minimal wintab32 support

This commit is contained in:
Anaël Seghezzi 2019-03-06 11:57:17 +01:00
parent 2fbb560eb7
commit 79ac263771
7 changed files with 380 additions and 0 deletions

View File

@ -1510,6 +1510,57 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,int);
*/ */
typedef void (* GLFWjoystickfun)(int,int); typedef void (* GLFWjoystickfun)(int,int);
/*! @brief The function signature for pen tablet data callbacks.
*
* This is the function signature for pen tablet data callback functions.
*
* @param[in] x pen position relative to the screen.
* @param[in] y pen position relative to the screen.
* @param[in] z pen position relative to the tablet.
* @param[in] pen pressure from 0.0 to 1.0.
* @param[in] pen pitch in degree.
* @param[in] pen yaw in degree.
* @param[in] pen roll in degree.
*
* @sa @ref pen_tablet_data
* @sa @ref glfwSetPenTabletDataCallback
*
* @since Added in version 3.3.
*
* @ingroup input
*/
typedef void (* GLFWpentabletdatafun)(double,double,double,double,double,double,double);
/*! @brief The function signature for pen tablet cursor callbacks.
*
* This is the function signature for pen tablet cursor callback functions.
*
* @param[in] pen cursor identifier.
*
* @sa @ref pen_tablet_cursor
* @sa @ref glfwSetPenTabletCursorCallback
*
* @since Added in version 3.3.
*
* @ingroup input
*/
typedef void (* GLFWpentabletcursorfun)(unsigned int);
/*! @brief The function signature for pen tablet proximity callbacks.
*
* This is the function signature for pen tablet proximity callback functions.
*
* @param[in] pen proximity state.
*
* @sa @ref pen_tablet_proximity
* @sa @ref glfwSetPenTabletProximityCallback
*
* @since Added in version 3.3.
*
* @ingroup input
*/
typedef void (* GLFWpentabletproximityfun)(int);
/*! @brief Video mode type. /*! @brief Video mode type.
* *
* This describes a single video mode. * This describes a single video mode.
@ -4963,6 +5014,72 @@ GLFWAPI const char* glfwGetGamepadName(int jid);
*/ */
GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state);
/*! @brief Sets the pen tablet data callback.
*
* This function sets the pen tablet data callback, or removes the
* currently set callback. This is called when the pen tablet data is updated.
*
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref pen_tablet_event
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI GLFWpentabletdatafun glfwSetPenTabletDataCallback(GLFWpentabletdatafun cbfun);
/*! @brief Sets the pen tablet cursor callback.
*
* This function sets the pen tablet cursor callback, or removes the
* currently set callback. This is called when the pen tablet cursor has changed.
*
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref pen_tablet_event
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI GLFWpentabletcursorfun glfwSetPenTabletCursorCallback(GLFWpentabletcursorfun cbfun);
/*! @brief Sets the pen tablet proximity callback.
*
* This function sets the pen tablet proximity callback, or removes the
* currently set callback. This is called when the pen tablet proximity has changed.
*
* @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback.
* @return The previously set callback, or `NULL` if no callback was set or the
* library had not been [initialized](@ref intro_init).
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref pen_tablet_event
*
* @since Added in version 3.3.
*
* @ingroup input
*/
GLFWAPI GLFWpentabletproximityfun glfwSetPenTabletProximityCallback(GLFWpentabletproximityfun cbfun);
/*! @brief Sets the clipboard to the specified string. /*! @brief Sets the clipboard to the specified string.
* *
* This function sets the system clipboard to the specified, UTF-8 encoded * This function sets the system clipboard to the specified, UTF-8 encoded

View File

@ -401,6 +401,29 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
js->hats[hat] = value; js->hats[hat] = value;
} }
// Notifies shared code of the new value of the pen tablet data
//
void _glfwInputPenTabletData(double x, double y, double z, double pressure, double pitch, double yaw, double roll)
{
if (_glfw.callbacks.pentabletdata)
_glfw.callbacks.pentabletdata(x, y, z, pressure, pitch, yaw, roll);
}
// Notifies shared code of the new value of the pen tablet cursor
//
void _glfwInputPenTabletCursor(unsigned int cursor)
{
if (_glfw.callbacks.pentabletcursor)
_glfw.callbacks.pentabletcursor(cursor);
}
// Notifies shared code of the new value of the pen tablet proximity
//
void _glfwInputPenTabletProximity(int proximity)
{
if (_glfw.callbacks.pentabletproximity)
_glfw.callbacks.pentabletproximity(proximity);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
@ -1294,6 +1317,27 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
return GLFW_TRUE; return GLFW_TRUE;
} }
GLFWAPI GLFWpentabletdatafun glfwSetPenTabletDataCallback(GLFWpentabletdatafun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.pentabletdata, cbfun);
return cbfun;
}
GLFWAPI GLFWpentabletcursorfun glfwSetPenTabletCursorCallback(GLFWpentabletcursorfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.pentabletcursor, cbfun);
return cbfun;
}
GLFWAPI GLFWpentabletproximityfun glfwSetPenTabletProximityCallback(GLFWpentabletproximityfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.pentabletproximity, cbfun);
return cbfun;
}
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
{ {
assert(string != NULL); assert(string != NULL);

View File

@ -567,6 +567,9 @@ struct _GLFWlibrary
struct { struct {
GLFWmonitorfun monitor; GLFWmonitorfun monitor;
GLFWjoystickfun joystick; GLFWjoystickfun joystick;
GLFWpentabletdatafun pentabletdata;
GLFWpentabletcursorfun pentabletcursor;
GLFWpentabletproximityfun pentabletproximity;
} callbacks; } callbacks;
// This is defined in the window API's platform.h // This is defined in the window API's platform.h
@ -728,6 +731,10 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value);
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement); void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement);
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window); void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window);
void _glfwInputPenTabletData(double x, double y, double z, double pressure, double pitch, double yaw, double roll);
void _glfwInputPenTabletCursor(unsigned int cursor);
void _glfwInputPenTabletProximity(int proximity);
#if defined(__GNUC__) #if defined(__GNUC__)
void _glfwInputError(int code, const char* format, ...) void _glfwInputError(int code, const char* format, ...)
__attribute__((format(printf, 2, 3))); __attribute__((format(printf, 2, 3)));

View File

@ -159,6 +159,21 @@ static GLFWbool loadLibraries(void)
GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo"); GetProcAddress(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
} }
_glfw.win32.wintab32.instance = LoadLibraryA("Wintab32.dll");
if (_glfw.win32.wintab32.instance)
{
_glfw.win32.wintab32.WTInfoA = (PFN_WTInfoA)
GetProcAddress(_glfw.win32.wintab32.instance, "WTInfoA");
_glfw.win32.wintab32.WTOpenA = (PFN_WTOpenA)
GetProcAddress(_glfw.win32.wintab32.instance, "WTOpenA");
_glfw.win32.wintab32.WTQueueSizeSet = (PFN_WTQueueSizeSet)
GetProcAddress(_glfw.win32.wintab32.instance, "WTQueueSizeSet");
_glfw.win32.wintab32.WTClose = (PFN_WTClose)
GetProcAddress(_glfw.win32.wintab32.instance, "WTClose");
_glfw.win32.wintab32.WTPacket = (PFN_WTPacket)
GetProcAddress(_glfw.win32.wintab32.instance, "WTPacket");
}
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -186,6 +201,9 @@ static void freeLibraries(void)
if (_glfw.win32.ntdll.instance) if (_glfw.win32.ntdll.instance)
FreeLibrary(_glfw.win32.ntdll.instance); FreeLibrary(_glfw.win32.ntdll.instance);
if (_glfw.win32.wintab32.instance)
FreeLibrary(_glfw.win32.wintab32.instance);
} }
// Create key code translation tables // Create key code translation tables
@ -327,6 +345,46 @@ static void createKeyTables(void)
} }
} }
// Init wintab context see https://developer-docs.wacom.com/display/DevDocs/Windows+Wintab+Documentation
//
static void initWintabContext(HWND hwnd)
{
if (_glfw.win32.wintab32.instance) {
LOGCONTEXTA context = {0};
_glfw.win32.wintab32.WTInfoA(4, 0, &context);
context.lcPktData = 0x0080 | 0x0100 | 0x0200 | 0x0040 | 0x0400 | 0x1000 | 0x0008 | 0x0020; // X Y Z BUTTONS NPRESSURE ORIENTATION CHANGED CURSOR
context.lcPktMode = 0;
context.lcMoveMask = context.lcPktData;
context.lcBtnUpMask = context.lcBtnDnMask;
context.lcOptions |= 0x0004; // CXO MESSAGES
context.lcOutOrgX = context.lcInOrgX;
context.lcOutOrgY = context.lcInOrgY;
context.lcOutExtX = context.lcInExtX;
context.lcOutExtY = -context.lcInExtY;
// open wintab context
_glfw.win32.wintab32.context = _glfw.win32.wintab32.WTOpenA(hwnd, &context, TRUE);
if (_glfw.win32.wintab32.context) {
_glfw.win32.wintab32.WTQueueSizeSet(_glfw.win32.wintab32.context, 256);
_glfw.win32.wintab32.WTInfoA(4, 0, &_glfw.win32.wintab32.contextInfo);
_glfw.win32.wintab32.WTInfoA(100, 15, &_glfw.win32.wintab32.pressureInfo);
_glfw.win32.wintab32.WTInfoA(100, 17, &_glfw.win32.wintab32.orientationInfo);
}
}
else {
_glfw.win32.wintab32.context = 0;
}
}
// Terminate wintab context
//
static void terminateWintabContext(void)
{
if (_glfw.win32.wintab32.instance && _glfw.win32.wintab32.context)
_glfw.win32.wintab32.WTClose(_glfw.win32.wintab32.context);
}
// Creates a dummy window for behind-the-scenes work // Creates a dummy window for behind-the-scenes work
// //
static HWND createHelperWindow(void) static HWND createHelperWindow(void)
@ -577,6 +635,7 @@ int _glfwPlatformInit(void)
_glfwInitTimerWin32(); _glfwInitTimerWin32();
_glfwInitJoysticksWin32(); _glfwInitJoysticksWin32();
initWintabContext(_glfw.win32.helperWindowHandle);
_glfwPollMonitorsWin32(); _glfwPollMonitorsWin32();
return GLFW_TRUE; return GLFW_TRUE;
@ -604,6 +663,7 @@ void _glfwPlatformTerminate(void)
_glfwTerminateEGL(); _glfwTerminateEGL();
_glfwTerminateJoysticksWin32(); _glfwTerminateJoysticksWin32();
terminateWintabContext();
freeLibraries(); freeLibraries();
} }

View File

@ -258,6 +258,78 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,
typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG); typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_ #define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
// wintab.dll function pointer typedefs
#define WT_PACKET 0x7FF0
#define WT_PROXIMITY 0x7FF5
DECLARE_HANDLE(HCTX);
typedef struct tagAXIS {
LONG min;
LONG max;
UINT units;
DWORD resolution;
} AXIS;
typedef struct tagORIENTATION {
int azimuth;
int altitude;
int twist;
} ORIENTATION;
typedef struct tagPACKET {
DWORD changed;
UINT cursor;
DWORD buttons;
DWORD x;
DWORD y;
DWORD z;
UINT normalPressure;
ORIENTATION orientation;
} PACKET;
typedef struct LOGCONTEXTA {
char lcName[40];
UINT lcOptions;
UINT lcStatus;
UINT lcLocks;
UINT lcMsgBase;
UINT lcDevice;
UINT lcPktRate;
DWORD lcPktData;
DWORD lcPktMode;
DWORD lcMoveMask;
DWORD lcBtnDnMask;
DWORD lcBtnUpMask;
LONG lcInOrgX;
LONG lcInOrgY;
LONG lcInOrgZ;
LONG lcInExtX;
LONG lcInExtY;
LONG lcInExtZ;
LONG lcOutOrgX;
LONG lcOutOrgY;
LONG lcOutOrgZ;
LONG lcOutExtX;
LONG lcOutExtY;
LONG lcOutExtZ;
DWORD lcSensX;
DWORD lcSensY;
DWORD lcSensZ;
BOOL lcSysMode;
int lcSysOrgX;
int lcSysOrgY;
int lcSysExtX;
int lcSysExtY;
DWORD lcSysSensX;
DWORD lcSysSensY;
} LOGCONTEXTA, *PLOGCONTEXTA, NEAR *NPLOGCONTEXTA, FAR *LPLOGCONTEXTA;
typedef UINT (WINAPI * PFN_WTInfoA)(UINT,UINT,LPVOID);
typedef HCTX (WINAPI * PFN_WTOpenA)(HWND,LPLOGCONTEXTA,BOOL);
typedef BOOL (WINAPI * PFN_WTQueueSizeSet)(HCTX,int);
typedef BOOL (WINAPI * PFN_WTClose)(HCTX);
typedef BOOL (WINAPI * PFN_WTPacket)(HCTX,UINT,LPVOID);
typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef VkFlags VkWin32SurfaceCreateFlagsKHR;
typedef struct VkWin32SurfaceCreateInfoKHR typedef struct VkWin32SurfaceCreateInfoKHR
@ -383,6 +455,19 @@ typedef struct _GLFWlibraryWin32
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
} ntdll; } ntdll;
struct {
HINSTANCE instance;
PFN_WTInfoA WTInfoA;
PFN_WTOpenA WTOpenA;
PFN_WTQueueSizeSet WTQueueSizeSet;
PFN_WTClose WTClose;
PFN_WTPacket WTPacket;
HCTX context;
LOGCONTEXTA contextInfo;
AXIS pressureInfo;
AXIS orientationInfo[3];
} wintab32;
} _GLFWlibraryWin32; } _GLFWlibraryWin32;
// Win32-specific per-monitor data // Win32-specific per-monitor data

View File

@ -616,6 +616,48 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
break; break;
} }
case WT_PROXIMITY:
{
_glfwInputPenTabletProximity(lParam != 0);
}
case WT_PACKET:
if (_glfw.win32.wintab32.instance)
{
#define FIX2DOUBLE(x) ((double)(HIWORD(x))+((double)LOWORD(x)/65536))
PACKET packet;
LOGCONTEXTA contextInfo = _glfw.win32.wintab32.contextInfo;
AXIS pressureInfo = _glfw.win32.wintab32.pressureInfo;
AXIS altInfo = _glfw.win32.wintab32.orientationInfo[1];
AXIS aziInfo = _glfw.win32.wintab32.orientationInfo[0];
AXIS rollInfo = _glfw.win32.wintab32.orientationInfo[2];
while (_glfw.win32.wintab32.WTPacket(_glfw.win32.wintab32.context, (UINT)wParam, &packet)) {
double x, y, z, pressure, pitch=0, yaw=0, roll=0;
x = ((double)(packet.x - contextInfo.lcInOrgX) / contextInfo.lcInExtX) * contextInfo.lcSysExtX + contextInfo.lcSysOrgX;
y = ((double)(packet.y - contextInfo.lcInOrgY) / contextInfo.lcInExtY) * contextInfo.lcSysExtY + contextInfo.lcSysOrgY;
z = ((double)(packet.z - contextInfo.lcOutOrgZ) / contextInfo.lcOutExtZ);
pressure = (double)(packet.normalPressure - pressureInfo.min) / (pressureInfo.max - pressureInfo.min);
if (aziInfo.resolution && altInfo.resolution) {
double alt = (double)(packet.orientation.altitude - altInfo.min) / (altInfo.max - altInfo.min);
double azi = (double)(packet.orientation.azimuth - aziInfo.min) / (aziInfo.max - aziInfo.min);
pitch = (0.5 - alt) * 180.0;
yaw = azi * 360.0;
}
if (rollInfo.resolution) { // roll seems to be mostly unsupported so this is untested
roll = (double)(packet.orientation.twist - rollInfo.min) / (rollInfo.max - rollInfo.min) * 360.0;
}
if (packet.changed & 0x0020) { // CURSOR changed
_glfwInputPenTabletCursor(packet.cursor);
}
_glfwInputPenTabletData(x, y, z, pressure, pitch, yaw, roll);
}
}
} }
return DefWindowProcW(hWnd, uMsg, wParam, lParam); return DefWindowProcW(hWnd, uMsg, wParam, lParam);

View File

@ -42,6 +42,10 @@
#include "getopt.h" #include "getopt.h"
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
// Event index // Event index
static unsigned int counter = 0; static unsigned int counter = 0;
@ -493,6 +497,24 @@ static void joystick_callback(int jid, int event)
} }
} }
void penTabletData_callback(double x, double y, double z, double pressure, double pitch, double yaw, double roll)
{
printf("%08x at %0.3f: pen: %f %f %f %f %f %f %f\n",
counter++, glfwGetTime(), x, y, z, pressure, pitch, yaw, roll);
}
void penTabletCursor_callback(unsigned int cursor)
{
printf("%08x at %0.3f: pen cursor: %d\n",
counter++, glfwGetTime(), cursor);
}
void penTabletProximity_callback(int proximity)
{
printf("%08x at %0.3f: pen proximity: %d\n",
counter++, glfwGetTime(), proximity);
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
Slot* slots; Slot* slots;
@ -510,6 +532,9 @@ int main(int argc, char** argv)
glfwSetMonitorCallback(monitor_callback); glfwSetMonitorCallback(monitor_callback);
glfwSetJoystickCallback(joystick_callback); glfwSetJoystickCallback(joystick_callback);
glfwSetPenTabletDataCallback(penTabletData_callback);
glfwSetPenTabletCursorCallback(penTabletCursor_callback);
glfwSetPenTabletProximityCallback(penTabletProximity_callback);
while ((ch = getopt(argc, argv, "hfn:")) != -1) while ((ch = getopt(argc, argv, "hfn:")) != -1)
{ {