mirror of
https://github.com/glfw/glfw.git
synced 2025-10-04 05:36:35 +00:00
Merge f47bd94967
into 8055dad7e4
This commit is contained in:
commit
d7ee3f6caa
@ -1510,6 +1510,59 @@ 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 radian.
|
||||
* @param[in] pen yaw in radian.
|
||||
* @param[in] pen roll in radian.
|
||||
*
|
||||
* @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.
|
||||
* It is called when the tablet cursor is changed, from stylus to eraser for example.
|
||||
*
|
||||
* @param[in] pen cursor identifier. 1 is usually a stylus, 2 and 3 an eraser.
|
||||
*
|
||||
* @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.
|
||||
* It is called when a tablet device (pen etc) entering or is exiting tablet proximity.
|
||||
*
|
||||
* @param[in] pen proximity state. 1 = entering, 0 = exiting.
|
||||
*
|
||||
* @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.
|
||||
@ -4994,6 +5047,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
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -44,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
|
||||
@ -437,6 +440,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)mouseDown:(NSEvent *)event
|
||||
{
|
||||
[self handlePenTablet:event];
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_LEFT,
|
||||
GLFW_PRESS,
|
||||
@ -450,14 +454,69 @@ 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] == NSEventSubtypeTabletPoint)
|
||||
{
|
||||
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,
|
||||
CGDisplayBounds(CGMainDisplayID()).size.height - pos.y,
|
||||
posz / 1024.0,
|
||||
pressure,
|
||||
pitch,
|
||||
yaw,
|
||||
0.0);
|
||||
}
|
||||
|
||||
if ([event subtype] == NSEventSubtypeTabletProximity)
|
||||
{
|
||||
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;
|
||||
@ -481,6 +540,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)rightMouseDown:(NSEvent *)event
|
||||
{
|
||||
[self handlePenTablet:event];
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_RIGHT,
|
||||
GLFW_PRESS,
|
||||
@ -494,6 +554,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)rightMouseUp:(NSEvent *)event
|
||||
{
|
||||
[self handlePenTablet:event];
|
||||
_glfwInputMouseClick(window,
|
||||
GLFW_MOUSE_BUTTON_RIGHT,
|
||||
GLFW_RELEASE,
|
||||
@ -502,6 +563,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)otherMouseDown:(NSEvent *)event
|
||||
{
|
||||
[self handlePenTablet:event];
|
||||
_glfwInputMouseClick(window,
|
||||
(int) [event buttonNumber],
|
||||
GLFW_PRESS,
|
||||
@ -515,6 +577,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
||||
|
||||
- (void)otherMouseUp:(NSEvent *)event
|
||||
{
|
||||
[self handlePenTablet:event];
|
||||
_glfwInputMouseClick(window,
|
||||
(int) [event buttonNumber],
|
||||
GLFW_RELEASE,
|
||||
|
44
src/input.c
44
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);
|
||||
|
@ -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
|
||||
@ -729,6 +732,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)));
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 = 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 = 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;
|
||||
}
|
||||
|
||||
if (packet.changed & 0x0020) { // CURSOR changed
|
||||
_glfwInputPenTabletCursor(packet.cursor);
|
||||
}
|
||||
|
||||
_glfwInputPenTabletData(x, y, z, pressure, pitch, yaw, roll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
|
116
src/x11_init.c
116
src/x11_init.c
@ -494,6 +494,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",
|
||||
@ -849,11 +853,119 @@ 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.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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 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)
|
||||
@ -991,11 +1103,15 @@ int _glfwPlatformInit(void)
|
||||
_glfwInitTimerPOSIX();
|
||||
|
||||
_glfwPollMonitorsX11();
|
||||
|
||||
initPenTablet(_glfw.x11.display);
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
terminatePenTablet();
|
||||
|
||||
if (_glfw.x11.helperWindowHandle)
|
||||
{
|
||||
if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.CLIPBOARD) ==
|
||||
|
@ -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*);
|
||||
@ -387,6 +391,14 @@ 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;
|
||||
unsigned int tablet_cursor;
|
||||
int stylus_deviceid;
|
||||
int eraser_deviceid;
|
||||
} xi;
|
||||
|
||||
struct {
|
||||
@ -438,6 +450,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);
|
||||
|
169
src/x11_window.c
169
src/x11_window.c
@ -32,6 +32,7 @@
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -1192,33 +1193,161 @@ 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(
|
||||
_glfw.x11.display, re->deviceid,
|
||||
re->property,
|
||||
0, 5, False,
|
||||
XIAnyPropertyType,
|
||||
&type, &format, &num_items, &bytes_after,
|
||||
(unsigned char **)&data) == Success)
|
||||
{
|
||||
if (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)
|
||||
{
|
||||
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 != _glfw.x11.xi.tablet_cursor)
|
||||
{
|
||||
_glfwInputPenTabletCursor(cursor);
|
||||
_glfw.x11.xi.tablet_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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user