From 79ac26377146426e1d73ead018f9d8abf7af407e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Wed, 6 Mar 2019 11:57:17 +0100 Subject: [PATCH 01/12] Add minimal wintab32 support --- include/GLFW/glfw3.h | 117 +++++++++++++++++++++++++++++++++++++++++++ src/input.c | 44 ++++++++++++++++ src/internal.h | 7 +++ src/win32_init.c | 60 ++++++++++++++++++++++ src/win32_platform.h | 85 +++++++++++++++++++++++++++++++ src/win32_window.c | 42 ++++++++++++++++ tests/events.c | 25 +++++++++ 7 files changed, 380 insertions(+) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 57d5c9c0d..f8447a0d6 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1510,6 +1510,57 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor*,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. * * This describes a single video mode. @@ -4963,6 +5014,72 @@ GLFWAPI const char* glfwGetGamepadName(int jid); */ 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. * * This function sets the system clipboard to the specified, UTF-8 encoded diff --git a/src/input.c b/src/input.c index b5e11542a..3b364aa79 100644 --- a/src/input.c +++ b/src/input.c @@ -401,6 +401,29 @@ void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char 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 ////// @@ -1294,6 +1317,27 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) 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) { assert(string != NULL); diff --git a/src/internal.h b/src/internal.h index abba5baf1..b6ab4e609 100644 --- a/src/internal.h +++ b/src/internal.h @@ -567,6 +567,9 @@ struct _GLFWlibrary struct { GLFWmonitorfun monitor; GLFWjoystickfun joystick; + GLFWpentabletdatafun pentabletdata; + GLFWpentabletcursorfun pentabletcursor; + GLFWpentabletproximityfun pentabletproximity; } callbacks; // 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 _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__) void _glfwInputError(int code, const char* format, ...) __attribute__((format(printf, 2, 3))); diff --git a/src/win32_init.c b/src/win32_init.c index 3ee5eb853..0fa995be1 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -159,6 +159,21 @@ static GLFWbool loadLibraries(void) 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; } @@ -186,6 +201,9 @@ static void freeLibraries(void) if (_glfw.win32.ntdll.instance) FreeLibrary(_glfw.win32.ntdll.instance); + + if (_glfw.win32.wintab32.instance) + FreeLibrary(_glfw.win32.wintab32.instance); } // 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 // static HWND createHelperWindow(void) @@ -577,6 +635,7 @@ int _glfwPlatformInit(void) _glfwInitTimerWin32(); _glfwInitJoysticksWin32(); + initWintabContext(_glfw.win32.helperWindowHandle); _glfwPollMonitorsWin32(); return GLFW_TRUE; @@ -604,6 +663,7 @@ void _glfwPlatformTerminate(void) _glfwTerminateEGL(); _glfwTerminateJoysticksWin32(); + terminateWintabContext(); freeLibraries(); } diff --git a/src/win32_platform.h b/src/win32_platform.h index 9a867c357..e925e9965 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -258,6 +258,78 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*, typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG); #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 struct VkWin32SurfaceCreateInfoKHR @@ -383,6 +455,19 @@ typedef struct _GLFWlibraryWin32 PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; } 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; // Win32-specific per-monitor data diff --git a/src/win32_window.c b/src/win32_window.c index 728b6e07a..038418ee3 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -616,6 +616,48 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, 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); diff --git a/tests/events.c b/tests/events.c index 5a0fde04a..9bcb5f666 100644 --- a/tests/events.c +++ b/tests/events.c @@ -42,6 +42,10 @@ #include "getopt.h" +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + // Event index 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) { Slot* slots; @@ -510,6 +532,9 @@ int main(int argc, char** argv) glfwSetMonitorCallback(monitor_callback); glfwSetJoystickCallback(joystick_callback); + glfwSetPenTabletDataCallback(penTabletData_callback); + glfwSetPenTabletCursorCallback(penTabletCursor_callback); + glfwSetPenTabletProximityCallback(penTabletProximity_callback); while ((ch = getopt(argc, argv, "hfn:")) != -1) { From fa5882eb54e94f26763b40f7b854c81aea00f90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Thu, 7 Mar 2019 09:54:05 +0100 Subject: [PATCH 02/12] Change orientation unit to radian --- include/GLFW/glfw3.h | 6 +++--- src/win32_window.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index f8447a0d6..a7ff89a70 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1518,9 +1518,9 @@ typedef void (* GLFWjoystickfun)(int,int); * @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. + * @param[in] pen pitch in radian. + * @param[in] pen yaw in radian. + * @param[in] pen roll in radian. * * @sa @ref pen_tablet_data * @sa @ref glfwSetPenTabletDataCallback diff --git a/src/win32_window.c b/src/win32_window.c index 038418ee3..edc8e4c95 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -639,13 +639,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, 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); + z = packet.z / 1024.0; 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; + pitch = alt * 3.14159265359; + yaw = azi * 6.28318530718; } 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; From bd7ce803696de31015b809e5c621a77b8f6ba7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Thu, 7 Mar 2019 12:38:24 +0100 Subject: [PATCH 03/12] Add pen tablet support for OSX cocoa --- src/cocoa_window.m | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 9bea2f27f..69dafb0eb 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -26,6 +26,7 @@ #include "internal.h" +#include #include #include @@ -439,6 +440,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)mouseDown:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, @@ -452,14 +454,70 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)mouseUp:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, translateFlags([event modifierFlags])); } +- (void)handlePenTablet:(NSEvent *)event +{ + if ([window->ns.object isKeyWindow]) + { + if ([event subtype] == NSTabletPointEventSubtype) + { + const double pressure = [event pressure]; + const NSPoint tilt = [event tilt]; + const NSPoint pos = [NSEvent mouseLocation]; + const double posz = [event absoluteZ]; + + double tx = tilt.x * 1.5707963267949; + double ty = tilt.y * 1.5707963267949; + + double sinx = sin(tx); + double siny = sin(ty); + double cosx = cos(tx); + double cosy = cos(ty); + /*double matrix[9] = { // full matrix for reference + 0.0, -cosy, siny, + cosx, -sinx*siny, -sinx*cosy, + sinx, cosx*siny, cosx*cosy + };*/ + double v[3] = {sinx, cosx*siny, cosx*cosy}; + double yaw = atan2(v[0], v[1]); + double pitch = 3.141592653589793 - acos(v[2]); + if (yaw < 0.0) yaw += 6.28318530717959; + + _glfwInputPenTabletData( + pos.x, + transformY(pos.y), + posz / 1024.0, + pressure, + pitch, + yaw, + 0.0); + } + + if ([event subtype] == NSTabletProximityEventSubtype) + { + static unsigned int s_cursor = 0; + unsigned int cursor = [event pointingDeviceType]; + + _glfwInputPenTabletProximity([event isEnteringProximity]); + if (cursor != s_cursor) + { + _glfwInputPenTabletCursor(cursor); + s_cursor = cursor; + } + } + } +} + - (void)mouseMoved:(NSEvent *)event { + [self handlePenTablet:event]; + if (window->cursorMode == GLFW_CURSOR_DISABLED) { const double dx = [event deltaX] - window->ns.cursorWarpDeltaX; @@ -483,6 +541,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)rightMouseDown:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, @@ -496,6 +555,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)rightMouseUp:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, @@ -504,6 +564,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)otherMouseDown:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, (int) [event buttonNumber], GLFW_PRESS, @@ -517,6 +578,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)otherMouseUp:(NSEvent *)event { + [self handlePenTablet:event]; _glfwInputMouseClick(window, (int) [event buttonNumber], GLFW_RELEASE, From 340c1200fc102b0d4b8c7fa0a1fe25d9b71e7fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Thu, 7 Mar 2019 12:56:05 +0100 Subject: [PATCH 04/12] Remove trailing whitespace --- src/cocoa_window.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 69dafb0eb..6887e4b7d 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -474,7 +474,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; double tx = tilt.x * 1.5707963267949; double ty = tilt.y * 1.5707963267949; - double sinx = sin(tx); double siny = sin(ty); double cosx = cos(tx); @@ -511,7 +510,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; s_cursor = cursor; } } - } + } } - (void)mouseMoved:(NSEvent *)event From eea6b32f6677e671705adc5ad5ddb5ad768e875b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Thu, 7 Mar 2019 14:51:12 +0100 Subject: [PATCH 05/12] Fix macOS 10.12 deprecated --- src/cocoa_window.m | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6887e4b7d..95a0330c1 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -45,6 +45,8 @@ #define NSEventMaskAny NSAnyEventMask #define NSEventTypeApplicationDefined NSApplicationDefined #define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat + #define NSEventSubtypeTabletPoint NSTabletPointEventSubtype + #define NSEventSubtypeTabletProximity NSTabletProximityEventSubtype #endif // Returns the style mask corresponding to the window settings @@ -465,7 +467,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; { if ([window->ns.object isKeyWindow]) { - if ([event subtype] == NSTabletPointEventSubtype) + if ([event subtype] == NSEventSubtypeTabletPoint) { const double pressure = [event pressure]; const NSPoint tilt = [event tilt]; @@ -490,7 +492,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _glfwInputPenTabletData( pos.x, - transformY(pos.y), + (double)transformY((float)pos.y), posz / 1024.0, pressure, pitch, @@ -498,7 +500,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; 0.0); } - if ([event subtype] == NSTabletProximityEventSubtype) + if ([event subtype] == NSEventSubtypeTabletProximity) { static unsigned int s_cursor = 0; unsigned int cursor = [event pointingDeviceType]; From 58d3c0fd456ec0103279a65170439593a060a034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Thu, 7 Mar 2019 15:04:38 +0100 Subject: [PATCH 06/12] Remove dependency over transformY --- src/cocoa_window.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 95a0330c1..e22b28752 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -492,7 +492,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; _glfwInputPenTabletData( pos.x, - (double)transformY((float)pos.y), + CGDisplayBounds(CGMainDisplayID()).size.height - pos.y, posz / 1024.0, pressure, pitch, From 6ab20fa776bfff3dac563cc6ec22bcdc889e9619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 8 Mar 2019 18:07:44 +0100 Subject: [PATCH 07/12] Add XInput2 tablet support --- src/x11_init.c | 94 ++++++++++++++++++++++++ src/x11_platform.h | 12 ++++ src/x11_window.c | 173 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 259 insertions(+), 20 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index e3e3ad518..436151753 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -490,6 +490,10 @@ static GLFWbool initExtensions(void) _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); _glfw.x11.xi.SelectEvents = (PFN_XISelectEvents) _glfw_dlsym(_glfw.x11.xi.handle, "XISelectEvents"); + _glfw.x11.xi.QueryDevice = (PFN_XIQueryDevice) + _glfw_dlsym(_glfw.x11.xi.handle, "XIQueryDevice"); + _glfw.x11.xi.GetProperty = (PFN_XIGetProperty) + _glfw_dlsym(_glfw.x11.xi.handle, "XIGetProperty"); if (XQueryExtension(_glfw.x11.display, "XInputExtension", @@ -845,11 +849,99 @@ static int errorHandler(Display *display, XErrorEvent* event) return 0; } +// Coordinate Transformation Matrix +// +static float * getDeviceCoordinateTransformationMatrix(Display *display, int deviceid) +{ + float *data = NULL; + Atom type; + int format; + unsigned long num_items, bytes_after; + + if (XIGetProperty( + display, deviceid, + XInternAtom(display, "Coordinate Transformation Matrix", False), + 0, 9, False, + XInternAtom(display, "FLOAT", False), + &type, &format, &num_items, &bytes_after, + (unsigned char **)&data + ) != Success) + return NULL; + + return data; +} + +// XInput2 init pen tablet +// +static void initPenTablet(Display *display) +{ + _glfw.x11.xi.stylus_deviceid = 0; + _glfw.x11.xi.eraser_deviceid = 0; + + if (_glfw.x11.xi.available) + { + int i, n; + XIDeviceInfo *dev_info = XIQueryDevice(display, XIAllDevices, &n); + + for (i = 0; i < n; i++) + { + XIDeviceInfo *dev = &dev_info[i]; + + if (strstr(dev->name, "stylus") || strstr(dev->name, "eraser")) + { + XIEventMask mask; + + mask.deviceid = dev->deviceid; + mask.mask_len = XIMaskLen(XI_RawMotion); + mask.mask = calloc(mask.mask_len, sizeof(char)); + XISetMask(mask.mask, XI_PropertyEvent); // property event to catch proximity change + XISetMask(mask.mask, XI_RawMotion); // raw motion to catch x, y, pressure and tilt + XISelectEvents(display, DefaultRootWindow(display), &mask, 1); + + if (strstr(dev->name, "stylus")) + { + int c; + + _glfw.x11.xi.stylus_deviceid = dev->deviceid; + + for (c = 0; c < dev->num_classes; c++) + { + if (dev->classes[c]->type == XIValuatorClass) + { + XIValuatorClassInfo *v = (XIValuatorClassInfo*)dev->classes[c]; + if (v->number < 32) _glfw.x11.xi.stylus_ClassInfo[v->number] = *v; + } + } + + _glfw.x11.xi.stylus_CTMatrix = getDeviceCoordinateTransformationMatrix(display, dev->deviceid); + } + else + { + _glfw.x11.xi.eraser_deviceid = dev->deviceid; + _glfw.x11.xi.eraser_CTMatrix = getDeviceCoordinateTransformationMatrix(display, dev->deviceid); + } + + free(mask.mask); + } + } + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// +// Apply Coordinate Transformation Matrix to a 2d vector +// +void _glfwApplyCoordTransformMatrix(float *matrix, float *px, float *py) +{ + float x = *px; + float y = *py; + *px = x * matrix[0] + y * matrix[1] + matrix[2]; + *py = x * matrix[3] + y * matrix[4] + matrix[5]; +} + // Sets the X error handler callback // void _glfwGrabErrorHandlerX11(void) @@ -987,6 +1079,8 @@ int _glfwPlatformInit(void) _glfwInitTimerPOSIX(); _glfwPollMonitorsX11(); + + initPenTablet(_glfw.x11.display); return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index c37c740e4..5a05701e2 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -113,8 +113,12 @@ typedef Bool (* PFN_XF86VidModeGetGammaRampSize)(Display*,int,int*); typedef Status (* PFN_XIQueryVersion)(Display*,int*,int*); typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); +typedef XIDeviceInfo* (* PFN_XIQueryDevice)(Display*,int,int*); +typedef Status (* PFN_XIGetProperty)(Display*,int,Atom,long,long,Bool,Atom,Atom*,int*,unsigned long*,unsigned long*,unsigned char**); #define XIQueryVersion _glfw.x11.xi.QueryVersion #define XISelectEvents _glfw.x11.xi.SelectEvents +#define XIQueryDevice _glfw.x11.xi.QueryDevice +#define XIGetProperty _glfw.x11.xi.GetProperty typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*); typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*); @@ -385,6 +389,13 @@ typedef struct _GLFWlibraryX11 int minor; PFN_XIQueryVersion QueryVersion; PFN_XISelectEvents SelectEvents; + PFN_XIQueryDevice QueryDevice; + PFN_XIGetProperty GetProperty; + XIValuatorClassInfo stylus_ClassInfo[32]; + float *stylus_CTMatrix; + float *eraser_CTMatrix; + int stylus_deviceid; + int eraser_deviceid; } xi; struct { @@ -436,6 +447,7 @@ unsigned long _glfwGetWindowPropertyX11(Window window, unsigned char** value); GLFWbool _glfwIsVisualTransparentX11(Visual* visual); +void _glfwApplyCoordTransformMatrix(float *matrix, float *px, float *py); void _glfwGrabErrorHandlerX11(void); void _glfwReleaseErrorHandlerX11(void); void _glfwInputErrorX11(int error, const char* message); diff --git a/src/x11_window.c b/src/x11_window.c index 92a137f48..8b131361c 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -32,6 +32,7 @@ #include +#include #include #include #include @@ -1192,33 +1193,165 @@ static void processEvent(XEvent *event) { _GLFWwindow* window = _glfw.x11.disabledCursorWindow; - if (window && - window->rawMouseMotion && - event->xcookie.extension == _glfw.x11.xi.majorOpcode && - XGetEventData(_glfw.x11.display, &event->xcookie) && - event->xcookie.evtype == XI_RawMotion) + if (event->xcookie.extension == _glfw.x11.xi.majorOpcode && + XGetEventData(_glfw.x11.display, &event->xcookie)) { - XIRawEvent* re = event->xcookie.data; - if (re->valuators.mask_len) + if (event->xcookie.evtype == XI_PropertyEvent) { - const double* values = re->raw_values; - double xpos = window->virtualCursorPosX; - double ypos = window->virtualCursorPosY; + // the first proximity event seems to arrive one later AFTER XI_RawMotion... + XIPropertyEvent* re = event->xcookie.data; - if (XIMaskIsSet(re->valuators.mask, 0)) + // pen tablet property + if (re->deviceid == _glfw.x11.xi.stylus_deviceid || + re->deviceid == _glfw.x11.xi.eraser_deviceid) { - xpos += *values; - values++; + if (re->what == XIPropertyModified) + { + float *data = NULL; + Atom type; + int format; + unsigned long num_items, bytes_after; + + if (XIGetProperty( + re->display, re->deviceid, + re->property, + 0, 5, False, + XIAnyPropertyType, + &type, &format, &num_items, &bytes_after, + (unsigned char **)&data + ) != Success) + data = NULL; + + if (data && format == 32 && num_items > 4) + { + _glfwInputPenTabletProximity(((unsigned int *)data)[4] != 0); + XFree(data); + } + } } - - if (XIMaskIsSet(re->valuators.mask, 1)) - ypos += *values; - - _glfwInputCursorPos(window, xpos, ypos); } - } + else if (event->xcookie.evtype == XI_RawMotion) + { + XIRawEvent* re = event->xcookie.data; + if (re->valuators.mask_len) + { + const double* values = re->raw_values; - XFreeEventData(_glfw.x11.display, &event->xcookie); + // pen tablet raw motion + if (re->deviceid == _glfw.x11.xi.stylus_deviceid || + re->deviceid == _glfw.x11.xi.eraser_deviceid) + { + static unsigned int s_cursor = 0; + unsigned int cursor = re->deviceid == _glfw.x11.xi.stylus_deviceid ? 1 : 2; + float x = 0.0f; + float y = 0.0f; + double pressure = 0.0; + double tiltx = 0.0; + double tilty = 0.0; + + if (cursor != s_cursor) + { + _glfwInputPenTabletCursor(cursor); + s_cursor = cursor; + } + + if (XIMaskIsSet(re->valuators.mask, 0)) + { + XIValuatorClassInfo *v = &_glfw.x11.xi.stylus_ClassInfo[0]; + x = (*values - v->min) / (v->max - v->min); + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 1)) + { + XIValuatorClassInfo *v = &_glfw.x11.xi.stylus_ClassInfo[1]; + y = (*values - v->min) / (v->max - v->min); + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 2)) + { + XIValuatorClassInfo *v = &_glfw.x11.xi.stylus_ClassInfo[2]; + pressure = (*values - v->min) / (v->max - v->min); + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 3)) + { + XIValuatorClassInfo *v = &_glfw.x11.xi.stylus_ClassInfo[3]; + tiltx = (*values - v->min) / (v->max - v->min) * 2.0 - 1.0; + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 4)) + { + XIValuatorClassInfo *v = &_glfw.x11.xi.stylus_ClassInfo[4]; + tilty = (*values - v->min) / (v->max - v->min) * 2.0 - 1.0; + values++; + } + + // apply coordinate transform matrix depending on current cursor + if (re->deviceid == _glfw.x11.xi.stylus_deviceid) + { + if (_glfw.x11.xi.stylus_CTMatrix) + _glfwApplyCoordTransformMatrix(_glfw.x11.xi.stylus_CTMatrix, &x, &y); + } + else + { + if (_glfw.x11.xi.eraser_CTMatrix) + _glfwApplyCoordTransformMatrix(_glfw.x11.xi.eraser_CTMatrix, &x, &y); + } + + // send data + { + double tx = tiltx * 1.5707963267949; + double ty = -tilty * 1.5707963267949; + double sinx = sin(tx); + double siny = sin(ty); + double cosx = cos(tx); + double cosy = cos(ty); + /*double matrix[9] = { // full matrix for reference + 0.0, -cosy, siny, + cosx, -sinx*siny, -sinx*cosy, + sinx, cosx*siny, cosx*cosy + };*/ + double v[3] = {sinx, cosx*siny, cosx*cosy}; + double yaw = atan2(v[0], v[1]); + double pitch = 3.141592653589793 - acos(v[2]); + if (yaw < 0.0) yaw += 6.28318530717959; + + _glfwInputPenTabletData( + (double)x * DisplayWidth(_glfw.x11.display, _glfw.x11.screen), + (double)y * DisplayHeight(_glfw.x11.display, _glfw.x11.screen), + 0.0, // can't find z coordinate + pressure, + pitch, + yaw, + 0.0); + } + } + // mouse raw motion + else if (window && window->rawMouseMotion) + { + double xpos = window->virtualCursorPosX; + double ypos = window->virtualCursorPosY; + + if (XIMaskIsSet(re->valuators.mask, 0)) + { + xpos += *values; + values++; + } + + if (XIMaskIsSet(re->valuators.mask, 1)) + ypos += *values; + + _glfwInputCursorPos(window, xpos, ypos); + } + } + } + + XFreeEventData(_glfw.x11.display, &event->xcookie); + } } return; From d7c1b080db42c9dd3829ae190757d9d88209041d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 8 Mar 2019 18:14:51 +0100 Subject: [PATCH 08/12] Fix trailing whitespace --- src/x11_init.c | 2 +- src/x11_window.c | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 436151753..944791995 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -879,7 +879,7 @@ static void initPenTablet(Display *display) _glfw.x11.xi.eraser_deviceid = 0; if (_glfw.x11.xi.available) - { + { int i, n; XIDeviceInfo *dev_info = XIQueryDevice(display, XIAllDevices, &n); diff --git a/src/x11_window.c b/src/x11_window.c index 8b131361c..389e51124 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1218,13 +1218,10 @@ static void processEvent(XEvent *event) 0, 5, False, XIAnyPropertyType, &type, &format, &num_items, &bytes_after, - (unsigned char **)&data - ) != Success) - data = NULL; - - if (data && format == 32 && num_items > 4) + (unsigned char **)&data) == Success) { - _glfwInputPenTabletProximity(((unsigned int *)data)[4] != 0); + if (format == 32 && num_items > 4) + _glfwInputPenTabletProximity(((unsigned int *)data)[4] != 0); XFree(data); } } From 00dc88af7b7703a5df81305012176fdc16222029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 8 Mar 2019 18:21:57 +0100 Subject: [PATCH 09/12] Fix trailing whitespace --- src/x11_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_init.c b/src/x11_init.c index 944791995..1f27f8136 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -903,7 +903,7 @@ static void initPenTablet(Display *display) int c; _glfw.x11.xi.stylus_deviceid = dev->deviceid; - + for (c = 0; c < dev->num_classes; c++) { if (dev->classes[c]->type == XIValuatorClass) From 04cf328ca6d042bdbf6b99034f2df38baf6ae0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Fri, 8 Mar 2019 18:34:35 +0100 Subject: [PATCH 10/12] Add cursor and proximity docu --- include/GLFW/glfw3.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index a7ff89a70..83bb03edb 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1534,8 +1534,9 @@ typedef void (* GLFWpentabletdatafun)(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. + * It is called when the tablet cursor is changed, from stylus to eraser for example. * - * @param[in] pen cursor identifier. + * @param[in] pen cursor identifier. 1 is usually a stylus, 2 and 3 an eraser. * * @sa @ref pen_tablet_cursor * @sa @ref glfwSetPenTabletCursorCallback @@ -1549,8 +1550,9 @@ 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. + * It is called when a tablet device (pen etc) entering or is exiting tablet proximity. * - * @param[in] pen proximity state. + * @param[in] pen proximity state. 1 = entering, 0 = exiting. * * @sa @ref pen_tablet_proximity * @sa @ref glfwSetPenTabletProximityCallback From 92d93ede90db20a96dc6eed853eeaaaedeebdcb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Sat, 9 Mar 2019 13:50:45 +0100 Subject: [PATCH 11/12] Add tablet termination and global cursor --- src/x11_init.c | 22 ++++++++++++++++++++++ src/x11_platform.h | 9 +++++---- src/x11_window.c | 5 ++--- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/x11_init.c b/src/x11_init.c index 1f27f8136..e753f0919 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -875,8 +875,11 @@ static float * getDeviceCoordinateTransformationMatrix(Display *display, int dev // static void initPenTablet(Display *display) { + _glfw.x11.xi.tablet_cursor = 0; _glfw.x11.xi.stylus_deviceid = 0; _glfw.x11.xi.eraser_deviceid = 0; + _glfw.x11.xi.stylus_CTMatrix = NULL; + _glfw.x11.xi.eraser_CTMatrix = NULL; if (_glfw.x11.xi.available) { @@ -927,6 +930,23 @@ static void initPenTablet(Display *display) } } +// XInput2 terminate pen tablet +// +static void terminatePenTablet(void) +{ + if (_glfw.x11.xi.stylus_CTMatrix) + { + XFree(_glfw.x11.xi.stylus_CTMatrix); + _glfw.x11.xi.stylus_CTMatrix = NULL; + } + + if (_glfw.x11.xi.eraser_CTMatrix) + { + XFree(_glfw.x11.xi.eraser_CTMatrix); + _glfw.x11.xi.eraser_CTMatrix = NULL; + } +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// @@ -1086,6 +1106,8 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { + terminatePenTablet(); + if (_glfw.x11.helperWindowHandle) { if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) == diff --git a/src/x11_platform.h b/src/x11_platform.h index 5a05701e2..1858da1f3 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -392,10 +392,11 @@ typedef struct _GLFWlibraryX11 PFN_XIQueryDevice QueryDevice; PFN_XIGetProperty GetProperty; XIValuatorClassInfo stylus_ClassInfo[32]; - float *stylus_CTMatrix; - float *eraser_CTMatrix; - int stylus_deviceid; - int eraser_deviceid; + float *stylus_CTMatrix; + float *eraser_CTMatrix; + unsigned int tablet_cursor; + int stylus_deviceid; + int eraser_deviceid; } xi; struct { diff --git a/src/x11_window.c b/src/x11_window.c index 389e51124..e04d7d293 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1238,7 +1238,6 @@ static void processEvent(XEvent *event) if (re->deviceid == _glfw.x11.xi.stylus_deviceid || re->deviceid == _glfw.x11.xi.eraser_deviceid) { - static unsigned int s_cursor = 0; unsigned int cursor = re->deviceid == _glfw.x11.xi.stylus_deviceid ? 1 : 2; float x = 0.0f; float y = 0.0f; @@ -1246,10 +1245,10 @@ static void processEvent(XEvent *event) double tiltx = 0.0; double tilty = 0.0; - if (cursor != s_cursor) + if (cursor != _glfw.x11.xi.tablet_cursor) { _glfwInputPenTabletCursor(cursor); - s_cursor = cursor; + _glfw.x11.xi.tablet_cursor = cursor; } if (XIMaskIsSet(re->valuators.mask, 0)) From f47bd94967ab2d057641ad6bac3caa9c6bc1dcfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ana=C3=ABl=20Seghezzi?= Date: Sat, 9 Mar 2019 14:29:05 +0100 Subject: [PATCH 12/12] Correct GetProperty segmentation fault --- src/x11_window.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x11_window.c b/src/x11_window.c index e04d7d293..941a2fdcc 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1213,7 +1213,7 @@ static void processEvent(XEvent *event) unsigned long num_items, bytes_after; if (XIGetProperty( - re->display, re->deviceid, + _glfw.x11.display, re->deviceid, re->property, 0, 5, False, XIAnyPropertyType,