diff options
author | Nicholas Rishel <rishel.nick@gmail.com> | 2021-02-16 10:27:21 +0300 |
---|---|---|
committer | Nicholas Rishel <rishel.nick@gmail.com> | 2021-02-16 10:27:21 +0300 |
commit | dd79a715c98147dd1603b867502d3d8a0c8ca777 (patch) | |
tree | 8025b6f3fbc6449f100a32a7fc1a932c50ccfc10 /intern/ghost | |
parent | 63fb53ad95dc21cc6f8647e4a157ddefa938e28f (diff) | |
parent | 2e81f2c01abd21fdbc79625f3f7a0778103fa199 (diff) |
Merge branch 'blender-v2.92-release'
# Conflicts:
# intern/ghost/intern/GHOST_SystemWin32.cpp
# intern/ghost/intern/GHOST_WindowWin32.cpp
# intern/ghost/intern/GHOST_WindowWin32.h
Diffstat (limited to 'intern/ghost')
-rw-r--r-- | intern/ghost/intern/GHOST_System.h | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 226 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.h | 19 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 449 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.h | 122 |
5 files changed, 237 insertions, 581 deletions
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 279f90b9641..2a7123b293e 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -239,7 +239,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 fb53357bb24..1e79d9dbaaf 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -237,11 +237,6 @@ GHOST_SystemWin32::~GHOST_SystemWin32() toggleConsole(1); } -GHOST_TUns64 GHOST_SystemWin32::millisSinceStart(__int64 ms) const -{ - return (GHOST_TUns64)(ms - m_start * 1000 / m_freq); -} - GHOST_TUns64 GHOST_SystemWin32::performanceCounterToMillis(__int64 perf_ticks) const { // Calculate the time passed since system initialization. @@ -955,101 +950,25 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, { GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - GHOST_TabletData td = window->m_tabletInRange ? window->getLastTabletData() : - GHOST_TABLET_DATA_NONE; + GHOST_TabletData td = GHOST_TABLET_DATA_NONE; - /* Move mouse to button event position. */ - if (!window->m_tabletInRange) { - processCursorEvent(window); - } - else { - /* Tablet should be handling in between mouse moves, only move to event position. */ + if (window->m_tabletInRange) { + td = window->getTabletData(); + + /* Check if tablet cursor position is in sync with Win32 cursor position, if not then move + * cursor to position where button event occurred. */ DWORD msgPos = ::GetMessagePos(); int msgPosX = GET_X_LPARAM(msgPos); int msgPosY = GET_Y_LPARAM(msgPos); - system->pushEvent(new GHOST_EventCursor( - ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td)); + if (msgPosX != system->m_mousePosX || msgPosY != system->m_mousePosY) { + system->pushEvent(new GHOST_EventCursor( + ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td)); + } } - window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased); return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); } -void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) -{ - GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - - std::vector<GHOST_WintabInfoWin32> wintabInfo; - if (!window->getWintabInfo(wintabInfo)) { - return; - } - - for (auto info : wintabInfo) { - switch (info.type) { - case GHOST_kEventCursorMove: { - system->pushEvent(new GHOST_EventCursor( - info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); - break; - } - case GHOST_kEventButtonDown: { - system->pushEvent(new GHOST_EventCursor( - info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); - - UINT message; - switch (info.button) { - case GHOST_kButtonMaskLeft: - message = WM_LBUTTONDOWN; - break; - case GHOST_kButtonMaskRight: - message = WM_RBUTTONDOWN; - break; - case GHOST_kButtonMaskMiddle: - message = WM_MBUTTONDOWN; - break; - default: - continue; - } - - MSG msg; - if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) && - WM_QUIT != msg.message) { - window->updateMouseCapture(MousePressed); - system->pushEvent( - new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); - } - break; - } - case GHOST_kEventButtonUp: { - UINT message; - switch (info.button) { - case GHOST_kButtonMaskLeft: - message = WM_LBUTTONUP; - break; - case GHOST_kButtonMaskRight: - message = WM_RBUTTONUP; - break; - case GHOST_kButtonMaskMiddle: - message = WM_MBUTTONUP; - break; - default: - continue; - } - - MSG msg; - if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) && - WM_QUIT != msg.message) { - window->updateMouseCapture(MouseReleased); - system->pushEvent( - new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); - } - break; - } - default: - break; - } - } -} - void GHOST_SystemWin32::processPointerEvent( UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) { @@ -1129,12 +1048,15 @@ void GHOST_SystemWin32::processPointerEvent( void GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) { - /* Cursor moves handled by tablets while active. */ - if (window->m_tabletInRange) { + if (window->m_tabletInRange && 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; } GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); + GHOST_TabletData td = window->getTabletData(); DWORD msgPos = ::GetMessagePos(); LONG msgTime = ::GetMessageTime(); @@ -1185,13 +1107,13 @@ void GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) window, points[i].x + x_accum, points[i].y + y_accum, - GHOST_TABLET_DATA_NONE)); + td)); } DWORD lastTimestamp = points[0].time; /* Check if we need to wrap the cursor. */ - if (window->getCursorGrabModeIsWarp()) { + if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { /* Wrap based on current cursor position in case Win32 mouse move queue is out of order due to * prior wrap. */ POINT point; @@ -1334,23 +1256,6 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA return event; } -GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window) -{ - GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - GHOST_Event *sizeEvent = new GHOST_Event( - system->getMilliSeconds(), GHOST_kEventWindowSize, window); - - /* We get WM_SIZE before we fully init. Do not dispatch before we are continuously resizing. */ - if (window->m_inLiveResize) { - system->pushEvent(sizeEvent); - system->dispatchEvents(); - return NULL; - } - else { - return sizeEvent; - } -} - GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_WindowWin32 *window) { @@ -1358,6 +1263,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); @@ -1385,18 +1291,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(); - - for (GHOST_IWindow *win : wm->getWindows()) { - GHOST_WindowWin32 *windowWin32 = (GHOST_WindowWin32 *)win; - windowWin32->setWintabEnabled(windowWin32->useTabletAPI(GHOST_kTabletWintab)); - } -} - void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax) { minmax->ptMinTrackSize.x = 320; @@ -1630,30 +1524,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, //////////////////////////////////////////////////////////////////////// // Wintab events, processed //////////////////////////////////////////////////////////////////////// - case WT_INFOCHANGE: { + case WT_INFOCHANGE: window->processWintabInfoChangeEvent(lParam); eventHandled = true; break; - } - case WT_CSRCHANGE: - window->updateWintabCursorInfo(); - eventHandled = true; - break; - case WT_PROXIMITY: { - if (window->useTabletAPI(GHOST_kTabletWintab)) { - if (LOWORD(lParam)) { - window->m_tabletInRange = true; - } - else { - window->processWintabLeave(); - } - } - eventHandled = true; - break; - } case WT_PACKET: - processWintabEvent(window); - eventHandled = true; + window->processWin32TabletEvent(wParam, lParam); + break; + case WT_CSRCHANGE: + case WT_PROXIMITY: + window->processWin32TabletInitEvent(); break; //////////////////////////////////////////////////////////////////////// // Pointer events, processed @@ -1669,53 +1549,52 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, // Mouse events, processed //////////////////////////////////////////////////////////////////////// case WM_LBUTTONDOWN: + window->updateMouseCapture(MousePressed); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); break; case WM_MBUTTONDOWN: + window->updateMouseCapture(MousePressed); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); break; case WM_RBUTTONDOWN: + window->updateMouseCapture(MousePressed); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskRight); break; case WM_XBUTTONDOWN: if ((short)HIWORD(wParam) == XBUTTON1) { + window->updateMouseCapture(MousePressed); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton4); } else if ((short)HIWORD(wParam) == XBUTTON2) { + window->updateMouseCapture(MousePressed); event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskButton5); } break; case WM_LBUTTONUP: + window->updateMouseCapture(MouseReleased); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskLeft); break; case WM_MBUTTONUP: + window->updateMouseCapture(MouseReleased); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskMiddle); break; case WM_RBUTTONUP: + window->updateMouseCapture(MouseReleased); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskRight); break; case WM_XBUTTONUP: if ((short)HIWORD(wParam) == XBUTTON1) { + window->updateMouseCapture(MouseReleased); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); } else if ((short)HIWORD(wParam) == XBUTTON2) { + window->updateMouseCapture(MouseReleased); event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); } break; case WM_MOUSEMOVE: - if (!window->m_mousePresent) { - TRACKMOUSEEVENT tme = {sizeof(tme)}; - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd; - TrackMouseEvent(&tme); - window->m_mousePresent = true; - window->setWintabOverlap(true); - } - - if (!window->m_tabletInRange) { - processCursorEvent(window); - eventHandled = true; - } + processCursorEvent(window); + eventHandled = true; break; case WM_MOUSEWHEEL: { /* The WM_MOUSEWHEEL message is sent to the focus window @@ -1757,13 +1636,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, window->loadCursor(true, GHOST_kStandardCursorDefault); } break; - case WM_MOUSELEAVE: - window->m_mousePresent = false; - window->setWintabOverlap(false); - if (!window->m_tabletInRange) { - processCursorEvent(window); - } - break; + //////////////////////////////////////////////////////////////////////// // Mouse events, ignored //////////////////////////////////////////////////////////////////////// @@ -1779,6 +1652,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * is sent to the window that has captured the mouse. */ break; + //////////////////////////////////////////////////////////////////////// // Window events, processed //////////////////////////////////////////////////////////////////////// @@ -1810,7 +1684,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->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam)); lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); break; } @@ -1852,8 +1726,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, /* Let DefWindowProc handle it. */ break; case WM_SIZING: - event = processWindowSizeEvent(window); - break; case WM_SIZE: /* The WM_SIZE message is sent to a window after its size has changed. * The WM_SIZE and WM_MOVE messages are not sent if an application handles the @@ -1861,15 +1733,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, * to perform any move or size change processing during the WM_WINDOWPOSCHANGED * message without calling DefWindowProc. */ - event = processWindowSizeEvent(window); - - if (wParam == SIZE_MINIMIZED) { - window->setWintabEnabled(false); + /* we get first WM_SIZE before we fully init. + * So, do not dispatch before we continuously resizing. */ + if (window->m_inLiveResize) { + system->pushEvent(processWindowEvent(GHOST_kEventWindowSize, window)); + system->dispatchEvents(); } - else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED) { - window->setWintabEnabled(true); + else { + event = processWindowEvent(GHOST_kEventWindowSize, window); } - break; case WM_CAPTURECHANGED: window->lostMouseCapture(); @@ -1920,12 +1792,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 8ae0b0927c3..86c443bb1c7 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -64,8 +64,6 @@ class GHOST_SystemWin32 : public GHOST_System { ** Time(r) functionality ***************************************************************************************/ - GHOST_TUns64 millisSinceStart(__int64 ms) const; - /** * This method converts performance counter measurements into milliseconds since the start of the * system process. @@ -267,16 +265,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. @@ -369,13 +357,6 @@ class GHOST_SystemWin32 : public GHOST_System { GHOST_TKey processSpecialKey(short vKey, short scanCode) const; /** - * Creates a window size event. - * \param window: The window receiving the event (the active window). - * \return The event created. - */ - static GHOST_Event *processWindowSizeEvent(GHOST_WindowWin32 *window); - - /** * Creates a window event. * \param type: The type of event to create. * \param window: The window receiving the event (the active window). diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 2de86ff21fb..1a4ed753112 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_mousePresent(false), m_tabletInRange(false), m_inLiveResize(false), m_system(system), @@ -82,7 +81,6 @@ 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), @@ -94,6 +92,11 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0); RECT win_rect = {left, top, (long)(left + width), (long)(top + height)}; RECT parent_rect = {0, 0, 0, 0}; + + // Initialize tablet variables + memset(&m_wintab, 0, sizeof(m_wintab)); + m_tabletData = GHOST_TABLET_DATA_NONE; + if (parentwindow) { GetWindowRect(m_parentWindowHwnd, &parent_rect); } @@ -230,24 +233,68 @@ 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(); - setWintabEnabled(true); - } + // 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); + } + m_wintab.info(WTI_INTERFACE, IFC_NDEVICES, &m_wintab.numDevices); + } + } CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } @@ -261,12 +308,12 @@ GHOST_WindowWin32::~GHOST_WindowWin32() } if (m_wintab.handle) { - setWintabEnabled(false); - 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); + memset(&m_wintab, 0, sizeof(m_wintab)); } if (m_user32) { @@ -908,62 +955,6 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure; } -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; - } - - /* 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)) { - - lc.lcPktData = PACKETDATA; - lc.lcPktMode = PACKETMODE; - lc.lcMoveMask = PACKETDATA; - lc.lcOptions |= CXO_CSRMESSAGES | CXO_MESSAGES; - /* 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); - - updateWintabCursorInfo(); - - /* 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. The Wintab spec dates back to 16 bit Windows, thus - * assumes memory recently deallocated may not be available, which is no longer a practical - * concern. */ - 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) { @@ -1043,85 +1034,24 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( } } - if (!outPointerInfo.empty()) { - lastTabletData = outPointerInfo.back().tabletData; - } - return GHOST_kSuccess; } -void GHOST_WindowWin32::setWintabEnabled(bool enable) +void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) { - if (m_wintab.enable && m_wintab.get && m_wintab.context) { - LOGCONTEXT context = {0}; - - if (m_wintab.get(m_wintab.context, &context)) { - if (enable && context.lcStatus & CXS_DISABLED && useTabletAPI(GHOST_kTabletWintab)) { - m_wintab.enable(m_wintab.context, true); - - POINT cursorPos; - ::GetCursorPos(&cursorPos); - GHOST_Rect bounds; - getClientBounds(bounds); - if (bounds.isInside(cursorPos.x, cursorPos.y)) { - setWintabOverlap(true); - } - } - else if (!enable && !(context.lcStatus & CXS_DISABLED)) { - setWintabOverlap(false); - m_wintab.enable(m_wintab.context, false); - } - } + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; } -} -void GHOST_WindowWin32::setWintabOverlap(bool overlap) -{ - if (m_wintab.overlap && m_wintab.get && m_wintab.packetsGet && m_wintab.context) { - LOGCONTEXT context = {0}; + if (m_wintab.enable && m_wintab.tablet) { + m_wintab.enable(m_wintab.tablet, state); - if (m_wintab.get(m_wintab.context, &context)) { - if (overlap && context.lcStatus & CXS_OBSCURED && useTabletAPI(GHOST_kTabletWintab)) { - m_wintab.overlap(m_wintab.context, true); - } - else if (!overlap && context.lcStatus & CXS_ONTOP) { - m_wintab.overlap(m_wintab.context, false); - - /* If context is disabled, Windows Ink may be active and managing m_tabletInRange. Don't - * modify it. */ - if (!(context.lcStatus & CXS_DISABLED)) { - processWintabLeave(); - } - } + if (m_wintab.overlap && state) { + m_wintab.overlap(m_wintab.tablet, TRUE); } } } -void GHOST_WindowWin32::processWintabLeave() -{ - m_tabletInRange = false; - m_wintab.buttons = 0; - /* Clear the packet queue. */ - m_wintab.packetsGet(m_wintab.context, m_wintab.pkts.size(), m_wintab.pkts.data()); -} - -void GHOST_WindowWin32::processWintabDisplayChangeEvent() -{ - 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)) { - - m_wintab.get(m_wintab.context, &lc_curr); - - 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); - } -} - bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const { if (m_system->getTabletAPI() == api) { @@ -1138,24 +1068,36 @@ bool GHOST_WindowWin32::useTabletAPI(GHOST_TTabletAPI api) const } } -void GHOST_WindowWin32::updateWintabCursorInfo() +void GHOST_WindowWin32::processWin32TabletInitEvent() { - if (m_wintab.info && m_wintab.context) { - AXIS Pressure, Orientation[3]; + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + + // Let's see if we can initialize tablet here + 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 { - 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_tabletData.Active = GHOST_kTabletModeNone; } void GHOST_WindowWin32::processWintabInfoChangeEvent(LPARAM lParam) @@ -1163,151 +1105,86 @@ void GHOST_WindowWin32::processWintabInfoChangeEvent(LPARAM lParam) /* 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); - if (useTabletAPI(GHOST_kTabletWintab)) { - setWintabEnabled(true); - } - } -} - -GHOST_TButtonMask GHOST_WindowWin32::wintabMouseToGhost(UINT cursor, WORD physicalButton) -{ - const WORD 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_kButtonMaskNone; - } - BYTE lb = logicalButtons[physicalButton]; - - if (lb >= numButtons) { - return GHOST_kButtonMaskNone; - } - switch (systemButtons[lb]) { - case SBN_LCLICK: - return GHOST_kButtonMaskLeft; - case SBN_RCLICK: - return GHOST_kButtonMaskRight; - case SBN_MCLICK: - return GHOST_kButtonMaskMiddle; - default: - return GHOST_kButtonMaskNone; } } -GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector<GHOST_WintabInfoWin32> &outWintabInfo) +void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam) { - if (!(useTabletAPI(GHOST_kTabletWintab) && m_wintab.packetsGet && m_wintab.context)) { - return GHOST_kFailure; + if (!useTabletAPI(GHOST_kTabletWintab)) { + 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_WintabInfoWin32 &out = outWintabInfo[i]; - - out.tabletData = GHOST_TABLET_DATA_NONE; - /* % 3 for multiple devices ("DualTrack"). */ - switch (pkt.pkCursor % 3) { - case 0: - /* Puck - processed as mouse. */ - out.tabletData.Active = GHOST_kTabletModeNone; - break; - case 1: - out.tabletData.Active = GHOST_kTabletModeStylus; - break; - case 2: - out.tabletData.Active = GHOST_kTabletModeEraser; - break; - } - - out.x = pkt.pkX; - out.y = pkt.pkY; - - if (m_wintab.maxPressure > 0) { - out.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. */ - out.tabletData.Xtilt = sin(azmRad) * vecLen; - out.tabletData.Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen); - } + 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; + } - /* Some Wintab libraries don't handle relative button input, so we track button presses - * manually. */ - out.button = GHOST_kButtonMaskNone; - out.type = GHOST_kEventCursorMove; - - DWORD buttonsChanged = m_wintab.buttons ^ pkt.pkButtons; - if (buttonsChanged) { - /* Find the index for the changed button from the button map. */ - WORD physicalButton = 0; - for (DWORD diff = (unsigned)buttonsChanged >> 1; diff > 0; diff = (unsigned)diff >> 1) { - physicalButton++; + if (m_wintab.maxPressure > 0) { + m_tabletData.Pressure = (float)pkt.pkNormalPressure / (float)m_wintab.maxPressure; + } + else { + m_tabletData.Pressure = 1.0f; } - out.button = wintabMouseToGhost(pkt.pkCursor, physicalButton); + if ((m_wintab.maxAzimuth > 0) && (m_wintab.maxAltitude > 0)) { + ORIENTATION ort = pkt.pkOrientation; + float vecLen; + float altRad, azmRad; /* in radians */ - if (out.button != GHOST_kButtonMaskNone) { - if (buttonsChanged & pkt.pkButtons) { - out.type = GHOST_kEventButtonDown; - } - else { - out.type = GHOST_kEventButtonUp; - } + /* + * 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; } - - /* Only update handled button, in case multiple button events arrived simultaneously. */ - m_wintab.buttons ^= 1 << physicalButton; } - - out.time = system->tickCountToMillis(pkt.pkTime); - } - - if (!outWintabInfo.empty()) { - lastTabletData = outWintabInfo.back().tabletData; } - - return GHOST_kSuccess; } -GHOST_TabletData GHOST_WindowWin32::getLastTabletData() +void GHOST_WindowWin32::bringTabletContextToFront() { - return lastTabletData; + if (!useTabletAPI(GHOST_kTabletWintab)) { + return; + } + + 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 12eed243438..71c97091189 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -34,14 +34,12 @@ # include "GHOST_ImeWin32.h" #endif -#include <queue> #include <vector> #include <wintab.h> // PACKETDATA and PACKETMODE modify structs in pktdef.h, so make sure they come first -#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; @@ -49,13 +47,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 int(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); @@ -236,14 +230,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; }; @@ -437,6 +424,11 @@ 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; + } + /** * Query whether given tablet API should be used. * \param api: Tablet API to test. @@ -455,50 +447,15 @@ class GHOST_WindowWin32 : public GHOST_Window { LPARAM lParam); /** - * Enables or disables Wintab context. - * \param enable: Whether the context should be enabled. - */ - void setWintabEnabled(bool enable); - - /** - * Changes Wintab context overlap. - * \param overlap: Whether context should be brought to top of overlap order. - */ - void setWintabOverlap(bool overlap); - - /** - * Resets Wintab state. - */ - void processWintabLeave(); - - /** - * Handle Wintab coordinate changes when DisplayChange events occur. - */ - void processWintabDisplayChangeEvent(); - - /** - * Updates cached Wintab properties for current cursor. - */ - void updateWintabCursorInfo(); - - /** * 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); - - /** - * Get the most recent tablet data. - * \return Most recent tablet data. - */ - GHOST_TabletData getLastTabletData(); + void processWin32TabletActivateEvent(WORD state); + void processWin32TabletInitEvent(); + void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); + void bringTabletContextToFront(); GHOST_TSuccess beginFullScreen() const { @@ -512,9 +469,6 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TUns16 getDPIHint() override; - /** Whether the mouse is either over or captured by the window. */ - bool m_mousePresent; - /** Whether a tablet stylus is being tracked. */ bool m_tabletInRange; @@ -600,51 +554,29 @@ 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; /** 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; - - /** Stores the Tablet context if detected Tablet features using WinTab.dll. */ - HCTX context = NULL; - /** Number of connected Wintab digitizers. */ - UINT numDevices = 0; - /** Pressed button map. */ - GHOST_TUns8 buttons = 0; - LONG maxPressure = 0; - LONG maxAzimuth = 0, maxAltitude = 0; - /** Reusable buffer to read in Wintab Packets. */ - std::vector<PACKET> pkts; + 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; + UINT numDevices; } m_wintab; - /** Most recent tablet data. */ - GHOST_TabletData lastTabletData = GHOST_TABLET_DATA_NONE; - - /** - * Wintab setup. - */ - void initializeWintab(); - - /** - * Convert Wintab system mapped (mouse) buttons into Ghost button mask. - * \param cursor: The Wintab cursor associated to the button. - * \param physicalButton: The physical button ID to inspect. - * \return The system mapped button. - */ - GHOST_TButtonMask wintabMouseToGhost(UINT cursor, WORD physicalButton); - GHOST_TWindowState m_normal_state; /** user32 dll handle*/ |