diff options
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.cpp | 68 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemWin32.h | 11 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 110 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.h | 67 |
4 files changed, 218 insertions, 38 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index bf12f049283..ebec5a773a0 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -116,6 +116,9 @@ #define WM_POINTERUPDATE 0x0245 #endif // WM_POINTERUPDATE +#define WM_POINTERDOWN 0x0246 +#define WM_POINTERUP 0x0247 + /* Workaround for some laptop touchpads, some of which seems to * have driver issues which makes it so window function receives * the message, but PeekMessage doesn't pick those messages for @@ -791,9 +794,55 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent( GHOST_WindowWin32 *window, GHOST_TButtonMask mask) { - return new GHOST_EventButton(getSystem()->getMilliSeconds(), type, window, mask); + GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem(); + if (window->useTabletAPI(GHOST_kTabletNative)) { + window->setTabletData(NULL); + } + return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask); } +GHOST_Event *GHOST_SystemWin32::processPointerEvent( + GHOST_TEventType type, + GHOST_WindowWin32 *window, + WPARAM wParam, + LPARAM lParam, + bool& eventHandled) +{ + GHOST_PointerInfoWin32 pointerInfo; + GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem(); + + if (!window->useTabletAPI(GHOST_kTabletNative)) { + return NULL; + } + + if (window->getPointerInfo(&pointerInfo, wParam, lParam) != GHOST_kSuccess) { + return NULL; + } + + if (!pointerInfo.isPrimary) { + eventHandled = true; + return NULL; // For multi-touch displays we ignore these events + } + + system->setCursorPosition(pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y); + + switch (type) { + case GHOST_kEventButtonDown: + window->setTabletData(&pointerInfo.tabletData); + eventHandled = true; + return new GHOST_EventButton(system->getMilliSeconds(), GHOST_kEventButtonDown, window, pointerInfo.buttonMask); + case GHOST_kEventButtonUp: + eventHandled = true; + return new GHOST_EventButton(system->getMilliSeconds(), GHOST_kEventButtonUp, window, pointerInfo.buttonMask); + case GHOST_kEventCursorMove: + window->setTabletData(&pointerInfo.tabletData); + eventHandled = true; + return new GHOST_EventCursor(system->getMilliSeconds(), GHOST_kEventCursorMove, window, + pointerInfo.pixelLocation.x, pointerInfo.pixelLocation.y); + default: + return NULL; + } +} GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_TEventType type, GHOST_WindowWin32 *window) { @@ -1220,8 +1269,23 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, case WT_PROXIMITY: window->processWin32TabletInitEvent(); break; + //////////////////////////////////////////////////////////////////////// + // Pointer events, processed + //////////////////////////////////////////////////////////////////////// + case WM_POINTERDOWN: + event = processPointerEvent(GHOST_kEventButtonDown, window, wParam, lParam, eventHandled); + if (event && eventHandled) { + window->registerMouseClickEvent(0); + } + break; + case WM_POINTERUP: + event = processPointerEvent(GHOST_kEventButtonUp, window, wParam, lParam, eventHandled); + if (event && eventHandled) { + window->registerMouseClickEvent(1); + } + break; case WM_POINTERUPDATE: - window->processWin32PointerEvent(wParam); + event = processPointerEvent(GHOST_kEventCursorMove, window, wParam, lParam, eventHandled); break; //////////////////////////////////////////////////////////////////////// // Mouse events, processed diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h index edf7c3fb695..62492e8d8b7 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.h +++ b/intern/ghost/intern/GHOST_SystemWin32.h @@ -261,6 +261,17 @@ protected: static GHOST_EventButton *processButtonEvent(GHOST_TEventType type, GHOST_WindowWin32 *window, GHOST_TButtonMask mask); /** + * Creates pointer event. + * \param type The type of event to create. + * \param window The window receiving the event (the active window). + * \param wParam The wParam from the wndproc + * \param lParam The lParam from the wndproc + * \param eventhandled true if the method handled the event + * \return The event created. + */ + static GHOST_Event *processPointerEvent(GHOST_TEventType type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool & eventhandled); + + /** * Creates cursor 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 b119a32e002..ed5e0798643 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -39,6 +39,7 @@ #include <Dwmapi.h> #endif +#include <windowsx.h> #include <math.h> #include <string.h> #include <assert.h> @@ -82,9 +83,10 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_customCursor(0), m_wantAlphaBackground(alphaBackground), m_normal_state(GHOST_kWindowStateNormal), - m_user32(NULL), + m_user32(NULL), m_fpGetPointerInfo(NULL), m_fpGetPointerPenInfo(NULL), + m_fpGetPointerTouchInfo(NULL), m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { @@ -284,6 +286,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, 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"); } // Initialize Wintab @@ -372,6 +375,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32() m_user32 = NULL; m_fpGetPointerInfo = NULL; m_fpGetPointerPenInfo = NULL; + m_fpGetPointerTouchInfo = NULL; } if (m_customCursor) { @@ -396,11 +400,6 @@ GHOST_WindowWin32::~GHOST_WindowWin32() ::DestroyWindow(m_hWnd); m_hWnd = 0; } - - if (m_user32) { - FreeLibrary(m_user32); - m_user32 = NULL; - } } bool GHOST_WindowWin32::getValid() const @@ -878,54 +877,93 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur return GHOST_kSuccess; } -void GHOST_WindowWin32::processWin32PointerEvent(WPARAM wParam) +GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam) { - if (!useTabletAPI(GHOST_kTabletNative)) { - return; // Other tablet API specified by user - } + 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); - if (!m_fpGetPointerInfo || !m_fpGetPointerPenInfo) { - return; // OS version does not support pointer API + // Obtain more accurate and predicted information from the Pointer API + POINTER_INFO pointerApiInfo; + if (!(m_fpGetPointerInfo && m_fpGetPointerInfo(pointerInfo->pointerId, &pointerApiInfo))) { + return GHOST_kFailure; } - UINT32 pointerId = GET_POINTERID_WPARAM(wParam); - POINTER_INFO pointerInfo; - if (!m_fpGetPointerInfo(pointerId, &pointerInfo)) { - return; // Invalid pointer info + 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; + } + + pointerInfo->pixelLocation = pointerApiInfo.ptPixelLocation; + pointerInfo->tabletData.Active = GHOST_kTabletModeNone; + pointerInfo->tabletData.Pressure = 1.0f; + pointerInfo->tabletData.Xtilt = 0.0f; + pointerInfo->tabletData.Ytilt = 0.0f; + + if (pointerApiInfo.pointerType != PT_PEN) { + return GHOST_kFailure; } - m_tabletData.Active = GHOST_kTabletModeNone; - m_tabletData.Pressure = 1.0f; - m_tabletData.Xtilt = 0.0f; - m_tabletData.Ytilt = 0.0f; - - if (pointerInfo.pointerType & PT_POINTER) { - POINTER_PEN_INFO pointerPenInfo; - if (!m_fpGetPointerPenInfo(pointerId, &pointerPenInfo)) { - return; - } + POINTER_PEN_INFO pointerPenInfo; + if (m_fpGetPointerPenInfo && m_fpGetPointerPenInfo(pointerInfo->pointerId, &pointerPenInfo)) { + pointerInfo->tabletData.Active = GHOST_kTabletModeStylus; - // With the Microsoft Surface Pen if you hover the within 1cm of the screen the WM_POINTERUPDATE - // event will fire with PEN_MASK_PRESSURE mask set and zero pressure. In this case we disable - // tablet mode until the pen is physically touching. This enables the user to switch to the - // mouse and draw at full pressure. - if (pointerPenInfo.penMask & PEN_MASK_PRESSURE && pointerPenInfo.pressure > 0) { - m_tabletData.Active = GHOST_kTabletModeStylus; - m_tabletData.Pressure = pointerPenInfo.pressure / 1024.0f; + if (pointerPenInfo.penMask & PEN_MASK_PRESSURE) { + pointerInfo->tabletData.Pressure = pointerPenInfo.pressure / 1024.0f; } if (pointerPenInfo.penFlags & PEN_FLAG_ERASER) { - m_tabletData.Active = GHOST_kTabletModeEraser; + pointerInfo->tabletData.Active = GHOST_kTabletModeEraser; } if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) { - m_tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f); + pointerInfo->tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f); } if (pointerPenInfo.penFlags & PEN_MASK_TILT_Y) { - m_tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f); + pointerInfo->tabletData.Ytilt = fmin(fabs(pointerPenInfo.tiltY / 90), 1.0f); } } + + return GHOST_kSuccess; +} + +void GHOST_WindowWin32::setTabletData(GHOST_TabletData * pTabletData) +{ + if (pTabletData) { + m_tabletData = *pTabletData; + } + else { + m_tabletData.Active = GHOST_kTabletModeNone; + m_tabletData.Pressure = 1.0f; + m_tabletData.Xtilt = 0.0f; + m_tabletData.Ytilt = 0.0f; + } } void GHOST_WindowWin32::processWin32TabletActivateEvent(WORD state) diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h index 41874579f73..5de6a62380a 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.h +++ b/intern/ghost/intern/GHOST_WindowWin32.h @@ -130,8 +130,70 @@ typedef struct tagPOINTER_PEN_INFO { INT32 tiltY; } POINTER_PEN_INFO; +/* + * Flags that appear in pointer input message parameters + */ +#define POINTER_MESSAGE_FLAG_NEW 0x00000001 // New pointer +#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002 // Pointer has not departed +#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004 // Pointer is in contact +#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 // Primary action +#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 // Secondary action +#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 // Third button +#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 // Fourth button +#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 // Fifth button +#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000 // Pointer is primary +#define POINTER_MESSAGE_FLAG_CONFIDENCE 0x00004000 // Pointer is considered unlikely to be accidental +#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000 // Pointer is departing in an abnormal manner + +typedef UINT32 TOUCH_FLAGS; +#define TOUCH_FLAG_NONE 0x00000000 // Default + +typedef UINT32 TOUCH_MASK; +#define TOUCH_MASK_NONE 0x00000000 // Default - none of the optional fields are valid +#define TOUCH_MASK_CONTACTAREA 0x00000001 // The rcContact field is valid +#define TOUCH_MASK_ORIENTATION 0x00000002 // The orientation field is valid +#define TOUCH_MASK_PRESSURE 0x00000004 // The pressure field is valid + +typedef struct tagPOINTER_TOUCH_INFO { + POINTER_INFO pointerInfo; + TOUCH_FLAGS touchFlags; + TOUCH_MASK touchMask; + RECT rcContact; + RECT rcContactRaw; + UINT32 orientation; + UINT32 pressure; +} POINTER_TOUCH_INFO; + + /* + * Macros to retrieve information from pointer input message parameters + */ +#define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam)) +#define IS_POINTER_FLAG_SET_WPARAM(wParam, flag) (((DWORD)HIWORD(wParam) & (flag)) == (flag)) +#define IS_POINTER_NEW_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_NEW) +#define IS_POINTER_INRANGE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INRANGE) +#define IS_POINTER_INCONTACT_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_INCONTACT) +#define IS_POINTER_FIRSTBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIRSTBUTTON) +#define IS_POINTER_SECONDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_SECONDBUTTON) +#define IS_POINTER_THIRDBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_THIRDBUTTON) +#define IS_POINTER_FOURTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FOURTHBUTTON) +#define IS_POINTER_FIFTHBUTTON_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_FIFTHBUTTON) +#define IS_POINTER_PRIMARY_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_PRIMARY) +#define HAS_POINTER_CONFIDENCE_WPARAM(wParam) IS_POINTER_FLAG_SET_WPARAM(wParam, POINTER_MESSAGE_FLAG_CONFIDENCE) +#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); + +struct GHOST_PointerInfoWin32 { + GHOST_TInt32 pointerId; + GHOST_TInt32 isInContact; + GHOST_TInt32 isPrimary; + GHOST_TSuccess hasButtonMask; + GHOST_TButtonMask buttonMask; + POINT pixelLocation; + GHOST_TabletData tabletData; +}; /** * GHOST window on M$ Windows OSs. @@ -316,7 +378,9 @@ public: return &m_tabletData; } + void setTabletData(GHOST_TabletData * tabletData); bool useTabletAPI(GHOST_TTabletAPI api) const; + void getPointerInfo(WPARAM wParam); void processWin32PointerEvent(WPARAM wParam); void processWin32TabletActivateEvent(WORD state); @@ -330,6 +394,8 @@ public: GHOST_TUns16 getDPIHint() override; + GHOST_TSuccess getPointerInfo(GHOST_PointerInfoWin32 *pointerInfo, WPARAM wParam, LPARAM lParam); + /** if the window currently resizing */ bool m_inLiveResize; @@ -445,6 +511,7 @@ private: HMODULE m_user32; GHOST_WIN32_GetPointerInfo m_fpGetPointerInfo; GHOST_WIN32_GetPointerPenInfo m_fpGetPointerPenInfo; + GHOST_WIN32_GetPointerTouchInfo m_fpGetPointerTouchInfo; /** Hwnd to parent window */ GHOST_TEmbedderWindowID m_parentWindowHwnd; |