forked from bartvdbraak/blender
Windows: refactor GHOST wintab handling.
This is backporting a change from 2.8, which may help solve crashes when activating a window. Previously bringTabletContextToFront() would call tablet API functions with NULL tablet, which may crash on some drivers. Ref T60811.
This commit is contained in:
parent
fccf506ed7
commit
6fdc688cd0
@ -79,15 +79,17 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||||||
m_nPressedButtons(0),
|
m_nPressedButtons(0),
|
||||||
m_customCursor(0),
|
m_customCursor(0),
|
||||||
m_wantAlphaBackground(alphaBackground),
|
m_wantAlphaBackground(alphaBackground),
|
||||||
m_wintab(NULL),
|
|
||||||
m_tabletData(NULL),
|
|
||||||
m_tablet(0),
|
|
||||||
m_maxPressure(0),
|
|
||||||
m_normal_state(GHOST_kWindowStateNormal),
|
m_normal_state(GHOST_kWindowStateNormal),
|
||||||
m_user32(NULL),
|
m_user32(NULL),
|
||||||
m_parentWindowHwnd(parentwindowhwnd),
|
m_parentWindowHwnd(parentwindowhwnd),
|
||||||
m_debug_context(is_debug)
|
m_debug_context(is_debug)
|
||||||
{
|
{
|
||||||
|
// Initialize tablet variables
|
||||||
|
memset(&m_wintab, 0, sizeof(m_wintab));
|
||||||
|
memset(&m_tabletData, 0, sizeof(m_tabletData));
|
||||||
|
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||||
|
|
||||||
|
// Create window
|
||||||
if (state != GHOST_kWindowStateFullScreen) {
|
if (state != GHOST_kWindowStateFullScreen) {
|
||||||
RECT rect;
|
RECT rect;
|
||||||
MONITORINFO monitor;
|
MONITORINFO monitor;
|
||||||
@ -274,16 +276,22 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||||||
RegisterRawInputDevices(&device, 1, sizeof(device));
|
RegisterRawInputDevices(&device, 1, sizeof(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_wintab = ::LoadLibrary("Wintab32.dll");
|
// Initialize Wintab
|
||||||
if (m_wintab) {
|
m_wintab.handle = ::LoadLibrary("Wintab32.dll");
|
||||||
GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
|
if (m_wintab.handle) {
|
||||||
GHOST_WIN32_WTOpen fpWTOpen = (GHOST_WIN32_WTOpen) ::GetProcAddress(m_wintab, "WTOpenA");
|
// Get API functions
|
||||||
|
m_wintab.info = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab.handle, "WTInfoA");
|
||||||
|
m_wintab.open = (GHOST_WIN32_WTOpen) ::GetProcAddress(m_wintab.handle, "WTOpenA");
|
||||||
|
m_wintab.close = (GHOST_WIN32_WTClose) ::GetProcAddress(m_wintab.handle, "WTClose");
|
||||||
|
m_wintab.packet = (GHOST_WIN32_WTPacket) ::GetProcAddress(m_wintab.handle, "WTPacket");
|
||||||
|
m_wintab.enable = (GHOST_WIN32_WTEnable) ::GetProcAddress(m_wintab.handle, "WTEnable");
|
||||||
|
m_wintab.overlap = (GHOST_WIN32_WTOverlap) ::GetProcAddress(m_wintab.handle, "WTOverlap");
|
||||||
|
|
||||||
// Let's see if we can initialize tablet here.
|
// Let's see if we can initialize tablet here.
|
||||||
// Check if WinTab available by getting system context info.
|
// Check if WinTab available by getting system context info.
|
||||||
LOGCONTEXT lc = { 0 };
|
LOGCONTEXT lc = { 0 };
|
||||||
lc.lcOptions |= CXO_SYSTEM;
|
lc.lcOptions |= CXO_SYSTEM;
|
||||||
if (fpWTInfo && fpWTInfo(WTI_DEFSYSCTX, 0, &lc)) {
|
if (m_wintab.open && m_wintab.info && m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) {
|
||||||
// Now init the tablet
|
// Now init the tablet
|
||||||
/* The maximum tablet size, pressure and orientation (tilt) */
|
/* The maximum tablet size, pressure and orientation (tilt) */
|
||||||
AXIS TabletX, TabletY, Pressure, Orientation[3];
|
AXIS TabletX, TabletY, Pressure, Orientation[3];
|
||||||
@ -297,42 +305,34 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||||||
lc.lcMoveMask = PACKETDATA;
|
lc.lcMoveMask = PACKETDATA;
|
||||||
|
|
||||||
/* Set the entire tablet as active */
|
/* Set the entire tablet as active */
|
||||||
fpWTInfo(WTI_DEVICES, DVC_X, &TabletX);
|
m_wintab.info(WTI_DEVICES, DVC_X, &TabletX);
|
||||||
fpWTInfo(WTI_DEVICES, DVC_Y, &TabletY);
|
m_wintab.info(WTI_DEVICES, DVC_Y, &TabletY);
|
||||||
|
|
||||||
/* get the max pressure, to divide into a float */
|
/* get the max pressure, to divide into a float */
|
||||||
BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
||||||
if (pressureSupport)
|
if (pressureSupport)
|
||||||
m_maxPressure = Pressure.axMax;
|
m_wintab.maxPressure = Pressure.axMax;
|
||||||
else
|
else
|
||||||
m_maxPressure = 0;
|
m_wintab.maxPressure = 0;
|
||||||
|
|
||||||
/* get the max tilt axes, to divide into floats */
|
/* get the max tilt axes, to divide into floats */
|
||||||
BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
||||||
if (tiltSupport) {
|
if (tiltSupport) {
|
||||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||||
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||||
/* all this assumes the minimum is 0 */
|
/* all this assumes the minimum is 0 */
|
||||||
m_maxAzimuth = Orientation[0].axMax;
|
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||||
m_maxAltitude = Orientation[1].axMax;
|
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||||
}
|
}
|
||||||
else { /* no so dont do tilt stuff */
|
else { /* no so dont do tilt stuff */
|
||||||
m_maxAzimuth = m_maxAltitude = 0;
|
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fpWTOpen) {
|
// The Wintab spec says we must open the context disabled if we are using cursor masks.
|
||||||
// The Wintab spec says we must open the context disabled if we are using cursor masks.
|
m_wintab.tablet = m_wintab.open(m_hWnd, &lc, FALSE);
|
||||||
m_tablet = fpWTOpen(m_hWnd, &lc, FALSE);
|
if (m_wintab.enable && m_wintab.tablet) {
|
||||||
if (m_tablet) {
|
m_wintab.enable(m_wintab.tablet, TRUE);
|
||||||
m_tabletData = new GHOST_TabletData();
|
|
||||||
m_tabletData->Active = GHOST_kTabletModeNone;
|
|
||||||
}
|
|
||||||
|
|
||||||
GHOST_WIN32_WTEnable fpWTEnable = (GHOST_WIN32_WTEnable) ::GetProcAddress(m_wintab, "WTEnable");
|
|
||||||
if (fpWTEnable) {
|
|
||||||
fpWTEnable(m_tablet, TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,14 +347,13 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
|
|||||||
m_Bar->Release();
|
m_Bar->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_wintab) {
|
if (m_wintab.handle) {
|
||||||
GHOST_WIN32_WTClose fpWTClose = (GHOST_WIN32_WTClose) ::GetProcAddress(m_wintab, "WTClose");
|
if (m_wintab.close && m_wintab.tablet) {
|
||||||
if (fpWTClose) {
|
m_wintab.close(m_wintab.tablet);
|
||||||
if (m_tablet)
|
|
||||||
fpWTClose(m_tablet);
|
|
||||||
delete m_tabletData;
|
|
||||||
m_tabletData = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FreeLibrary(m_wintab.handle);
|
||||||
|
memset(&m_wintab, 0, sizeof(m_wintab));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_customCursor) {
|
if (m_customCursor) {
|
||||||
@ -883,118 +882,103 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
|
|||||||
|
|
||||||
void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state)
|
void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state)
|
||||||
{
|
{
|
||||||
if (!m_tablet) {
|
if (m_wintab.enable && m_wintab.tablet) {
|
||||||
return;
|
m_wintab.enable(m_wintab.tablet, state);
|
||||||
}
|
|
||||||
|
|
||||||
GHOST_WIN32_WTEnable fpWTEnable = (GHOST_WIN32_WTEnable) ::GetProcAddress(m_wintab, "WTEnable");
|
if (m_wintab.overlap && state) {
|
||||||
GHOST_WIN32_WTOverlap fpWTOverlap = (GHOST_WIN32_WTOverlap) ::GetProcAddress(m_wintab, "WTOverlap");
|
m_wintab.overlap(m_wintab.tablet, TRUE);
|
||||||
|
|
||||||
if (fpWTEnable) {
|
|
||||||
fpWTEnable(m_tablet, state);
|
|
||||||
if (fpWTOverlap && state) {
|
|
||||||
fpWTOverlap(m_tablet, TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHOST_WindowWin32::processWin32TabletInitEvent()
|
void GHOST_WindowWin32::processWin32TabletInitEvent()
|
||||||
{
|
{
|
||||||
if (m_wintab && m_tabletData) {
|
// Let's see if we can initialize tablet here
|
||||||
GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
|
if (m_wintab.info && m_wintab.tablet) {
|
||||||
|
AXIS Pressure, Orientation[3]; /* The maximum tablet size */
|
||||||
|
|
||||||
// let's see if we can initialize tablet here
|
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
||||||
/* check if WinTab available. */
|
if (pressureSupport)
|
||||||
if (fpWTInfo) {
|
m_wintab.maxPressure = Pressure.axMax;
|
||||||
AXIS Pressure, Orientation[3]; /* The maximum tablet size */
|
else
|
||||||
|
m_wintab.maxPressure = 0;
|
||||||
|
|
||||||
BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
||||||
if (pressureSupport)
|
if (tiltSupport) {
|
||||||
m_maxPressure = Pressure.axMax;
|
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||||
else
|
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||||
m_maxPressure = 0;
|
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||||
|
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||||
BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
}
|
||||||
if (tiltSupport) {
|
else { /* no so dont do tilt stuff */
|
||||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||||
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
|
||||||
m_maxAzimuth = Orientation[0].axMax;
|
|
||||||
m_maxAltitude = Orientation[1].axMax;
|
|
||||||
}
|
|
||||||
else { /* no so dont do tilt stuff */
|
|
||||||
m_maxAzimuth = m_maxAltitude = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tabletData->Active = GHOST_kTabletModeNone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
|
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
PACKET pkt;
|
if (m_wintab.packet && m_wintab.tablet) {
|
||||||
if (m_wintab) {
|
PACKET pkt;
|
||||||
GHOST_WIN32_WTPacket fpWTPacket = (GHOST_WIN32_WTPacket) ::GetProcAddress(m_wintab, "WTPacket");
|
if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) {
|
||||||
if (fpWTPacket) {
|
switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
|
||||||
if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
|
case 0:
|
||||||
if (m_tabletData) {
|
m_tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
|
||||||
switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
|
break;
|
||||||
case 0:
|
case 1:
|
||||||
m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */
|
m_tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 2:
|
||||||
m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */
|
m_tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
|
||||||
break;
|
break;
|
||||||
case 2:
|
}
|
||||||
m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (m_maxPressure > 0) {
|
|
||||||
m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_tabletData->Pressure = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
|
if (m_wintab.maxPressure > 0) {
|
||||||
ORIENTATION ort = pkt.pkOrientation;
|
m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
|
||||||
float vecLen;
|
}
|
||||||
float altRad, azmRad; /* in radians */
|
else {
|
||||||
|
m_tabletData.Pressure = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
|
||||||
* from the wintab spec:
|
ORIENTATION ort = pkt.pkOrientation;
|
||||||
* orAzimuth Specifies the clockwise rotation of the
|
float vecLen;
|
||||||
* cursor about the z axis through a full circular range.
|
float altRad, azmRad; /* in radians */
|
||||||
*
|
|
||||||
* orAltitude Specifies the angle with the x-y plane
|
|
||||||
* through a signed, semicircular range. Positive values
|
|
||||||
* specify an angle upward toward the positive z axis;
|
|
||||||
* negative values specify an angle downward toward the negative z axis.
|
|
||||||
*
|
|
||||||
* wintab.h defines .orAltitude as a UINT but documents .orAltitude
|
|
||||||
* as positive for upward angles and negative for downward angles.
|
|
||||||
* WACOM uses negative altitude values to show that the pen is inverted;
|
|
||||||
* therefore we cast .orAltitude as an (int) and then use the absolute value.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* convert raw fixed point data to radians */
|
/*
|
||||||
altRad = (float)((fabs((float)ort.orAltitude) / (float)m_maxAltitude) * M_PI / 2.0);
|
* from the wintab spec:
|
||||||
azmRad = (float)(((float)ort.orAzimuth / (float)m_maxAzimuth) * M_PI * 2.0);
|
* orAzimuth Specifies the clockwise rotation of the
|
||||||
|
* cursor about the z axis through a full circular range.
|
||||||
|
*
|
||||||
|
* orAltitude Specifies the angle with the x-y plane
|
||||||
|
* through a signed, semicircular range. Positive values
|
||||||
|
* specify an angle upward toward the positive z axis;
|
||||||
|
* negative values specify an angle downward toward the negative z axis.
|
||||||
|
*
|
||||||
|
* wintab.h defines .orAltitude as a UINT but documents .orAltitude
|
||||||
|
* as positive for upward angles and negative for downward angles.
|
||||||
|
* WACOM uses negative altitude values to show that the pen is inverted;
|
||||||
|
* therefore we cast .orAltitude as an (int) and then use the absolute value.
|
||||||
|
*/
|
||||||
|
|
||||||
/* find length of the stylus' projected vector on the XY plane */
|
/* convert raw fixed point data to radians */
|
||||||
vecLen = cos(altRad);
|
altRad = (float)((fabs((float)ort.orAltitude) / (float)m_wintab.maxAltitude) * M_PI / 2.0);
|
||||||
|
azmRad = (float)(((float)ort.orAzimuth / (float)m_wintab.maxAzimuth) * M_PI * 2.0);
|
||||||
|
|
||||||
/* from there calculate X and Y components based on azimuth */
|
/* find length of the stylus' projected vector on the XY plane */
|
||||||
m_tabletData->Xtilt = sin(azmRad) * vecLen;
|
vecLen = cos(altRad);
|
||||||
m_tabletData->Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
|
|
||||||
|
|
||||||
}
|
/* from there calculate X and Y components based on azimuth */
|
||||||
else {
|
m_tabletData.Xtilt = sin(azmRad) * vecLen;
|
||||||
m_tabletData->Xtilt = 0.0f;
|
m_tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
|
||||||
m_tabletData->Ytilt = 0.0f;
|
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
m_tabletData.Xtilt = 0.0f;
|
||||||
|
m_tabletData.Ytilt = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1002,11 +986,8 @@ void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
|
|||||||
|
|
||||||
void GHOST_WindowWin32::bringTabletContextToFront()
|
void GHOST_WindowWin32::bringTabletContextToFront()
|
||||||
{
|
{
|
||||||
if (m_wintab) {
|
if (m_wintab.overlap && m_wintab.tablet) {
|
||||||
GHOST_WIN32_WTOverlap fpWTOverlap = (GHOST_WIN32_WTOverlap) ::GetProcAddress(m_wintab, "WTOverlap");
|
m_wintab.overlap(m_wintab.tablet, TRUE);
|
||||||
if (fpWTOverlap) {
|
|
||||||
fpWTOverlap(m_tablet, TRUE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +242,7 @@ public:
|
|||||||
|
|
||||||
const GHOST_TabletData *GetTabletData()
|
const GHOST_TabletData *GetTabletData()
|
||||||
{
|
{
|
||||||
return m_tabletData;
|
return &m_tabletData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void processWin32TabletActivateEvent(WORD state);
|
void processWin32TabletActivateEvent(WORD state);
|
||||||
@ -343,16 +343,27 @@ private:
|
|||||||
static const wchar_t *s_windowClassName;
|
static const wchar_t *s_windowClassName;
|
||||||
static const int s_maxTitleLength;
|
static const int s_maxTitleLength;
|
||||||
|
|
||||||
/** WinTab dll handle */
|
|
||||||
HMODULE m_wintab;
|
|
||||||
|
|
||||||
/** Tablet data for GHOST */
|
/** Tablet data for GHOST */
|
||||||
GHOST_TabletData *m_tabletData;
|
GHOST_TabletData m_tabletData;
|
||||||
|
|
||||||
/** Stores the Tablet context if detected Tablet features using WinTab.dll */
|
/* Wintab API */
|
||||||
HCTX m_tablet;
|
struct {
|
||||||
LONG m_maxPressure;
|
/** WinTab dll handle */
|
||||||
LONG m_maxAzimuth, m_maxAltitude;
|
HMODULE handle;
|
||||||
|
|
||||||
|
/** API functions */
|
||||||
|
GHOST_WIN32_WTInfo info;
|
||||||
|
GHOST_WIN32_WTOpen open;
|
||||||
|
GHOST_WIN32_WTClose close;
|
||||||
|
GHOST_WIN32_WTPacket packet;
|
||||||
|
GHOST_WIN32_WTEnable enable;
|
||||||
|
GHOST_WIN32_WTOverlap overlap;
|
||||||
|
|
||||||
|
/** Stores the Tablet context if detected Tablet features using WinTab.dll */
|
||||||
|
HCTX tablet;
|
||||||
|
LONG maxPressure;
|
||||||
|
LONG maxAzimuth, maxAltitude;
|
||||||
|
} m_wintab;
|
||||||
|
|
||||||
GHOST_TWindowState m_normal_state;
|
GHOST_TWindowState m_normal_state;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user