[Bf-blender-cvs] [2933fd6c7c1] master: Fix T55589, T60967: Windows pen pressure issues at start/end of the stroke.

Christopher Peerman noreply at git.blender.org
Wed Apr 3 20:03:44 CEST 2019


Commit: 2933fd6c7c16d95c8d8e7a5b171edd35632cdb50
Author: Christopher Peerman
Date:   Wed Apr 3 16:36:28 2019 +0200
Branches: master
https://developer.blender.org/rB2933fd6c7c16d95c8d8e7a5b171edd35632cdb50

Fix T55589, T60967: Windows pen pressure issues at start/end of the stroke.

The new implementation uses WM_POINTERDOWN, WM_POINTERUP and WM_POINTERUPDATE
and the pointer API to process stylus events. This avoids the delays that comes
with the WM_MOUSE and WM_xBUTTON events. The implementation should work on
Windows 8, and Windows 10 with both legacy and new pen interaction.

It also changes how the pressure is reset when the Windows Ink implementation
is enabled. The previous version reset the pressure to full when the pen left
the screen, however for some hardware implementations this allowed a small
window where Blender may process the final move event and read the pressure
as full leaving a dot on the last event.

Differential Revision: https://developer.blender.org/D4314

===================================================================

M	intern/ghost/intern/GHOST_SystemWin32.cpp
M	intern/ghost/intern/GHOST_SystemWin32.h
M	intern/ghost/intern/GHOST_WindowWin32.cpp
M	intern/ghost/intern/GHOST_WindowWin32.h

===================================================================

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
@@ -260,6 +260,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.
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);
+			p

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list