[Bf-blender-cvs] [ea3e0b3e8cb] master: Windows: support high resolution tablet pen events for Wintab
Nicholas Rishel
noreply at git.blender.org
Wed Apr 8 12:28:22 CEST 2020
Commit: ea3e0b3e8cbcf2768f2e8316addf554e06b888ee
Author: Nicholas Rishel
Date: Fri Mar 27 17:03:28 2020 +0100
Branches: master
https://developer.blender.org/rBea3e0b3e8cbcf2768f2e8316addf554e06b888ee
Windows: support high resolution tablet pen events for Wintab
Together with Windows Ink support, this should fully resolve T70765.
Differential Revision: https://developer.blender.org/D6675
===================================================================
M intern/ghost/intern/GHOST_System.h
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_System.h b/intern/ghost/intern/GHOST_System.h
index eaaa2ff6ee6..c404fe21e41 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -238,7 +238,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.
*/
- void setTabletAPI(GHOST_TTabletAPI api);
+ virtual 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 fdd022e44ac..b91792938d5 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -938,15 +938,100 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
window->updateMouseCapture(MouseReleased);
}
- if (window->m_tabletInRange) {
- if (window->useTabletAPI(GHOST_kTabletNative)) {
+ /* Check for active Wintab mouse emulation in addition to a tablet in range because a proximity
+ * leave event might have fired before the Windows mouse up event, thus there are still tablet
+ * events to grab. The described behavior was observed in a Wacom Bamboo CTE-450.
+ */
+ if (window->m_tabletInRange || window->wintabSysButPressed()) {
+ if (window->useTabletAPI(GHOST_kTabletWintab) && processWintabEvents(type, window)) {
+ // Wintab processing only handles in-contact events.
+ return NULL;
+ }
+ else if (window->useTabletAPI(GHOST_kTabletNative)) {
// Win32 Pointer processing handles input while in-range and in-contact events.
return NULL;
}
+
+ // If using Wintab and this was a button down event but no button event was queued while
+ // processing Wintab packets, fall through to create a button event.
}
return new GHOST_EventButton(
- system->getMilliSeconds(), type, window, mask, window->getTabletData());
+ system->getMilliSeconds(), type, window, mask, GHOST_TABLET_DATA_NONE);
+}
+
+GHOST_TSuccess GHOST_SystemWin32::processWintabEvents(GHOST_TEventType type,
+ GHOST_WindowWin32 *window)
+{
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
+
+ /* Only process Wintab packets if we can correlate them to a Window's mouse button event. When a
+ * button event associated to a mouse button by Wintab occurs outside of WM_*BUTTON events,
+ * there's no way to tell if other simultaneously pressed non-mouse mapped buttons are associated
+ * to a modifier key (shift, alt, ctrl) or a system event (scroll, etc.) and thus it is not
+ * possible to determine if a mouse click event should occur.
+ */
+ if (!window->getMousePressed() && !window->wintabSysButPressed()) {
+ return GHOST_kFailure;
+ }
+
+ std::vector<GHOST_WintabInfoWin32> wintabInfo;
+ if (!window->getWintabInfo(wintabInfo)) {
+ return GHOST_kFailure;
+ }
+
+ auto wtiIter = wintabInfo.begin();
+
+ /* We only process events that correlate to a mouse button events, so there may exist Wintab
+ * button down events that were instead mapped to e.g. scroll still in the queue. We need to
+ * skip those and find the last button down mapped to mouse buttons.
+ */
+ if (!window->wintabSysButPressed()) {
+ for (auto it = wtiIter; it != wintabInfo.end(); it++) {
+ if (it->type == GHOST_kEventButtonDown) {
+ wtiIter = it;
+ }
+ }
+ }
+
+ for (; wtiIter != wintabInfo.end(); wtiIter++) {
+ auto info = *wtiIter;
+
+ switch (info.type) {
+ case GHOST_kEventButtonDown: {
+ /* While changing windows with a tablet, Window's mouse button events normally occur before
+ * tablet proximity events, so a button up event can't be differentiated as occurring from
+ * a Wintab tablet or a normal mouse and a Ghost button event will always be generated.
+ *
+ * If we were called during a button down event create a ghost button down event, otherwise
+ * don't duplicate the prior button down as it interrupts drawing immediately after
+ * changing a window.
+ */
+ if (type == GHOST_kEventButtonDown) {
+ // Move cursor to point of contact because GHOST_EventButton does not include position.
+ system->pushEvent(new GHOST_EventCursor(
+ info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+ system->pushEvent(
+ new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
+ }
+ window->updateWintabSysBut(MousePressed);
+ break;
+ }
+ case GHOST_kEventCursorMove:
+ system->pushEvent(new GHOST_EventCursor(
+ info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+ break;
+ case GHOST_kEventButtonUp:
+ system->pushEvent(
+ new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
+ window->updateWintabSysBut(MouseReleased);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return GHOST_kSuccess;
}
void GHOST_SystemWin32::processPointerEvents(
@@ -1034,13 +1119,19 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
GHOST_TInt32 x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
- if (window->m_tabletInRange) {
- if (window->useTabletAPI(GHOST_kTabletNative)) {
+ if (window->m_tabletInRange || window->wintabSysButPressed()) {
+ if (window->useTabletAPI(GHOST_kTabletWintab) &&
+ processWintabEvents(GHOST_kEventCursorMove, window)) {
+ return NULL;
+ }
+ else 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;
}
+
+ // If using Wintab but no button event is currently active, fall through to default handling
}
system->getCursorPosition(x_screen, y_screen);
@@ -1073,7 +1164,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window,
x_screen + x_accum,
y_screen + y_accum,
- window->getTabletData());
+ GHOST_TABLET_DATA_NONE);
}
}
else {
@@ -1082,7 +1173,7 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
window,
x_screen,
y_screen,
- window->getTabletData());
+ GHOST_TABLET_DATA_NONE);
}
return NULL;
}
@@ -1193,7 +1284,6 @@ 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);
@@ -1221,6 +1311,19 @@ 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();
+ GHOST_WindowWin32 *activeWindow = (GHOST_WindowWin32 *)wm->getActiveWindow();
+
+ for (GHOST_IWindow *win : wm->getWindows()) {
+ GHOST_WindowWin32 *windowsWindow = (GHOST_WindowWin32 *)win;
+ windowsWindow->updateWintab(windowsWindow == activeWindow);
+ }
+}
+
void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax)
{
minmax->ptMinTrackSize.x = 320;
@@ -1456,15 +1559,17 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
////////////////////////////////////////////////////////////////////////
- // Tablet events, processed
+ // Wintab events, processed
////////////////////////////////////////////////////////////////////////
- case WT_PACKET:
- window->processWin32TabletEvent(wParam, lParam);
+ case WT_INFOCHANGE: {
+ window->processWintabInfoChangeEvent(lParam);
break;
- case WT_CSRCHANGE:
- case WT_PROXIMITY:
- window->processWin32TabletInitEvent();
+ }
+ case WT_PROXIMITY: {
+ bool inRange = LOWORD(lParam);
+ window->processWintabProximityEvent(inRange);
break;
+ }
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
////////////////////////////////////////////////////////////////////////
@@ -1603,7 +1708,9 @@ 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));
+
+ window->updateWintab(LOWORD(wParam) != WA_INACTIVE);
+
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
@@ -1661,6 +1768,11 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
else {
event = processWindowEvent(GHOST_kEventWindowSize, window);
}
+
+ if (msg == WM_SIZE && wParam == SIZE_MINIMIZED) {
+ window->updateWintab(false);
+ }
+
break;
case WM_CAPTURECHANGED:
window->lostMouseCapture();
@@ -1711,6 +1823,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwn
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list