Revert "Revert "Windows: support high resolution tablet pen events for Wintab""
This reverts commit e90d8422d0
.
This commit is contained in:
parent
c503c5f756
commit
abbdfc8bf7
|
@ -237,7 +237,7 @@ class GHOST_System : public GHOST_ISystem {
|
|||
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
|
||||
* \param api Enum indicating which API to use.
|
||||
*/
|
||||
void setTabletAPI(GHOST_TTabletAPI api);
|
||||
virtual void setTabletAPI(GHOST_TTabletAPI api);
|
||||
GHOST_TTabletAPI getTabletAPI(void);
|
||||
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
|
|
|
@ -941,15 +941,100 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
|
|||
window->updateMouseCapture(MouseReleased);
|
||||
}
|
||||
|
||||
if (window->m_tabletInRange) {
|
||||
if (window->useTabletAPI(GHOST_kTabletNative)) {
|
||||
/* Check for active Wintab mouse emulation in addition to a tablet in range because a proximity
|
||||
* leave event might have fired before the Windows mouse up event, thus there are still tablet
|
||||
* events to grab. The described behavior was observed in a Wacom Bamboo CTE-450.
|
||||
*/
|
||||
if (window->m_tabletInRange || window->wintabSysButPressed()) {
|
||||
if (window->useTabletAPI(GHOST_kTabletWintab) && processWintabEvents(type, window)) {
|
||||
// Wintab processing only handles in-contact events.
|
||||
return NULL;
|
||||
}
|
||||
else if (window->useTabletAPI(GHOST_kTabletNative)) {
|
||||
// Win32 Pointer processing handles input while in-range and in-contact events.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If using Wintab and this was a button down event but no button event was queued while
|
||||
// processing Wintab packets, fall through to create a button event.
|
||||
}
|
||||
|
||||
return new GHOST_EventButton(
|
||||
system->getMilliSeconds(), type, window, mask, window->getTabletData());
|
||||
system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemWin32::processWintabEvents(GHOST_TEventType type,
|
||||
GHOST_WindowWin32 *window)
|
||||
{
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
|
||||
|
||||
/* Only process Wintab packets if we can correlate them to a Window's mouse button event. When a
|
||||
* button event associated to a mouse button by Wintab occurs outside of WM_*BUTTON events,
|
||||
* there's no way to tell if other simultaneously pressed non-mouse mapped buttons are associated
|
||||
* to a modifier key (shift, alt, ctrl) or a system event (scroll, etc.) and thus it is not
|
||||
* possible to determine if a mouse click event should occur.
|
||||
*/
|
||||
if (!window->getMousePressed() && !window->wintabSysButPressed()) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
std::vector<GHOST_WintabInfoWin32> wintabInfo;
|
||||
if (!window->getWintabInfo(wintabInfo)) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
auto wtiIter = wintabInfo.begin();
|
||||
|
||||
/* We only process events that correlate to a mouse button events, so there may exist Wintab
|
||||
* button down events that were instead mapped to e.g. scroll still in the queue. We need to
|
||||
* skip those and find the last button down mapped to mouse buttons.
|
||||
*/
|
||||
if (!window->wintabSysButPressed()) {
|
||||
for (auto it = wtiIter; it != wintabInfo.end(); it++) {
|
||||
if (it->type == GHOST_kEventButtonDown) {
|
||||
wtiIter = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (; wtiIter != wintabInfo.end(); wtiIter++) {
|
||||
auto info = *wtiIter;
|
||||
|
||||
switch (info.type) {
|
||||
case GHOST_kEventButtonDown: {
|
||||
/* While changing windows with a tablet, Window's mouse button events normally occur before
|
||||
* tablet proximity events, so a button up event can't be differentiated as occurring from
|
||||
* a Wintab tablet or a normal mouse and a Ghost button event will always be generated.
|
||||
*
|
||||
* If we were called during a button down event create a ghost button down event, otherwise
|
||||
* don't duplicate the prior button down as it interrupts drawing immediately after
|
||||
* changing a window.
|
||||
*/
|
||||
if (type == GHOST_kEventButtonDown) {
|
||||
// Move cursor to point of contact because GHOST_EventButton does not include position.
|
||||
system->pushEvent(new GHOST_EventCursor(
|
||||
info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
|
||||
system->pushEvent(
|
||||
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
|
||||
}
|
||||
window->updateWintabSysBut(MousePressed);
|
||||
break;
|
||||
}
|
||||
case GHOST_kEventCursorMove:
|
||||
system->pushEvent(new GHOST_EventCursor(
|
||||
info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
|
||||
break;
|
||||
case GHOST_kEventButtonUp:
|
||||
system->pushEvent(
|
||||
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
|
||||
window->updateWintabSysBut(MouseReleased);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
void GHOST_SystemWin32::processPointerEvents(
|
||||
|
@ -1037,13 +1122,19 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
|||
GHOST_TInt32 x_screen, y_screen;
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
|
||||
|
||||
if (window->m_tabletInRange) {
|
||||
if (window->useTabletAPI(GHOST_kTabletNative)) {
|
||||
if (window->m_tabletInRange || window->wintabSysButPressed()) {
|
||||
if (window->useTabletAPI(GHOST_kTabletWintab) &&
|
||||
processWintabEvents(GHOST_kEventCursorMove, window)) {
|
||||
return NULL;
|
||||
}
|
||||
else if (window->useTabletAPI(GHOST_kTabletNative)) {
|
||||
// Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet
|
||||
// input aren't normally generated when using WM_POINTER events, but manually moving the
|
||||
// system cursor as we do in WM_POINTER handling does.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If using Wintab but no button event is currently active, fall through to default handling
|
||||
}
|
||||
|
||||
system->getCursorPosition(x_screen, y_screen);
|
||||
|
@ -1076,7 +1167,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
|||
window,
|
||||
x_screen + x_accum,
|
||||
y_screen + y_accum,
|
||||
window->getTabletData());
|
||||
GHOST_TABLET_DATA_NONE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1085,7 +1176,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
|
|||
window,
|
||||
x_screen,
|
||||
y_screen,
|
||||
window->getTabletData());
|
||||
GHOST_TABLET_DATA_NONE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1202,7 +1293,6 @@ GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type,
|
|||
|
||||
if (type == GHOST_kEventWindowActivate) {
|
||||
system->getWindowManager()->setActiveWindow(window);
|
||||
window->bringTabletContextToFront();
|
||||
}
|
||||
|
||||
return new GHOST_Event(system->getMilliSeconds(), type, window);
|
||||
|
@ -1230,6 +1320,19 @@ GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
|
|||
system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data));
|
||||
}
|
||||
|
||||
void GHOST_SystemWin32::setTabletAPI(GHOST_TTabletAPI api)
|
||||
{
|
||||
GHOST_System::setTabletAPI(api);
|
||||
|
||||
GHOST_WindowManager *wm = getWindowManager();
|
||||
GHOST_WindowWin32 *activeWindow = (GHOST_WindowWin32 *)wm->getActiveWindow();
|
||||
|
||||
for (GHOST_IWindow *win : wm->getWindows()) {
|
||||
GHOST_WindowWin32 *windowsWindow = (GHOST_WindowWin32 *)win;
|
||||
windowsWindow->updateWintab(windowsWindow == activeWindow);
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax)
|
||||
{
|
||||
minmax->ptMinTrackSize.x = 320;
|
||||
|
@ -1467,15 +1570,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
}
|
||||
break;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Tablet events, processed
|
||||
// Wintab events, processed
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
case WT_PACKET:
|
||||
window->processWin32TabletEvent(wParam, lParam);
|
||||
case WT_INFOCHANGE: {
|
||||
window->processWintabInfoChangeEvent(lParam);
|
||||
break;
|
||||
case WT_CSRCHANGE:
|
||||
case WT_PROXIMITY:
|
||||
window->processWin32TabletInitEvent();
|
||||
}
|
||||
case WT_PROXIMITY: {
|
||||
bool inRange = LOWORD(lParam);
|
||||
window->processWintabProximityEvent(inRange);
|
||||
break;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Pointer events, processed
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1614,7 +1719,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
* will not be dispatched to OUR active window if we minimize one of OUR windows. */
|
||||
if (LOWORD(wParam) == WA_INACTIVE)
|
||||
window->lostMouseCapture();
|
||||
window->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam));
|
||||
|
||||
window->updateWintab(LOWORD(wParam) != WA_INACTIVE);
|
||||
|
||||
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
break;
|
||||
}
|
||||
|
@ -1672,6 +1779,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
else {
|
||||
event = processWindowEvent(GHOST_kEventWindowSize, window);
|
||||
}
|
||||
|
||||
if (msg == WM_SIZE && wParam == SIZE_MINIMIZED) {
|
||||
window->updateWintab(false);
|
||||
}
|
||||
|
||||
break;
|
||||
case WM_CAPTURECHANGED:
|
||||
window->lostMouseCapture();
|
||||
|
@ -1722,6 +1834,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
|||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
}
|
||||
break;
|
||||
case WM_DISPLAYCHANGE:
|
||||
for (GHOST_IWindow *iter_win : system->getWindowManager()->getWindows()) {
|
||||
GHOST_WindowWin32 *iter_win32win = (GHOST_WindowWin32 *)iter_win;
|
||||
iter_win32win->processWintabDisplayChangeEvent();
|
||||
}
|
||||
break;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Window events, ignored
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -265,6 +265,16 @@ class GHOST_SystemWin32 : public GHOST_System {
|
|||
int mouseY,
|
||||
void *data);
|
||||
|
||||
/***************************************************************************************
|
||||
** Modify tablet API
|
||||
***************************************************************************************/
|
||||
|
||||
/**
|
||||
* Set which tablet API to use.
|
||||
* \param api Enum indicating which API to use.
|
||||
*/
|
||||
void setTabletAPI(GHOST_TTabletAPI api) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Initializes the system.
|
||||
|
|
|
@ -81,6 +81,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||
m_nPressedButtons(0),
|
||||
m_customCursor(0),
|
||||
m_wantAlphaBackground(alphaBackground),
|
||||
m_wintab(),
|
||||
m_normal_state(GHOST_kWindowStateNormal),
|
||||
m_user32(NULL),
|
||||
m_fpGetPointerInfoHistory(NULL),
|
||||
|
@ -89,10 +90,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||
m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL),
|
||||
m_debug_context(is_debug)
|
||||
{
|
||||
// Initialize tablet variables
|
||||
memset(&m_wintab, 0, sizeof(m_wintab));
|
||||
m_tabletData = GHOST_TABLET_DATA_NONE;
|
||||
|
||||
// Create window
|
||||
if (state != GHOST_kWindowStateFullScreen) {
|
||||
RECT rect;
|
||||
|
@ -297,66 +294,25 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
|
|||
m_user32, "GetPointerTouchInfoHistory");
|
||||
}
|
||||
|
||||
// Initialize Wintab
|
||||
m_wintab.handle = ::LoadLibrary("Wintab32.dll");
|
||||
if (m_wintab.handle && m_system->getTabletAPI() != GHOST_kTabletNative) {
|
||||
// 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.
|
||||
// Check if WinTab available by getting system context info.
|
||||
LOGCONTEXT lc = {0};
|
||||
lc.lcOptions |= CXO_SYSTEM;
|
||||
if (m_wintab.open && m_wintab.info && m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) {
|
||||
// Now init the tablet
|
||||
/* The maximum tablet size, pressure and orientation (tilt) */
|
||||
AXIS TabletX, TabletY, Pressure, Orientation[3];
|
||||
|
||||
// Open a Wintab context
|
||||
|
||||
// Open the context
|
||||
lc.lcPktData = PACKETDATA;
|
||||
lc.lcPktMode = PACKETMODE;
|
||||
lc.lcOptions |= CXO_MESSAGES;
|
||||
lc.lcMoveMask = PACKETDATA;
|
||||
|
||||
/* Set the entire tablet as active */
|
||||
m_wintab.info(WTI_DEVICES, DVC_X, &TabletX);
|
||||
m_wintab.info(WTI_DEVICES, DVC_Y, &TabletY);
|
||||
|
||||
/* get the max pressure, to divide into a float */
|
||||
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
||||
if (pressureSupport)
|
||||
m_wintab.maxPressure = Pressure.axMax;
|
||||
else
|
||||
m_wintab.maxPressure = 0;
|
||||
|
||||
/* get the max tilt axes, to divide into floats */
|
||||
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
||||
if (tiltSupport) {
|
||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||
/* all this assumes the minimum is 0 */
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (m_wintab.enable && m_wintab.tablet) {
|
||||
m_wintab.enable(m_wintab.tablet, TRUE);
|
||||
}
|
||||
}
|
||||
if ((m_wintab.handle = ::LoadLibrary("Wintab32.dll")) &&
|
||||
(m_wintab.info = (GHOST_WIN32_WTInfo)::GetProcAddress(m_wintab.handle, "WTInfoA")) &&
|
||||
(m_wintab.open = (GHOST_WIN32_WTOpen)::GetProcAddress(m_wintab.handle, "WTOpenA")) &&
|
||||
(m_wintab.get = (GHOST_WIN32_WTGet)::GetProcAddress(m_wintab.handle, "WTGetA")) &&
|
||||
(m_wintab.set = (GHOST_WIN32_WTSet)::GetProcAddress(m_wintab.handle, "WTSetA")) &&
|
||||
(m_wintab.close = (GHOST_WIN32_WTClose)::GetProcAddress(m_wintab.handle, "WTClose")) &&
|
||||
(m_wintab.packetsGet = (GHOST_WIN32_WTPacketsGet)::GetProcAddress(m_wintab.handle,
|
||||
"WTPacketsGet")) &&
|
||||
(m_wintab.queueSizeGet = (GHOST_WIN32_WTQueueSizeGet)::GetProcAddress(m_wintab.handle,
|
||||
"WTQueueSizeGet")) &&
|
||||
(m_wintab.queueSizeSet = (GHOST_WIN32_WTQueueSizeSet)::GetProcAddress(m_wintab.handle,
|
||||
"WTQueueSizeSet")) &&
|
||||
(m_wintab.enable = (GHOST_WIN32_WTEnable)::GetProcAddress(m_wintab.handle, "WTEnable")) &&
|
||||
(m_wintab.overlap = (GHOST_WIN32_WTOverlap)::GetProcAddress(m_wintab.handle, "WTOverlap"))) {
|
||||
initializeWintab();
|
||||
// Determine which tablet API to use and enable it.
|
||||
updateWintab(true);
|
||||
}
|
||||
|
||||
CoCreateInstance(
|
||||
CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
|
||||
}
|
||||
|
@ -370,8 +326,8 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
|
|||
}
|
||||
|
||||
if (m_wintab.handle) {
|
||||
if (m_wintab.close && m_wintab.tablet) {
|
||||
m_wintab.close(m_wintab.tablet);
|
||||
if (m_wintab.close && m_wintab.context) {
|
||||
m_wintab.close(m_wintab.context);
|
||||
}
|
||||
|
||||
FreeLibrary(m_wintab.handle);
|
||||
|
@ -819,6 +775,27 @@ bool GHOST_WindowWin32::getMousePressed() const
|
|||
return m_nPressedButtons;
|
||||
}
|
||||
|
||||
bool GHOST_WindowWin32::wintabSysButPressed() const
|
||||
{
|
||||
return m_wintab.numSysButtons;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::updateWintabSysBut(GHOST_MouseCaptureEventWin32 event)
|
||||
{
|
||||
switch (event) {
|
||||
case MousePressed:
|
||||
m_wintab.numSysButtons++;
|
||||
break;
|
||||
case MouseReleased:
|
||||
if (m_wintab.numSysButtons)
|
||||
m_wintab.numSysButtons--;
|
||||
break;
|
||||
case OperatorGrab:
|
||||
case OperatorUngrab:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HCURSOR GHOST_WindowWin32::getStandardCursor(GHOST_TStandardCursor shape) const
|
||||
{
|
||||
// Convert GHOST cursor to Windows OEM cursor
|
||||
|
@ -1022,6 +999,103 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha
|
|||
return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::updateWintab(bool active)
|
||||
{
|
||||
if (m_wintab.enable && m_wintab.overlap && m_wintab.context) {
|
||||
bool useWintab = useTabletAPI(GHOST_kTabletWintab);
|
||||
bool enable = active && useWintab;
|
||||
|
||||
// Disabling context while the Window is not minimized can cause issues on receiving Wintab
|
||||
// input while changing a window for some drivers, so only disable if either Wintab had been
|
||||
// disabled or the window is minimized.
|
||||
m_wintab.enable(m_wintab.context, useWintab && !::IsIconic(m_hWnd));
|
||||
m_wintab.overlap(m_wintab.context, enable);
|
||||
|
||||
if (!enable) {
|
||||
// WT_PROXIMITY event doesn't occur unless tablet's cursor leaves the proximity while the
|
||||
// window is active.
|
||||
m_tabletInRange = false;
|
||||
m_wintab.numSysButtons = 0;
|
||||
m_wintab.sysButtonsPressed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::initializeWintab()
|
||||
{
|
||||
// return if wintab library handle doesn't exist or wintab is already initialized
|
||||
if (!m_wintab.handle || m_wintab.context) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's see if we can initialize tablet here.
|
||||
// Check if WinTab available by getting system context info.
|
||||
LOGCONTEXT lc = {0};
|
||||
if (m_wintab.open && m_wintab.info && m_wintab.queueSizeGet && m_wintab.queueSizeSet &&
|
||||
m_wintab.info(WTI_DEFSYSCTX, 0, &lc)) {
|
||||
// Now init the tablet
|
||||
/* The pressure and orientation (tilt) */
|
||||
AXIS Pressure, Orientation[3];
|
||||
|
||||
// Open a Wintab context
|
||||
|
||||
// Open the context
|
||||
lc.lcPktData = PACKETDATA;
|
||||
lc.lcPktMode = PACKETMODE;
|
||||
lc.lcMoveMask = PACKETDATA;
|
||||
// Wacom maps y origin to the tablet's bottom
|
||||
// Invert to match Windows y origin mapping to the screen top
|
||||
lc.lcOutExtY = -lc.lcOutExtY;
|
||||
|
||||
m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices);
|
||||
|
||||
/* get the max pressure, to divide into a float */
|
||||
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
||||
m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0;
|
||||
|
||||
/* get the max tilt axes, to divide into floats */
|
||||
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||
if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||
/* all this assumes the minimum is 0 */
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
|
||||
// The Wintab spec says we must open the context disabled if we are using cursor masks.
|
||||
m_wintab.context = m_wintab.open(m_hWnd, &lc, FALSE);
|
||||
|
||||
// Wintab provides no way to determine the maximum queue size aside from checking if attempts
|
||||
// to change the queue size are successful.
|
||||
const int maxQueue = 500;
|
||||
int queueSize = m_wintab.queueSizeGet(m_wintab.context);
|
||||
|
||||
while (queueSize < maxQueue) {
|
||||
int testSize = min(queueSize + 16, maxQueue);
|
||||
if (m_wintab.queueSizeSet(m_wintab.context, testSize)) {
|
||||
queueSize = testSize;
|
||||
}
|
||||
else {
|
||||
/* From Windows Wintab Documentation for WTQueueSizeSet:
|
||||
* "If the return value is zero, the context has no queue because the function deletes the
|
||||
* original queue before attempting to create a new one. The application must continue
|
||||
* calling the function with a smaller queue size until the function returns a non - zero
|
||||
* value."
|
||||
*
|
||||
* In our case we start with a known valid queue size and in the event of failure roll
|
||||
* back to the last valid queue size.
|
||||
*/
|
||||
m_wintab.queueSizeSet(m_wintab.context, queueSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_wintab.pkts.resize(queueSize);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
|
||||
std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
@ -1104,28 +1178,20 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
|
|||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData)
|
||||
void GHOST_WindowWin32::processWintabDisplayChangeEvent()
|
||||
{
|
||||
if (pTabletData) {
|
||||
m_tabletData = *pTabletData;
|
||||
}
|
||||
else {
|
||||
m_tabletData = GHOST_TABLET_DATA_NONE;
|
||||
}
|
||||
}
|
||||
LOGCONTEXT lc_sys = {0}, lc_curr = {0};
|
||||
|
||||
void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state)
|
||||
{
|
||||
if (!useTabletAPI(GHOST_kTabletWintab)) {
|
||||
return;
|
||||
}
|
||||
if (m_wintab.info && m_wintab.get && m_wintab.set && m_wintab.info(WTI_DEFSYSCTX, 0, &lc_sys)) {
|
||||
|
||||
if (m_wintab.enable && m_wintab.tablet) {
|
||||
m_wintab.enable(m_wintab.tablet, state);
|
||||
m_wintab.get(m_wintab.context, &lc_curr);
|
||||
|
||||
if (m_wintab.overlap && state) {
|
||||
m_wintab.overlap(m_wintab.tablet, TRUE);
|
||||
}
|
||||
lc_curr.lcOutOrgX = lc_sys.lcOutOrgX;
|
||||
lc_curr.lcOutOrgY = lc_sys.lcOutOrgY;
|
||||
lc_curr.lcOutExtX = lc_sys.lcOutExtX;
|
||||
lc_curr.lcOutExtY = -lc_sys.lcOutExtY;
|
||||
|
||||
m_wintab.set(m_wintab.context, &lc_curr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1135,7 +1201,7 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const
|
|||
return true;
|
||||
}
|
||||
else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
|
||||
if (m_wintab.tablet)
|
||||
if (m_wintab.numDevices)
|
||||
return api == GHOST_kTabletWintab;
|
||||
else
|
||||
return api == GHOST_kTabletNative;
|
||||
|
@ -1145,115 +1211,180 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const
|
|||
}
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::processWin32TabletInitEvent()
|
||||
void GHOST_WindowWin32::processWintabProximityEvent(bool inRange)
|
||||
{
|
||||
if (!useTabletAPI(GHOST_kTabletWintab)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's see if we can initialize tablet here
|
||||
if (m_wintab.info && m_wintab.tablet) {
|
||||
if (m_wintab.info && m_wintab.context) {
|
||||
AXIS Pressure, Orientation[3]; /* The maximum tablet size */
|
||||
|
||||
BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
|
||||
if (pressureSupport)
|
||||
m_wintab.maxPressure = Pressure.axMax;
|
||||
else
|
||||
m_wintab.maxPressure = 0;
|
||||
m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0;
|
||||
|
||||
BOOL tiltSupport = m_wintab.info(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
|
||||
if (tiltSupport) {
|
||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||
if (Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
/* does the tablet support azimuth ([0]) and altitude ([1]) */
|
||||
if (tiltSupport && Orientation[0].axResolution && Orientation[1].axResolution) {
|
||||
m_wintab.maxAzimuth = Orientation[0].axMax;
|
||||
m_wintab.maxAltitude = Orientation[1].axMax;
|
||||
}
|
||||
else { /* no so dont do tilt stuff */
|
||||
m_wintab.maxAzimuth = m_wintab.maxAltitude = 0;
|
||||
}
|
||||
}
|
||||
|
||||
m_tabletData.Active = GHOST_kTabletModeNone;
|
||||
m_tabletInRange = inRange;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
|
||||
void GHOST_WindowWin32::processWintabInfoChangeEvent(LPARAM lParam)
|
||||
{
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
|
||||
|
||||
// Update number of connected Wintab digitizers
|
||||
if (LOWORD(lParam) == WTI_INTERFACE && HIWORD(lParam) == IFC_NDEVICES) {
|
||||
m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices);
|
||||
updateWintab((GHOST_WindowWin32 *)system->getWindowManager()->getActiveWindow() == this);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWin32::wintabMouseToGhost(UINT cursor,
|
||||
DWORD physicalButton,
|
||||
GHOST_TButtonMask &ghostButton)
|
||||
{
|
||||
const DWORD numButtons = 32;
|
||||
BYTE logicalButtons[numButtons] = {0};
|
||||
BYTE systemButtons[numButtons] = {0};
|
||||
|
||||
m_wintab.info(WTI_CURSORS + cursor, CSR_BUTTONMAP, &logicalButtons);
|
||||
m_wintab.info(WTI_CURSORS + cursor, CSR_SYSBTNMAP, &systemButtons);
|
||||
|
||||
if (physicalButton >= numButtons) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
BYTE lb = logicalButtons[physicalButton];
|
||||
|
||||
if (lb >= numButtons) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
switch (systemButtons[lb]) {
|
||||
case SBN_LCLICK:
|
||||
ghostButton = GHOST_kButtonMaskLeft;
|
||||
return GHOST_kSuccess;
|
||||
case SBN_RCLICK:
|
||||
ghostButton = GHOST_kButtonMaskRight;
|
||||
return GHOST_kSuccess;
|
||||
case SBN_MCLICK:
|
||||
ghostButton = GHOST_kButtonMaskMiddle;
|
||||
return GHOST_kSuccess;
|
||||
default:
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
|
||||
{
|
||||
if (!useTabletAPI(GHOST_kTabletWintab)) {
|
||||
return;
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (m_wintab.packet && m_wintab.tablet) {
|
||||
PACKET pkt;
|
||||
if (m_wintab.packet((HCTX)lParam, wParam, &pkt)) {
|
||||
switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
|
||||
case 0:
|
||||
m_tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
|
||||
break;
|
||||
case 1:
|
||||
m_tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
|
||||
break;
|
||||
case 2:
|
||||
m_tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
|
||||
break;
|
||||
}
|
||||
if (!(m_wintab.packetsGet && m_wintab.context)) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (m_wintab.maxPressure > 0) {
|
||||
m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
|
||||
|
||||
const int numPackets = m_wintab.packetsGet(
|
||||
m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data());
|
||||
outWintabInfo.resize(numPackets);
|
||||
|
||||
for (int i = 0; i < numPackets; i++) {
|
||||
PACKET pkt = m_wintab.pkts[i];
|
||||
GHOST_TabletData tabletData = GHOST_TABLET_DATA_NONE;
|
||||
switch (pkt.pkCursor % 3) { /* % 3 for multiple devices ("DualTrack") */
|
||||
case 0:
|
||||
tabletData.Active = GHOST_kTabletModeNone; /* puck - not yet supported */
|
||||
break;
|
||||
case 1:
|
||||
tabletData.Active = GHOST_kTabletModeStylus; /* stylus */
|
||||
break;
|
||||
case 2:
|
||||
tabletData.Active = GHOST_kTabletModeEraser; /* eraser */
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_wintab.maxPressure > 0) {
|
||||
tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure;
|
||||
}
|
||||
|
||||
if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
|
||||
ORIENTATION ort = pkt.pkOrientation;
|
||||
float vecLen;
|
||||
float altRad, azmRad; /* in radians */
|
||||
|
||||
/*
|
||||
* from the wintab spec:
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* convert raw fixed point data to radians */
|
||||
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);
|
||||
|
||||
/* find length of the stylus' projected vector on the XY plane */
|
||||
vecLen = cos(altRad);
|
||||
|
||||
/* from there calculate X and Y components based on azimuth */
|
||||
tabletData.Xtilt = sin(azmRad) * vecLen;
|
||||
tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
|
||||
}
|
||||
|
||||
outWintabInfo[i].x = pkt.pkX;
|
||||
outWintabInfo[i].y = pkt.pkY;
|
||||
|
||||
// Some Wintab libraries don't handle relative button input correctly, so we track button
|
||||
// presses manually.
|
||||
DWORD buttonsChanged = m_wintab.sysButtonsPressed ^ pkt.pkButtons;
|
||||
|
||||
// Find the index for the changed button from the button map.
|
||||
DWORD physicalButton = 0;
|
||||
for (DWORD diff = (unsigned)buttonsChanged >> 1; diff > 0; diff = (unsigned)diff >> 1) {
|
||||
physicalButton++;
|
||||
}
|
||||
|
||||
if (buttonsChanged &&
|
||||
wintabMouseToGhost(pkt.pkCursor, physicalButton, outWintabInfo[i].button)) {
|
||||
if (buttonsChanged & pkt.pkButtons) {
|
||||
outWintabInfo[i].type = GHOST_kEventButtonDown;
|
||||
}
|
||||
else {
|
||||
m_tabletData.Pressure = 1.0f;
|
||||
}
|
||||
|
||||
if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) {
|
||||
ORIENTATION ort = pkt.pkOrientation;
|
||||
float vecLen;
|
||||
float altRad, azmRad; /* in radians */
|
||||
|
||||
/*
|
||||
* from the wintab spec:
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* convert raw fixed point data to radians */
|
||||
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);
|
||||
|
||||
/* find length of the stylus' projected vector on the XY plane */
|
||||
vecLen = cos(altRad);
|
||||
|
||||
/* from there calculate X and Y components based on azimuth */
|
||||
m_tabletData.Xtilt = sin(azmRad) * vecLen;
|
||||
m_tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
|
||||
}
|
||||
else {
|
||||
m_tabletData.Xtilt = 0.0f;
|
||||
m_tabletData.Ytilt = 0.0f;
|
||||
outWintabInfo[i].type = GHOST_kEventButtonUp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
outWintabInfo[i].type = GHOST_kEventCursorMove;
|
||||
}
|
||||
|
||||
void GHOST_WindowWin32::bringTabletContextToFront()
|
||||
{
|
||||
if (!useTabletAPI(GHOST_kTabletWintab)) {
|
||||
return;
|
||||
m_wintab.sysButtonsPressed = pkt.pkButtons;
|
||||
|
||||
// Wintab does not support performance counters, so use low frequency counter instead
|
||||
outWintabInfo[i].time = system->tickCountToMillis(pkt.pkTime);
|
||||
outWintabInfo[i].tabletData = tabletData;
|
||||
}
|
||||
|
||||
if (m_wintab.overlap && m_wintab.tablet) {
|
||||
m_wintab.overlap(m_wintab.tablet, TRUE);
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TUns16 GHOST_WindowWin32::getDPIHint()
|
||||
|
|
|
@ -37,8 +37,9 @@
|
|||
#include <vector>
|
||||
|
||||
#include <wintab.h>
|
||||
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
|
||||
#define PACKETMODE PK_BUTTONS
|
||||
#define PACKETDATA \
|
||||
(PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME)
|
||||
#define PACKETMODE 0
|
||||
#include <pktdef.h>
|
||||
|
||||
class GHOST_SystemWin32;
|
||||
|
@ -46,9 +47,13 @@ class GHOST_DropTargetWin32;
|
|||
|
||||
// typedefs for WinTab functions to allow dynamic loading
|
||||
typedef UINT(API *GHOST_WIN32_WTInfo)(UINT, UINT, LPVOID);
|
||||
typedef BOOL(API *GHOST_WIN32_WTGet)(HCTX, LPLOGCONTEXTA);
|
||||
typedef BOOL(API *GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA);
|
||||
typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL);
|
||||
typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX);
|
||||
typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID);
|
||||
typedef BOOL(API *GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID);
|
||||
typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX);
|
||||
typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int);
|
||||
typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
|
||||
typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL);
|
||||
|
||||
|
@ -229,7 +234,14 @@ struct GHOST_PointerInfoWin32 {
|
|||
GHOST_TButtonMask buttonMask;
|
||||
POINT pixelLocation;
|
||||
GHOST_TUns64 time;
|
||||
GHOST_TabletData tabletData;
|
||||
};
|
||||
|
||||
struct GHOST_WintabInfoWin32 {
|
||||
GHOST_TInt32 x, y;
|
||||
GHOST_TEventType type;
|
||||
GHOST_TButtonMask button;
|
||||
GHOST_TUns64 time;
|
||||
GHOST_TabletData tabletData;
|
||||
};
|
||||
|
||||
|
@ -423,12 +435,16 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const;
|
||||
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const;
|
||||
|
||||
const GHOST_TabletData &getTabletData()
|
||||
{
|
||||
return m_tabletData;
|
||||
}
|
||||
/**
|
||||
* Handle setup and switch between Wintab and Pointer APIs
|
||||
* \param active Whether the window is or will be in an active state
|
||||
*/
|
||||
void updateWintab(bool active);
|
||||
|
||||
void setTabletData(GHOST_TabletData *tabletData);
|
||||
/**
|
||||
* Query whether given tablet API should be used.
|
||||
* \param api Tablet API to test.
|
||||
*/
|
||||
bool useTabletAPI(GHOST_TTabletAPI api) const;
|
||||
|
||||
/**
|
||||
|
@ -441,10 +457,28 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
void processWin32TabletActivateEvent(WORD state);
|
||||
void processWin32TabletInitEvent();
|
||||
void processWin32TabletEvent(WPARAM wParam, LPARAM lParam);
|
||||
void bringTabletContextToFront();
|
||||
/**
|
||||
* Handle Wintab coordinate changes when DisplayChange events occur.
|
||||
*/
|
||||
void processWintabDisplayChangeEvent();
|
||||
|
||||
/**
|
||||
* Set tablet details when a cursor enters range
|
||||
*/
|
||||
void processWintabProximityEvent(bool inRange);
|
||||
|
||||
/**
|
||||
* Handle Wintab info changes such as change in number of connected tablets.
|
||||
* \param lParam LPARAM of the event
|
||||
*/
|
||||
void processWintabInfoChangeEvent(LPARAM lParam);
|
||||
|
||||
/**
|
||||
* Translate Wintab packets into GHOST_WintabInfoWin32 structs.
|
||||
* \param outWintabInfo Storage to return resulting GHOST_WintabInfoWin32 structs
|
||||
* \return Success if able to read packets, even if there are none
|
||||
*/
|
||||
GHOST_TSuccess getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
|
||||
|
||||
GHOST_TSuccess beginFullScreen() const
|
||||
{
|
||||
|
@ -464,6 +498,19 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
*/
|
||||
bool getMousePressed() const;
|
||||
|
||||
/**
|
||||
* Get if there are currently pressed Wintab buttons associated to a Windows mouse button press
|
||||
* \return True if there are currently any pressed Wintab buttons associated to a Windows
|
||||
* mouse button press
|
||||
*/
|
||||
bool wintabSysButPressed() const;
|
||||
|
||||
/**
|
||||
* Register a Wintab button has been associated to a Windows mouse button press
|
||||
* \param event Whether the button was pressed or released
|
||||
*/
|
||||
void updateWintabSysBut(GHOST_MouseCaptureEventWin32 event);
|
||||
|
||||
/** Whether a tablet stylus is being tracked */
|
||||
bool m_tabletInRange;
|
||||
|
||||
|
@ -547,28 +594,49 @@ class GHOST_WindowWin32 : public GHOST_Window {
|
|||
static const wchar_t *s_windowClassName;
|
||||
static const int s_maxTitleLength;
|
||||
|
||||
/** Tablet data for GHOST */
|
||||
GHOST_TabletData m_tabletData;
|
||||
|
||||
/* Wintab API */
|
||||
struct {
|
||||
/** WinTab dll handle */
|
||||
HMODULE handle;
|
||||
HMODULE handle = NULL;
|
||||
|
||||
/** 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;
|
||||
GHOST_WIN32_WTInfo info = NULL;
|
||||
GHOST_WIN32_WTGet get = NULL;
|
||||
GHOST_WIN32_WTSet set = NULL;
|
||||
GHOST_WIN32_WTOpen open = NULL;
|
||||
GHOST_WIN32_WTClose close = NULL;
|
||||
GHOST_WIN32_WTPacketsGet packetsGet = NULL;
|
||||
GHOST_WIN32_WTQueueSizeGet queueSizeGet = NULL;
|
||||
GHOST_WIN32_WTQueueSizeSet queueSizeSet = NULL;
|
||||
GHOST_WIN32_WTEnable enable = NULL;
|
||||
GHOST_WIN32_WTOverlap overlap = NULL;
|
||||
|
||||
/** Stores the Tablet context if detected Tablet features using WinTab.dll */
|
||||
HCTX tablet;
|
||||
LONG maxPressure;
|
||||
LONG maxAzimuth, maxAltitude;
|
||||
HCTX context = NULL;
|
||||
/** Number of connected Wintab digitizers */
|
||||
UINT numDevices = 0;
|
||||
/** Number of cursors currently in contact mapped to system buttons */
|
||||
GHOST_TUns8 numSysButtons = 0;
|
||||
/** Cursors currently in contact mapped to system buttons */
|
||||
DWORD sysButtonsPressed = 0;
|
||||
LONG maxPressure = 0;
|
||||
LONG maxAzimuth = 0, maxAltitude = 0;
|
||||
/* Queue size doesn't change once set, so reuse the same buffer */
|
||||
std::vector<PACKET> pkts;
|
||||
} m_wintab;
|
||||
|
||||
/**
|
||||
* Wintab setup
|
||||
*/
|
||||
void initializeWintab();
|
||||
|
||||
/**
|
||||
* Convert Wintab system mapped (mouse) buttons into Ghost button mask
|
||||
*/
|
||||
GHOST_TSuccess wintabMouseToGhost(UINT cursor,
|
||||
DWORD physicalButton,
|
||||
GHOST_TButtonMask &buttonMask);
|
||||
|
||||
GHOST_TWindowState m_normal_state;
|
||||
|
||||
/** user32 dll handle*/
|
||||
|
|
Loading…
Reference in New Issue