diff options
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/intern/GHOST_System.h | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 148 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.h | 10 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 455 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.h | 118 |
5 files changed, 203 insertions, 530 deletions
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index c404fe21e41..eaaa2ff6ee6 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -238,7 +238,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. */ - virtual void setTabletAPI(GHOST_TTabletAPI api); + void setTabletAPI(GHOST_TTabletAPI api); GHOST_TTabletAPI getTabletAPI(void); #ifdef WITH_INPUT_NDOF diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index b91792938d5..fdd022e44ac 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -938,100 +938,15 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, window->updateMouseCapture(MouseReleased); } - /* 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)) { + if (window->m_tabletInRange) { + 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, 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; + system->getMilliSeconds(), type, window, mask, window->getTabletData()); } void GHOST_SystemWin32::processPointerEvents( @@ -1119,19 +1034,13 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - if (window->m_tabletInRange || window->wintabSysButPressed()) { - if (window->useTabletAPI(GHOST_kTabletWintab) && - processWintabEvents(GHOST_kEventCursorMove, window)) { - return NULL; - } - else if (window->useTabletAPI(GHOST_kTabletNative)) { + if (window->m_tabletInRange) { + 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); @@ -1164,7 +1073,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind window, x_screen + x_accum, y_screen + y_accum, - GHOST_TABLET_DATA_NONE); + window->getTabletData()); } } else { @@ -1173,7 +1082,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind window, x_screen, y_screen, - GHOST_TABLET_DATA_NONE); + window->getTabletData()); } return NULL; } @@ -1284,6 +1193,7 @@ 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); @@ -1311,19 +1221,6 @@ 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; @@ -1559,17 +1456,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, } break; //////////////////////////////////////////////////////////////////////// - // Wintab events, processed + // Tablet events, processed //////////////////////////////////////////////////////////////////////// - case WT_INFOCHANGE: { - window->processWintabInfoChangeEvent(lParam); + case WT_PACKET: + window->processWin32TabletEvent(wParam, lParam); break; - } - case WT_PROXIMITY: { - bool inRange = LOWORD(lParam); - window->processWintabProximityEvent(inRange); + case WT_CSRCHANGE: + case WT_PROXIMITY: + window->processWin32TabletInitEvent(); break; - } //////////////////////////////////////////////////////////////////////// // Pointer events, processed //////////////////////////////////////////////////////////////////////// @@ -1708,9 +1603,7 @@ 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->updateWintab(LOWORD(wParam) != WA_INACTIVE); - + window->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam)); lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); break; } @@ -1768,11 +1661,6 @@ 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(); @@ -1823,12 +1711,6 @@ 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 //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index 05221cbdc40..c6d810d2a38 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -266,16 +266,6 @@ 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. diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 1ca0dd47cbe..b0ba7b6befb 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -72,7 +72,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, bool is_debug, bool dialog) : GHOST_Window(width, height, state, wantStereoVisual, false), - m_tabletInRange(false), m_inLiveResize(false), m_system(system), m_hDC(0), @@ -81,15 +80,19 @@ 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), m_fpGetPointerPenInfoHistory(NULL), m_fpGetPointerTouchInfoHistory(NULL), m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : NULL), - m_debug_context(is_debug) + m_debug_context(is_debug), + m_tabletInRange(false) { + // Initialize tablet variables + memset(&m_wintab, 0, sizeof(m_wintab)); + m_tabletData = GHOST_TABLET_DATA_NONE; + // Create window if (state != GHOST_kWindowStateFullScreen) { RECT rect; @@ -294,25 +297,66 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_user32, "GetPointerTouchInfoHistory"); } - 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); - } + // Initialize Wintab + m_wintab.handle = ::LoadLibrary("Wintab32.dll"); + if (m_wintab.handle) { + // 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); + } + } + } CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } @@ -326,8 +370,8 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } if (m_wintab.handle) { - if (m_wintab.close && m_wintab.context) { - m_wintab.close(m_wintab.context); + if (m_wintab.close && m_wintab.tablet) { + m_wintab.close(m_wintab.tablet); } FreeLibrary(m_wintab.handle); @@ -776,27 +820,6 @@ 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 @@ -1000,103 +1023,6 @@ 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) { @@ -1179,20 +1105,28 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( return GHOST_kSuccess; } -void GHOST_WindowWin32::processWintabDisplayChangeEvent() +void GHOST_WindowWin32::setTabletData(GHOST_TabletData *pTabletData) { - LOGCONTEXT lc_sys = {0}, lc_curr = {0}; - - if (m_wintab.info && m_wintab.get && m_wintab.set && m_wintab.info(WTI_DEFSYSCTX, 0, &lc_sys)) { + if (pTabletData) { + m_tabletData = *pTabletData; + } + else { + m_tabletData = GHOST_TABLET_DATA_NONE; + } +} - m_wintab.get(m_wintab.context, &lc_curr); +void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) +{ + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } - lc_curr.lcOutOrgX = lc_sys.lcOutOrgX; - lc_curr.lcOutOrgY = lc_sys.lcOutOrgY; - lc_curr.lcOutExtX = lc_sys.lcOutExtX; - lc_curr.lcOutExtY = -lc_sys.lcOutExtY; + if (m_wintab.enable && m_wintab.tablet) { + m_wintab.enable(m_wintab.tablet, state); - m_wintab.set(m_wintab.context, &lc_curr); + if (m_wintab.overlap && state) { + m_wintab.overlap(m_wintab.tablet, TRUE); + } } } @@ -1202,7 +1136,7 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const return true; } else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) { - if (m_wintab.numDevices) + if (m_wintab.tablet) return api == GHOST_kTabletWintab; else return api == GHOST_kTabletNative; @@ -1212,180 +1146,115 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const } } -void GHOST_WindowWin32::processWintabProximityEvent(bool inRange) +void GHOST_WindowWin32::processWin32TabletInitEvent() { if (!useTabletAPI(GHOST_kTabletWintab)) { return; } // Let's see if we can initialize tablet here - if (m_wintab.info && m_wintab.context) { + if (m_wintab.info && m_wintab.tablet) { AXIS Pressure, Orientation[3]; /* The maximum tablet size */ BOOL pressureSupport = m_wintab.info(WTI_DEVICES, DVC_NPRESSURE, &Pressure); - m_wintab.maxPressure = pressureSupport ? Pressure.axMax : 0; + if (pressureSupport) + m_wintab.maxPressure = Pressure.axMax; + else + m_wintab.maxPressure = 0; 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) { - 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; + 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; + } } } - m_tabletInRange = inRange; -} - -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; - } + m_tabletData.Active = GHOST_kTabletModeNone; } -GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo) +void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) { if (!useTabletAPI(GHOST_kTabletWintab)) { - return GHOST_kFailure; - } - - if (!(m_wintab.packetsGet && m_wintab.context)) { - return GHOST_kFailure; + return; } - 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.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.maxPressure > 0) { - tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure; - } + if (m_wintab.maxPressure > 0) { + m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure; + } + 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 */ - tabletData.Xtilt = sin(azmRad) * vecLen; - tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen); - } + if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ - outWintabInfo[i].x = pkt.pkX; - outWintabInfo[i].y = pkt.pkY; + /* + * 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. + */ - // Some Wintab libraries don't handle relative button input correctly, so we track button - // presses manually. - DWORD buttonsChanged = m_wintab.sysButtonsPressed ^ pkt.pkButtons; + /* 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 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++; - } + /* find length of the stylus' projected vector on the XY plane */ + vecLen = cos(altRad); - if (buttonsChanged && - wintabMouseToGhost(pkt.pkCursor, physicalButton, outWintabInfo[i].button)) { - if (buttonsChanged & pkt.pkButtons) { - outWintabInfo[i].type = GHOST_kEventButtonDown; + /* 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 { - outWintabInfo[i].type = GHOST_kEventButtonUp; + m_tabletData.Xtilt = 0.0f; + m_tabletData.Ytilt = 0.0f; } } - else { - outWintabInfo[i].type = GHOST_kEventCursorMove; - } - - 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; +void GHOST_WindowWin32::bringTabletContextToFront() +{ + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; } - return GHOST_kSuccess; + if (m_wintab.overlap && m_wintab.tablet) { + m_wintab.overlap(m_wintab.tablet, TRUE); + } } GHOST_TUns16 GHOST_WindowWin32::getDPIHint() diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index d4427f67e9b..2951901ceb4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -36,9 +36,8 @@ #endif #include <wintab.h> -#define PACKETDATA \ - (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR | PK_X | PK_Y | PK_TIME) -#define PACKETMODE 0 +#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR) +#define PACKETMODE PK_BUTTONS #include <pktdef.h> class GHOST_SystemWin32; @@ -46,13 +45,9 @@ 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_WTPacketsGet)(HCTX, int, LPVOID); -typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX); -typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int); +typedef BOOL(API *GHOST_WIN32_WTPacket)(HCTX, UINT, LPVOID); typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL); typedef BOOL(API *GHOST_WIN32_WTOverlap)(HCTX, BOOL); @@ -233,14 +228,7 @@ 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; }; @@ -434,16 +422,12 @@ class GHOST_WindowWin32 : public GHOST_Window { HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const; void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const; - /** - * 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); + const GHOST_TabletData &GetTabletData() + { + return m_tabletData; + } - /** - * Query whether given tablet API should be used. - * \param api Tablet API to test. - */ + void setTabletData(GHOST_TabletData *tabletData); bool useTabletAPI(GHOST_TTabletAPI api) const; /** @@ -456,28 +440,10 @@ class GHOST_WindowWin32 : public GHOST_Window { WPARAM wParam, LPARAM lParam); - /** - * 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); + void processWin32TabletActivateEvent(WORD state); + void processWin32TabletInitEvent(); + void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); + void bringTabletContextToFront(); GHOST_TSuccess beginFullScreen() const { @@ -497,19 +463,6 @@ 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; @@ -593,49 +546,28 @@ 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 = NULL; + HMODULE handle; /** API functions */ - 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; + 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 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; + HCTX tablet; + LONG maxPressure; + LONG maxAzimuth, maxAltitude; } 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*/ |