[Bf-blender-cvs] [46932079184] master: Windows: add support for Windows Ink.

Christopher Peerman noreply at git.blender.org
Mon Jan 14 20:49:04 CET 2019


Commit: 46932079184754ace63b25f854e3f273fbf6f0c5
Author: Christopher Peerman
Date:   Mon Jan 14 17:46:49 2019 +0100
Branches: master
https://developer.blender.org/rB46932079184754ace63b25f854e3f273fbf6f0c5

Windows: add support for Windows Ink.

Before this Blender always needed the Wintab driver. This adds support for the
native pressure API in Windows 8+, making it possible to get pressure sensitivity
on e.g. Microsoft Surface hardware without any extra drivers.

By default Blender will automatically use Wintab if available, and if not use
Windows Ink instead. There is also a new user preference to explicitly specify
which API to use if automatic detection fails.

Fixes T57869: no pressure sensitivity with Surface pen or laptop.

Code by Christopher Peerman with some tweaks by Brecht Van Lommel.

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

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

M	intern/ghost/GHOST_C-api.h
M	intern/ghost/GHOST_ISystem.h
M	intern/ghost/GHOST_Types.h
M	intern/ghost/intern/GHOST_C-api.cpp
M	intern/ghost/intern/GHOST_System.cpp
M	intern/ghost/intern/GHOST_System.h
M	intern/ghost/intern/GHOST_SystemWin32.cpp
M	intern/ghost/intern/GHOST_WindowWin32.cpp
M	intern/ghost/intern/GHOST_WindowWin32.h
M	release/scripts/startup/bl_ui/space_userpref.py
M	source/blender/makesdna/DNA_userdef_types.h
M	source/blender/makesrna/intern/rna_userdef.c
M	source/blender/windowmanager/WM_api.h
M	source/blender/windowmanager/intern/wm_window.c

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

diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 1ce051d2660..45ec41f63a0 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -742,6 +742,13 @@ extern GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthan
  */
 extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle);
 
+/**
+ * Set which tablet API to use. Only affects Windows, other platforms have a single API.
+ * \param systemhandle The handle to the system
+ * \param api Enum indicating which API to use.
+ */
+extern void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api);
+
 /**
  * Returns the status of the tablet
  * \param windowhandle The handle to the window
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 42ae750e20a..39686c56719 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -397,6 +397,12 @@ public:
 	 */
 	virtual GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const = 0;
 
+	/**
+	 * 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) = 0;
+
 #ifdef WITH_INPUT_NDOF
 	/**
 	 * Sets 3D mouse deadzone
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 1fc1d1a3e56..f786c99342b 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -90,6 +90,12 @@ typedef enum {
 	GHOST_kTabletModeEraser
 } GHOST_TTabletMode;
 
+typedef enum {
+	GHOST_kTabletAutomatic = 0,
+	GHOST_kTabletNative,
+	GHOST_kTabletWintab,
+} GHOST_TTabletAPI;
+
 typedef struct GHOST_TabletData {
 	GHOST_TTabletMode Active; /* 0=None, 1=Stylus, 2=Eraser */
 	float Pressure; /* range 0.0 (not touching) to 1.0 (full pressure) */
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index ab0e7b724b8..d3fb7d6f043 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -750,8 +750,13 @@ GHOST_TSuccess GHOST_InvalidateWindow(GHOST_WindowHandle windowhandle)
 	return window->invalidate();
 }
 
+void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
+{
+	GHOST_ISystem *system = (GHOST_ISystem *) systemhandle;
+	system->setTabletAPI(api);
+}
 
-extern const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
+const GHOST_TabletData *GHOST_GetTabletData(GHOST_WindowHandle windowhandle)
 {
 	return ((GHOST_IWindow *)windowhandle)->GetTabletData();
 }
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index fc69900acdf..149649f11d1 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -52,10 +52,11 @@ GHOST_System::GHOST_System()
       m_displayManager(NULL),
       m_timerManager(NULL),
       m_windowManager(NULL),
-      m_eventManager(NULL)
+      m_eventManager(NULL),
 #ifdef WITH_INPUT_NDOF
-      , m_ndofManager(0)
+      m_ndofManager(0),
 #endif
+      m_tabletAPI(GHOST_kTabletAutomatic)
 {
 }
 
@@ -297,6 +298,16 @@ GHOST_TSuccess GHOST_System::getButtonState(GHOST_TButtonMask mask, bool& isDown
 	return success;
 }
 
