diff options
-rw-r--r-- | intern/ghost/GHOST_Types.h | 2 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 104 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 140 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.h | 57 |
4 files changed, 195 insertions, 108 deletions
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 8126c2299c6..b8de31df6c6 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -118,7 +118,7 @@ typedef struct GHOST_TabletData { } GHOST_TabletData; static const GHOST_TabletData GHOST_TABLET_DATA_NONE = { - GHOST_kTabletModeNone, /* No tablet connected. */ + GHOST_kTabletModeNone, /* No cursor in range */ 1.0f, /* Pressure */ 0.0f, /* Xtilt */ 0.0f}; /* Ytilt */ diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index ad53afd9555..fdd022e44ac 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -115,12 +115,22 @@ # define WM_DPICHANGED 0x02E0 #endif // WM_DPICHANGED +// WM_POINTER API messages minimum Windows 7 +#ifndef WM_POINTERENTER +# define WM_POINTERENTER 0x0249 +#endif // WM_POINTERENTER +#ifndef WM_POINTERDOWN +# define WM_POINTERDOWN 0x0246 +#endif // WM_POINTERDOWN #ifndef WM_POINTERUPDATE # define WM_POINTERUPDATE 0x0245 #endif // WM_POINTERUPDATE - -#define WM_POINTERDOWN 0x0246 -#define WM_POINTERUP 0x0247 +#ifndef WM_POINTERUP +# define WM_POINTERUP 0x0247 +#endif // WM_POINTERUP +#ifndef WM_POINTERLEAVE +# define WM_POINTERLEAVE 0x024A +#endif // WM_POINTERLEAVE /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives @@ -928,9 +938,13 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, window->updateMouseCapture(MouseReleased); } - if (window->useTabletAPI(GHOST_kTabletNative)) { - window->setTabletData(NULL); + if (window->m_tabletInRange) { + if (window->useTabletAPI(GHOST_kTabletNative)) { + // Win32 Pointer processing handles input while in-range and in-contact events. + return NULL; + } } + return new GHOST_EventButton( system->getMilliSeconds(), type, window, mask, window->getTabletData()); } @@ -938,57 +952,81 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, void GHOST_SystemWin32::processPointerEvents( UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) { - GHOST_PointerInfoWin32 pointerInfo; + std::vector<GHOST_PointerInfoWin32> pointerInfo; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); if (!window->useTabletAPI(GHOST_kTabletNative)) { return; } - if (window->getPointerInfo(&pointerInfo, wParam, lParam) != GHOST_kSuccess) { + if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) { return; } - if (!pointerInfo.isPrimary) { + if (!pointerInfo[0].isPrimary) { eventHandled = true; return; // For multi-touch displays we ignore these events } - system->setCursorPosition(pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y); - switch (type) { + case WM_POINTERENTER: + window->m_tabletInRange = true; + system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].pixelLocation.x, + pointerInfo[0].pixelLocation.y, + pointerInfo[0].tabletData)); + break; case WM_POINTERDOWN: - /* Update window tablet data to be included in event. */ - window->setTabletData(&pointerInfo.tabletData); - system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + // Move cursor to point of contact because GHOST_EventButton does not include position. + system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].pixelLocation.x, + pointerInfo[0].pixelLocation.y, + pointerInfo[0].tabletData)); + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, GHOST_kEventButtonDown, window, - pointerInfo.buttonMask, - pointerInfo.tabletData)); + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); window->updateMouseCapture(MousePressed); break; case WM_POINTERUPDATE: - /* Update window tablet data to be included in event. */ - system->pushEvent(GHOST_EventCursor(system->getMilliSeconds(), - GHOST_kEventCursorMove, - window, - pointerInfo.pixelLocation.x, - pointerInfo.pixelLocation.y, - pointerInfo.tabletData)); + // Coalesced pointer events are reverse chronological order, reorder chronologically. + // Only contiguous move events are coalesced. + for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) { + system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time, + GHOST_kEventCursorMove, + window, + pointerInfo[i].pixelLocation.x, + pointerInfo[i].pixelLocation.y, + pointerInfo[i].tabletData)); + } break; case WM_POINTERUP: - system->pushEvent(new GHOST_EventButton(system->getMilliSeconds(), + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, GHOST_kEventButtonUp, window, - pointerInfo.buttonMask, - window->getTabletData())); + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); window->updateMouseCapture(MouseReleased); break; + case WM_POINTERLEAVE: + window->m_tabletInRange = false; + system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, + GHOST_kEventCursorMove, + window, + pointerInfo[0].buttonMask, + pointerInfo[0].tabletData)); + break; default: break; } eventHandled = true; + system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y); } GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) @@ -996,12 +1034,18 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TInt32 x_screen, y_screen; GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); - system->getCursorPosition(x_screen, y_screen); + 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; + } + } - /* TODO: CHECK IF THIS IS A TABLET EVENT */ - bool is_tablet = false; + system->getCursorPosition(x_screen, y_screen); - if (is_tablet == false && window->getCursorGrabModeIsWarp()) { + if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { GHOST_TInt32 x_new = x_screen; GHOST_TInt32 y_new = y_screen; GHOST_TInt32 x_accum, y_accum; @@ -1424,9 +1468,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, //////////////////////////////////////////////////////////////////////// // Pointer events, processed //////////////////////////////////////////////////////////////////////// + case WM_POINTERENTER: case WM_POINTERDOWN: case WM_POINTERUPDATE: case WM_POINTERUP: + case WM_POINTERLEAVE: processPointerEvents(msg, window, wParam, lParam, eventHandled); break; //////////////////////////////////////////////////////////////////////// diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 9d957da61cd..b0ba7b6befb 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -82,11 +82,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_wantAlphaBackground(alphaBackground), m_normal_state(GHOST_kWindowStateNormal), m_user32(NULL), - m_fpGetPointerInfo(NULL), - m_fpGetPointerPenInfo(NULL), - m_fpGetPointerTouchInfo(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)); @@ -288,11 +289,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, // Initialize Windows Ink if (m_user32) { - m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo)::GetProcAddress(m_user32, "GetPointerInfo"); - m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo)::GetProcAddress(m_user32, - "GetPointerPenInfo"); - m_fpGetPointerTouchInfo = (GHOST_WIN32_GetPointerTouchInfo)::GetProcAddress( - m_user32, "GetPointerTouchInfo"); + m_fpGetPointerInfoHistory = (GHOST_WIN32_GetPointerInfoHistory)::GetProcAddress( + m_user32, "GetPointerInfoHistory"); + m_fpGetPointerPenInfoHistory = (GHOST_WIN32_GetPointerPenInfoHistory)::GetProcAddress( + m_user32, "GetPointerPenInfoHistory"); + m_fpGetPointerTouchInfoHistory = (GHOST_WIN32_GetPointerTouchInfoHistory)::GetProcAddress( + m_user32, "GetPointerTouchInfoHistory"); } // Initialize Wintab @@ -379,9 +381,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32() if (m_user32) { FreeLibrary(m_user32); m_user32 = NULL; - m_fpGetPointerInfo = NULL; - m_fpGetPointerPenInfo = NULL; - m_fpGetPointerTouchInfo = NULL; + m_fpGetPointerInfoHistory = NULL; + m_fpGetPointerPenInfoHistory = NULL; + m_fpGetPointerTouchInfoHistory = NULL; } if (m_customCursor) { @@ -1021,78 +1023,82 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure; } -GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, - WPARAM wParam, - LPARAM lParam) +GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( + std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM lParam) { - ZeroMemory(pointerInfo, sizeof(GHOST_PointerInfoWin32)); - - // Obtain the basic information from the event - pointerInfo->pointerId = GET_POINTERID_WPARAM(wParam); - pointerInfo->isInContact = IS_POINTER_INCONTACT_WPARAM(wParam); - pointerInfo->isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); - - // Obtain more accurate and predicted information from the Pointer API - POINTER_INFO pointerApiInfo; - if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) { + if (!useTabletAPI(GHOST_kTabletNative)) { return GHOST_kFailure; } - pointerInfo->hasButtonMask = GHOST_kSuccess; - switch (pointerApiInfo.ButtonChangeType) { - case POINTER_CHANGE_FIRSTBUTTON_DOWN: - case POINTER_CHANGE_FIRSTBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskLeft; - break; - case POINTER_CHANGE_SECONDBUTTON_DOWN: - case POINTER_CHANGE_SECONDBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskRight; - break; - case POINTER_CHANGE_THIRDBUTTON_DOWN: - case POINTER_CHANGE_THIRDBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskMiddle; - break; - case POINTER_CHANGE_FOURTHBUTTON_DOWN: - case POINTER_CHANGE_FOURTHBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskButton4; - break; - case POINTER_CHANGE_FIFTHBUTTON_DOWN: - case POINTER_CHANGE_FIFTHBUTTON_UP: - pointerInfo->buttonMask = GHOST_kButtonMaskButton5; - break; - default: - pointerInfo->hasButtonMask = GHOST_kFailure; - break; + GHOST_TInt32 pointerId = GET_POINTERID_WPARAM(wParam); + GHOST_TInt32 isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); + GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem(); + GHOST_TUns32 outCount; + + if (!(m_fpGetPointerInfoHistory && m_fpGetPointerInfoHistory(pointerId, &outCount, NULL))) { + return GHOST_kFailure; } - pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation; - pointerInfo->tabletData.Active = GHOST_kTabletModeNone; - pointerInfo->tabletData.Pressure = 1.0f; - pointerInfo->tabletData.Xtilt = 0.0f; - pointerInfo->tabletData.Ytilt = 0.0f; + auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount); + outPointerInfo.resize(outCount); - if (pointerApiInfo.pointerType != PT_PEN) { + if (!(m_fpGetPointerPenInfoHistory && + m_fpGetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) { return GHOST_kFailure; } - POINTER_PEN_INFO pointerPenInfo; - if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) { - pointerInfo->tabletData.Active = GHOST_kTabletModeStylus; + for (GHOST_TUns32 i = 0; i < outCount; i++) { + POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo; + // Obtain the basic information from the event + outPointerInfo[i].pointerId = pointerId; + outPointerInfo[i].isPrimary = isPrimary; + + switch (pointerApiInfo.ButtonChangeType) { + case POINTER_CHANGE_FIRSTBUTTON_DOWN: + case POINTER_CHANGE_FIRSTBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft; + break; + case POINTER_CHANGE_SECONDBUTTON_DOWN: + case POINTER_CHANGE_SECONDBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight; + break; + case POINTER_CHANGE_THIRDBUTTON_DOWN: + case POINTER_CHANGE_THIRDBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle; + break; + case POINTER_CHANGE_FOURTHBUTTON_DOWN: + case POINTER_CHANGE_FOURTHBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4; + break; + case POINTER_CHANGE_FIFTHBUTTON_DOWN: + case POINTER_CHANGE_FIFTHBUTTON_UP: + outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5; + break; + default: + break; + } + + outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation; + outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus; + outPointerInfo[i].tabletData.Pressure = 1.0f; + outPointerInfo[i].tabletData.Xtilt = 0.0f; + outPointerInfo[i].tabletData.Ytilt = 0.0f; + outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount); - if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) { - pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f; + if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) { + outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f; } - if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) { - pointerInfo->tabletData.Active = GHOST_kTabletModeEraser; + if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) { + outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser; } - if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) { - pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f); + if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) { + outPointerInfo[i].tabletData.Xtilt = fmin(fabs(pointerPenInfo[i].tiltX / 90.0f), 1.0f); } - if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) { - pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f); + if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) { + outPointerInfo[i].tabletData.Ytilt = fmin(fabs(pointerPenInfo[i].tiltY / 90.0f), 1.0f); } } diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index fad8813c5d0..2951901ceb4 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -88,6 +88,26 @@ typedef enum tagPOINTER_BUTTON_CHANGE_TYPE { typedef DWORD POINTER_INPUT_TYPE; typedef UINT32 POINTER_FLAGS; +#define POINTER_FLAG_NONE 0x00000000 +#define POINTER_FLAG_NEW 0x00000001 +#define POINTER_FLAG_INRANGE 0x00000002 +#define POINTER_FLAG_INCONTACT 0x00000004 +#define POINTER_FLAG_FIRSTBUTTON 0x00000010 +#define POINTER_FLAG_SECONDBUTTON 0x00000020 +#define POINTER_FLAG_THIRDBUTTON 0x00000040 +#define POINTER_FLAG_FOURTHBUTTON 0x00000080 +#define POINTER_FLAG_FIFTHBUTTON 0x00000100 +#define POINTER_FLAG_PRIMARY 0x00002000 +#define POINTER_FLAG_CONFIDENCE 0x000004000 +#define POINTER_FLAG_CANCELED 0x000008000 +#define POINTER_FLAG_DOWN 0x00010000 +#define POINTER_FLAG_UPDATE 0x00020000 +#define POINTER_FLAG_UP 0x00040000 +#define POINTER_FLAG_WHEEL 0x00080000 +#define POINTER_FLAG_HWHEEL 0x00100000 +#define POINTER_FLAG_CAPTURECHANGED 0x00200000 +#define POINTER_FLAG_HASTRANSFORM 0x00400000 + typedef struct tagPOINTER_INFO { POINTER_INPUT_TYPE pointerType; UINT32 pointerId; @@ -192,17 +212,23 @@ typedef struct tagPOINTER_TOUCH_INFO { #define IS_POINTER_CANCELED_WPARAM(wParam) \ IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CANCELED) -typedef BOOL(API *GHOST_WIN32_GetPointerInfo)(UINT32 pointerId, POINTER_INFO *pointerInfo); -typedef BOOL(API *GHOST_WIN32_GetPointerPenInfo)(UINT32 pointerId, POINTER_PEN_INFO *penInfo); -typedef BOOL(API *GHOST_WIN32_GetPointerTouchInfo)(UINT32 pointerId, POINTER_TOUCH_INFO *penInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_INFO *pointerInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerPenInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_PEN_INFO *penInfo); +typedef BOOL(WINAPI *GHOST_WIN32_GetPointerTouchInfoHistory)(UINT32 pointerId, + UINT32 *entriesCount, + POINTER_TOUCH_INFO *touchInfo); struct GHOST_PointerInfoWin32 { GHOST_TInt32 pointerId; - GHOST_TInt32 isInContact; GHOST_TInt32 isPrimary; - GHOST_TSuccess hasButtonMask; GHOST_TButtonMask buttonMask; POINT pixelLocation; + GHOST_TUns64 time; + GHOST_TabletData tabletData; }; @@ -403,9 +429,17 @@ class GHOST_WindowWin32 : public GHOST_Window { void setTabletData(GHOST_TabletData *tabletData); bool useTabletAPI(GHOST_TTabletAPI api) const; - void getPointerInfo(WPARAM wParam); - void processWin32PointerEvent(WPARAM wParam); + /** + * Translate WM_POINTER events into GHOST_PointerInfoWin32 structs. + * \param outPointerInfo Storage to return resulting GHOST_PointerInfoWin32 structs + * \param wParam WPARAM of the event + * \param lParam LPARAM of the event + */ + GHOST_TSuccess getPointerInfo(std::vector<GHOST_PointerInfoWin32> &outPointerInfo, + WPARAM wParam, + LPARAM lParam); + void processWin32TabletActivateEvent(WORD state); void processWin32TabletInitEvent(); void processWin32TabletEvent(WPARAM wParam, LPARAM lParam); @@ -429,7 +463,8 @@ class GHOST_WindowWin32 : public GHOST_Window { */ bool getMousePressed() const; - GHOST_TSuccess getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam); + /** Whether a tablet stylus is being tracked */ + bool m_tabletInRange; /** if the window currently resizing */ bool m_inLiveResize; @@ -537,9 +572,9 @@ class GHOST_WindowWin32 : public GHOST_Window { /** user32 dll handle*/ HMODULE m_user32; - GHOST_WIN32_GetPointerInfo m_fpGetPointerInfo; - GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo; - GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo; + GHOST_WIN32_GetPointerInfoHistory m_fpGetPointerInfoHistory; + GHOST_WIN32_GetPointerPenInfoHistory m_fpGetPointerPenInfoHistory; + GHOST_WIN32_GetPointerTouchInfoHistory m_fpGetPointerTouchInfoHistory; HWND m_parentWindowHwnd; |