+void GHOST_System::setTabletAPI(GHOST_TTabletAPI api)
+{
+	m_tabletAPI = api;
+}
+
+bool GHOST_System::useTabletAPI(GHOST_TTabletAPI api) const
+{
+	return (m_tabletAPI == GHOST_kTabletAutomatic || m_tabletAPI == api);
+}
+
 #ifdef WITH_INPUT_NDOF
 void GHOST_System::setNDOFDeadZone(float deadzone)
 {
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index ee3c30c35b4..7660ddc947e 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -247,6 +247,17 @@ public:
 	 */
 	GHOST_TSuccess getButtonState(GHOST_TButtonMask mask, bool& isDown) const;
 
+	/**
+	 * Set which tablet API to use. Only affects Windows, other platforms have a single API.
+	 * \param api Enum indicating which API to use.
+	 */
+	void setTabletAPI(GHOST_TTabletAPI api);
+
+	/**
+	 * Test if given tablet API should be used by event handling.
+	 */
+	bool useTabletAPI(GHOST_TTabletAPI api) const;
+
 #ifdef WITH_INPUT_NDOF
 	/***************************************************************************************
 	 * Access to 3D mouse.
@@ -380,6 +391,8 @@ protected:
 	/** Settings of the display before the display went fullscreen. */
 	GHOST_DisplaySetting m_preFullScreenSetting;
 
+	/** Which tablet API to use. */
+	GHOST_TTabletAPI m_tabletAPI;
 };
 
 inline GHOST_TimerManager *GHOST_System::getTimerManager() const
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 00852c1ad05..70010f8b558 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -122,6 +122,10 @@
 #define WM_DPICHANGED 0x02E0
 #endif // WM_DPICHANGED
 
+#ifndef WM_POINTERUPDATE
+#define WM_POINTERUPDATE 0x0245
+#endif // WM_POINTERUPDATE
+
 /* 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
@@ -1233,6 +1237,9 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
 				case WT_PROXIMITY:
 					window->processWin32TabletInitEvent();
 					break;
+				case WM_POINTERUPDATE:
+					window->processWin32PointerEvent(wParam);
+					break;
 				////////////////////////////////////////////////////////////////////////
 				// Mouse events, processed
 				////////////////////////////////////////////////////////////////////////
@@ -1450,8 +1457,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
 					 * change such as when the window is moved to a monitor with a different DPI.
 					 */
 					{
-						WORD newYAxisDPI = HIWORD(wParam);
-						WORD newXAxisDPI = LOWORD(wParam);
 						// The suggested new size and position of the window.
 						RECT* const suggestedWindowRect = (RECT*)lParam;
 
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 7027c2af368..da23baa3111 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -51,7 +51,9 @@
 #include <string.h>
 #include <assert.h>
 
-
+#ifndef GET_POINTERID_WPARAM
+#define GET_POINTERID_WPARAM(wParam)                (LOWORD(wParam))
+#endif // GET_POINTERID_WPARAM
 
 const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
 const int GHOST_WindowWin32::s_maxTitleLength = 128;
@@ -89,6 +91,8 @@ 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_parentWindowHwnd(parentwindowhwnd),
       m_debug_context(is_debug)
 {
@@ -284,6 +288,12 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
 		RegisterRawInputDevices(&device, 1, sizeof(device));
 	}
 
+	// Initialize Windows Ink
+	if (m_user32) {
+		m_fpGetPointerInfo = (GHOST_WIN32_GetPointerInfo) ::GetProcAddress(m_user32, "GetPointerInfo");
+		m_fpGetPointerPenInfo = (GHOST_WIN32_GetPointerPenInfo) ::GetProcAddress(m_user32, "GetPointerPenInfo");
+	}
+
 	// Initialize Wintab
 	m_wintab.handle = ::LoadLibrary("Wintab32.dll");
 	if (m_wintab.handle) {
@@ -353,6 +363,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
 	if (m_Bar) {
 		m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
 		m_Bar->Release();
+		m_Bar = NULL;
 	}
 
 	if (m_wintab.handle) {
@@ -364,6 +375,13 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
 		memset(&m_wintab, 0, sizeof(m_wintab));
 	}
 
+	if (m_user32) {
+		FreeLibrary(m_user32);
+		m_user32 = NULL;
+		m_fpGetPointerInfo = NULL;
+		m_fpGetPointerPenInfo = NULL;
+	}
+
 	if (m_customCursor) {
 		DestroyCursor(m_customCursor);
 		m_customCursor = NULL;
@@ -371,6 +389,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
 
 	if (m_hWnd != NULL && m_hDC != NULL && releaseNativeHandles()) {
 		::ReleaseDC(m_hWnd, m_hDC);
+		m_hDC = NULL;
 	}
 
 	if (m_hWnd) {
@@ -379,6 +398,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
 			RevokeDragDrop(m_hWnd);
 			// Release our reference of the DropTarget and it will delete itself eventually.
 			m_dropTarget->Release();
+			m_dropTarget = NULL;
 		}
 		::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, NULL);
 		::DestroyWindow(m_hWnd);
@@ -866,8 +886,62 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cur
 	return GHOST_kSuccess;
 }
 
+void GHOST_WindowWin32::processWin32PointerEvent(WPARAM wParam)
+{
+	if (!m_system->useTabletAPI(GHOST_kTabletNative)) {
+		return; // Other tablet API specified by user
+	}
+
+	if (!m_fpGetPointerInfo || !m_fpGetPointerPenInfo) {
+		return; // OS version does not support pointer API
+	}
+
+	UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
+	POINTER_INFO pointerInfo;
+	if (!m_fpGetPointerInfo(pointerId, &pointerInfo)) {
+		return; // Invalid pointer info
+	}
+
+	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;
+		}
+
+		// 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.penFlags & PEN_FLAG_ERASER) {
+			m_tabletData.Active = GHOST_kTabletModeEraser;
+		}
+
+		if (pointerPenInfo.penFlags & PEN_MASK_TILT_X) {
+			m_tabletData.Xtilt = fmin(fabs(pointerPenInfo.tiltX / 90), 1.0f);
+		}
+
+		if (

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list