Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Rishel <rishel.nick@gmail.com>2021-09-05 04:20:40 +0300
committerNicholas Rishel <rishel.nick@gmail.com>2021-09-05 21:51:43 +0300
commita8f7bfa21366de1bc37c9aef29f3555b61249964 (patch)
treefb39cd0018c9ae8fe30d6e81b6d38455231bb77f
parentccd5264344fada7e0499d1e70208b6b9058c68bf (diff)
Continuous grab mostly working for Wintab and Windows Ink. Some minor race conditions for Windows Ink when a pen quickly enters then leaves range shortly after a mouse event.
# Conflicts: # intern/ghost/intern/GHOST_SystemWin32.cpp
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp345
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h12
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp13
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_Wintab.cpp51
-rw-r--r--intern/ghost/intern/GHOST_Wintab.h12
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c4
7 files changed, 375 insertions, 64 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 8511da5b233..e79c5e0ce0a 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -150,6 +150,8 @@ GHOST_SystemWin32::GHOST_SystemWin32()
// blurry scaling and enables WM_DPICHANGED to allow us to draw at proper DPI.
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
+ EnableMouseInPointer(true);
+
// Check if current keyboard layout uses AltGr and save keylayout ID for
// specialized handling if keys like VK_OEM_*. I.e. french keylayout
// generates VK_OEM_8 for their exclamation key (key left of right shift)
@@ -160,6 +162,11 @@ GHOST_SystemWin32::GHOST_SystemWin32()
#ifdef WITH_INPUT_NDOF
m_ndofManager = new GHOST_NDOFManagerWin32(*this);
#endif
+
+ POINT pt;
+ ::GetCursorPos(&pt);
+ m_lastX = pt.x;
+ m_lastY = pt.y;
}
GHOST_SystemWin32::~GHOST_SystemWin32()
@@ -878,7 +885,7 @@ GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type,
return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td);
}
-void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
+void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window, UINT genSerial)
{
GHOST_Wintab *wt = window->getWintab();
if (!wt) {
@@ -888,7 +895,7 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
std::vector<GHOST_WintabInfoWin32> wintabInfo;
- wt->getInput(wintabInfo);
+ wt->getInput(wintabInfo, genSerial);
/* Wintab provided coordinates are untrusted until a Wintab and Win32 button down event match.
* This is checked on every button down event, and revoked if there is a mismatch. This can
@@ -908,8 +915,35 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
}
wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y);
+
+ if (system->m_firstProximity) {
+ system->m_firstProximity = false;
+
+ // XXX bad if not trusted coodinates
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x_accum -= info.x - system->m_lastX;
+ y_accum -= info.y - system->m_lastY;
+ window->setCursorGrabAccum(x_accum, y_accum);
+ }
+ }
+
+ int x = info.x;
+ int y = info.y;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x += x_accum;
+ y += y_accum;
+ }
+
system->pushEvent(new GHOST_EventCursor(
- info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+ info.time, GHOST_kEventCursorMove, window, x, y, info.tabletData));
+
+ system->m_lastX = info.x;
+ system->m_lastY = info.y;
break;
}
@@ -948,8 +982,18 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
/* Move cursor to button location, to prevent incorrect cursor position when
* transitioning from unsynchronized Win32 to Wintab cursor control. */
wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y);
+
+ int x = info.x;
+ int y = info.y;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x += x_accum;
+ y += y_accum;
+ }
system->pushEvent(new GHOST_EventCursor(
- info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData));
+ info.time, GHOST_kEventCursorMove, window, x, y, info.tabletData));
window->updateMouseCapture(MousePressed);
system->pushEvent(
@@ -1006,6 +1050,17 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
int x, y;
system->getCursorPosition(x, y);
+ /* TODO decouple required ordering of accum and last position */
+ system->m_lastX = x;
+ system->m_lastY = y;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x += x_accum;
+ y += y_accum;
+ }
+
/* TODO supply tablet data */
GHOST_TabletData td = wt->getLastTabletData();
td.Pressure = 1.0f;
@@ -1017,9 +1072,13 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
void GHOST_SystemWin32::processPointerEvent(
UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled)
{
+ int32_t pointerId = GET_POINTERID_WPARAM(wParam);
+ POINTER_INPUT_TYPE inputType;
+ GetPointerType(pointerId, &inputType);
+
/* Pointer events might fire when changing windows for a device which is set to use Wintab,
* even when Wintab is left enabled but set to the bottom of Wintab overlap order. */
- if (!window->usingTabletAPI(GHOST_kTabletWinPointer)) {
+ if (!window->usingTabletAPI(GHOST_kTabletWinPointer) && inputType != PT_MOUSE) {
return;
}
@@ -1027,6 +1086,13 @@ void GHOST_SystemWin32::processPointerEvent(
std::vector<GHOST_PointerInfoWin32> pointerInfo;
if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) {
+ if (inputType == PT_MOUSE && type == WM_POINTERUPDATE) {
+ GHOST_EventCursor *event = processCursorEvent(window, pointerId);
+ if (event) {
+ system->pushEvent(event);
+ eventHandled = true;
+ }
+ }
return;
}
@@ -1035,25 +1101,43 @@ void GHOST_SystemWin32::processPointerEvent(
/* Coalesced pointer events are reverse chronological order, reorder chronologically.
* Only contiguous move events are coalesced. */
for (uint32_t 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));
+ int x = pointerInfo[i].pixelLocation.x;
+ int y = pointerInfo[i].pixelLocation.y;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x += x_accum;
+ y += y_accum;
+ }
+
+ system->pushEvent(new GHOST_EventCursor(
+ pointerInfo[i].time, GHOST_kEventCursorMove, window, x, y, pointerInfo[i].tabletData));
+ }
+
+ if (pointerInfo.size() > 0) {
+ GHOST_PointerInfoWin32 front = pointerInfo.front();
+ system->m_lastX = front.pixelLocation.x;
+ system->m_lastY = front.pixelLocation.y;
}
/* Leave event unhandled so that system cursor is moved. */
break;
- case WM_POINTERDOWN:
+ case WM_POINTERDOWN: {
+ int x = pointerInfo[0].pixelLocation.x;
+ int y = pointerInfo[0].pixelLocation.y;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x += x_accum;
+ y += y_accum;
+ }
+
/* 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_EventCursor(
+ pointerInfo[0].time, GHOST_kEventCursorMove, window, x, y, pointerInfo[0].tabletData));
system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
GHOST_kEventButtonDown,
window,
@@ -1065,6 +1149,7 @@ void GHOST_SystemWin32::processPointerEvent(
eventHandled = true;
break;
+ }
case WM_POINTERUP:
system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
GHOST_kEventButtonUp,
@@ -1082,9 +1167,9 @@ void GHOST_SystemWin32::processPointerEvent(
}
}
-GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
+GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window,
+ int32_t pointerId)
{
- int32_t x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
if (window->getTabletData().Active != GHOST_kTabletModeNone) {
@@ -1092,9 +1177,11 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
return NULL;
}
- DWORD pos = ::GetMessagePos();
- x_screen = GET_X_LPARAM(pos);
- y_screen = GET_Y_LPARAM(pos);
+ POINTER_INFO pointerInfo;
+ GetPointerInfo(pointerId, &pointerInfo);
+
+ int32_t x_screen = pointerInfo.ptPixelLocation.x;
+ int32_t y_screen = pointerInfo.ptPixelLocation.y;
int32_t x_accum = 0;
int32_t y_accum = 0;
@@ -1120,21 +1207,24 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
system->setCursorPosition(x_new, y_new); /* wrap */
/* We may be in an event before cursor wrap has taken effect */
- if (window->m_activeWarpX >= 0 && warpX < 0 ||
- window->m_activeWarpX <= 0 && warpX > 0) {
+ if (window->m_activeWarpX >= 0 && warpX < 0 || window->m_activeWarpX <= 0 && warpX > 0) {
x_accum -= warpX;
}
- if (window->m_activeWarpY >= 0 && warpY < 0 ||
- window->m_activeWarpY <= 0 && warpY > 0) {
+ if (window->m_activeWarpY >= 0 && warpY < 0 || window->m_activeWarpY <= 0 && warpY > 0) {
y_accum -= warpY;
}
+ /* XXX move to else, track pending accum instead? may add more code with no gain other than
+ * minimizing risk of object momentarily jumping, if any benefit? */
window->setCursorGrabAccum(x_accum, y_accum);
window->m_activeWarpX = warpX;
window->m_activeWarpY = warpY;
+ system->m_lastX = x_new;
+ system->m_lastY = y_new;
+
/* When wrapping we don't need to add an event because the setCursorPosition call will cause
* a new event after. We also need to skip outdated messages while warp is active to prevent
* applying cursor accumulation to old coordinates. */
@@ -1146,6 +1236,9 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
}
}
+ system->m_lastX = x_screen;
+ system->m_lastY = y_screen;
+
return new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
@@ -1629,9 +1722,39 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
if (inRange) {
/* Some devices don't emit WT_CSRCHANGE events, so update cursor info here. */
wt->updateCursorInfo();
+
+ wt->enterRange();
+
+ window->m_mousePresent = true;
+
+ if (window->getCursorGrabModeIsWarp()) {
+ system->m_firstProximity = true;
+ /* Mouse events are still generated asynchronously and may have been processed
+ * while Wintab was out of range, thus we may be in the middle of a cursor wrap
+ * event. */
+ window->m_activeWarpX = 0;
+ window->m_activeWarpY = 0;
+ }
}
else {
wt->leaveRange();
+
+ /* Check if pointer device left range while outside of the window. This is necessary
+ * because WM_POINTERENTER and WM_POINTERLEAVE events don't fire when a pen enters
+ * and leaves without hoving over the window, but the cursor is moved resulting in a
+ * WM_POINTERLEAVE event for the mouse. */
+ int32_t msgPosX;
+ int32_t msgPosY;
+ system->getCursorPosition(msgPosX, msgPosY);
+
+ GHOST_Rect bounds;
+ window->getClientBounds(bounds);
+
+ if (!bounds.isInside(msgPosX, msgPosY)) {
+ window->m_mousePresent = false;
+ }
+
+ break;
}
}
eventHandled = true;
@@ -1650,29 +1773,153 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
break;
}
case WT_PACKET:
- processWintabEvent(window);
+ processWintabEvent(window, wParam);
eventHandled = true;
break;
////////////////////////////////////////////////////////////////////////
// Pointer events, processed
////////////////////////////////////////////////////////////////////////
case WM_POINTERUPDATE:
+ if (!window->m_mousePresent) {
+ if (window->usingTabletAPI(GHOST_kTabletWintab) && window->getCursorGrabModeIsWarp() &&
+ !window->m_activeWarpX && !window->m_activeWarpY) {
+ int32_t x, y;
+ system->getCursorPosition(x, y);
+
+ GHOST_Rect bounds;
+ window->getClientBounds(bounds);
+
+ if (!bounds.isInside(x, y)) {
+ break;
+ }
+ }
+
+ window->m_mousePresent = true;
+
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->gainFocus();
+ }
+
+ /* Only adjust cursor/grab accum offset if not in the middle of a warp event. */
+ if (window->getCursorGrabModeIsWarp() && !window->m_activeWarpX &&
+ !window->m_activeWarpY) {
+ uint32_t pointerId = GET_POINTERID_WPARAM(wParam);
+ POINTER_INFO pointerInfo;
+ GetPointerInfo(pointerId, &pointerInfo);
+ int x = pointerInfo.ptPixelLocation.x;
+ int y = pointerInfo.ptPixelLocation.y;
+
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x_accum -= x - system->m_lastX;
+ y_accum -= y - system->m_lastY;
+ window->setCursorGrabAccum(x_accum, y_accum);
+ }
+ }
+
+ processPointerEvent(msg, window, wParam, lParam, eventHandled);
+ break;
case WM_POINTERDOWN:
case WM_POINTERUP:
processPointerEvent(msg, window, wParam, lParam, eventHandled);
break;
- case WM_POINTERLEAVE: {
+ case WM_POINTERDEVICEINRANGE:
+ break;
+ case WM_POINTERDEVICEOUTOFRANGE: {
+ /* Check if pointer device left range while outside of the window. This is necessary
+ * because WM_POINTERENTER and WM_POINTERLEAVE events don't fire when a pen enters and
+ * leaves without hoving over the window, but the cursor is moved resulting in a
+ * WM_POINTERLEAVE event for the mouse. */
+ DWORD msgPos = ::GetMessagePos();
+ int msgPosX = GET_X_LPARAM(msgPos);
+ int msgPosY = GET_Y_LPARAM(msgPos);
+
+ GHOST_Rect bounds;
+ window->getClientBounds(bounds);
+
+ if (!bounds.isInside(msgPosX, msgPosY)) {
+ window->m_mousePresent = false;
+ }
+
+ break;
+ }
+ case WM_POINTERENTER: {
+ /* XXX no pointerenter for PT_MOUSE. */
+
uint32_t pointerId = GET_POINTERID_WPARAM(wParam);
POINTER_INFO pointerInfo;
- if (!GetPointerInfo(pointerId, &pointerInfo)) {
+ POINTER_INPUT_TYPE type;
+ if (!GetPointerType(pointerId, &type) || !GetPointerInfo(pointerId, &pointerInfo)) {
+ break;
+ }
+ if (type == PT_PEN) {
+ // window->setPointerPenInfo();
+ }
+
+ /* if mouse is not present, don't apply warp as it will be handled in WM_POINTERUPDATE */
+ /* XXX this is likely causing issues on leaving/entering across same process windows. */
+ if (window->getCursorGrabModeIsWarp() && window->m_mousePresent) {
+ if (type == PT_PEN && window->usingTabletAPI(GHOST_kTabletWintab)) {
+ break;
+ }
+
+ int x = pointerInfo.ptPixelLocation.x;
+ int y = pointerInfo.ptPixelLocation.y;
+
+ int32_t x_accum, y_accum;
+ window->getCursorGrabAccum(x_accum, y_accum);
+ x_accum -= x - system->m_lastX;
+ y_accum -= y - system->m_lastY;
+ window->setCursorGrabAccum(x_accum, y_accum);
+
+ window->m_activeWarpX = 0;
+ window->m_activeWarpY = 0;
+ }
+
+ break;
+ }
+ case WM_POINTERLEAVE: {
+ uint32_t pointerId = GET_POINTERID_WPARAM(wParam);
+ POINTER_INPUT_TYPE type;
+ if (!GetPointerType(pointerId, &type)) {
break;
}
/* Reset pointer pen info if pen device has left tracking range. */
- if (pointerInfo.pointerType == PT_PEN) {
+ /* XXX Note, because touch is considered a left button down, it is never in range when it
+ * leaves */
+ if (type == PT_PEN) {
+ if (window->usingTabletAPI(GHOST_kTabletWintab)) {
+ break;
+ }
window->resetPointerPenInfo();
+
+ /* If pen is still in range, the cursor left the window via a hovering pen. */
+ if (IS_POINTER_INRANGE_WPARAM(wParam)) {
+ window->m_mousePresent = false;
+ }
+
eventHandled = true;
}
+
+ /* XXX this fires when a mouse is moved after having left from a pen device entering
+ * while outside of the window. */
+ if (type == PT_MOUSE && window->m_mousePresent) {
+ window->m_mousePresent = false;
+ /* Check for tablet data in case mouse movement is actually a Wintab device. */
+ if (window->getCursorGrabModeIsWarp() &&
+ window->getTabletData().Active == GHOST_kTabletModeNone) {
+ event = processCursorEvent(window, pointerId);
+ }
+ else if (!window->getCursorGrabModeIsWarp()) {
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->loseFocus();
+ }
+ }
+ }
+
break;
}
////////////////////////////////////////////////////////////////////////
@@ -1713,20 +1960,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_MOUSEMOVE:
- if (!window->m_mousePresent) {
- TRACKMOUSEEVENT tme = {sizeof(tme)};
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hwnd;
- TrackMouseEvent(&tme);
- window->m_mousePresent = true;
- GHOST_Wintab *wt = window->getWintab();
- if (wt) {
- wt->gainFocus();
- }
- }
-
- event = processCursorEvent(window);
-
break;
case WM_MOUSEWHEEL: {
/* The WM_MOUSEWHEEL message is sent to the focus window
@@ -1762,17 +1995,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
}
break;
case WM_MOUSELEAVE: {
- window->m_mousePresent = false;
- if (window->getTabletData().Active == GHOST_kTabletModeNone) {
- event = processCursorEvent(window);
- }
- GHOST_Wintab *wt = window->getWintab();
- if (wt) {
- wt->loseFocus();
- }
break;
}
- ////////////////////////////////////////////////////////////////////////
// Mouse events, ignored
////////////////////////////////////////////////////////////////////////
case WM_NCMOUSEMOVE:
@@ -1817,9 +2041,15 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
window);
/* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL
* will not be dispatched to OUR active window if we minimize one of OUR windows. */
- if (LOWORD(wParam) == WA_INACTIVE)
+ if (LOWORD(wParam) == WA_INACTIVE) {
window->lostMouseCapture();
+ GHOST_Wintab *wt = window->getWintab();
+ if (wt) {
+ wt->loseFocus();
+ }
+ }
+
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
break;
}
@@ -2273,3 +2503,8 @@ int GHOST_SystemWin32::toggleConsole(int action)
return m_consoleStatus;
}
+
+void GHOST_SystemWin32::warpGrabAccum(GHOST_WindowWin32 *win, int32_t x, int32_t y)
+{
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
+}
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 4794982dc65..55d7edcc9b5 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -321,8 +321,9 @@ class GHOST_SystemWin32 : public GHOST_System {
/**
* Creates tablet events from Wintab events.
* \param window: The window receiving the event (the active window).
+ * \param TODO
*/
- static void processWintabEvent(GHOST_WindowWin32 *window);
+ static void processWintabEvent(GHOST_WindowWin32 *window, UINT genSerial);
/**
* Creates tablet events from pointer events.
@@ -338,9 +339,10 @@ class GHOST_SystemWin32 : public GHOST_System {
/**
* Creates cursor event.
* \param window: The window receiving the event (the active window).
+ * \param TODO
* \return The event created.
*/
- static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window);
+ static GHOST_EventCursor *processCursorEvent(GHOST_WindowWin32 *window, int32_t pointerId);
/**
* Handles a mouse wheel event.
@@ -471,6 +473,12 @@ class GHOST_SystemWin32 : public GHOST_System {
/** Wheel delta accumulator. */
int m_wheelDeltaAccum;
+
+ int32_t m_lastX;
+ int32_t m_lastY;
+ bool m_firstProximity = false;
+
+ static void warpGrabAccum(GHOST_WindowWin32 *win, int32_t x, int32_t y);
};
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys &keys) const
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 084b9677fab..a28889cf379 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -194,6 +194,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
loadWintab(GHOST_kWindowStateMinimized != state);
}
+ RegisterPointerDeviceNotifications(m_hWnd, TRUE);
+
/* Allow the showing of a progress bar on the taskbar. */
CoCreateInstance(
CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
@@ -627,6 +629,7 @@ void GHOST_WindowWin32::lostMouseCapture()
m_hasGrabMouse = false;
m_nPressedButtons = 0;
m_hasMouseCaptured = false;
+ m_mousePresent = false; // XXX necessary?
}
}
@@ -878,6 +881,11 @@ GHOST_TSuccess GHOST_WindowWin32::getPointerInfo(
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)GHOST_System::getSystem();
uint32_t outCount = 0;
+ POINTER_INPUT_TYPE inputType;
+ if (GetPointerType(pointerId, &inputType) && inputType == PT_MOUSE) {
+ return GHOST_kFailure;
+ }
+
if (!(GetPointerPenInfoHistory(pointerId, &outCount, NULL))) {
return GHOST_kFailure;
}
@@ -956,6 +964,11 @@ void GHOST_WindowWin32::resetPointerPenInfo()
m_lastPointerTabletData = GHOST_TABLET_DATA_NONE;
}
+void GHOST_WindowWin32::setPointerPenInfo()
+{
+ m_lastPointerTabletData.Active = GHOST_kTabletModeStylus;
+}
+
GHOST_Wintab *GHOST_WindowWin32::getWintab() const
{
return m_wintab;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index 306398618cd..a2d20c460ba 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -269,6 +269,8 @@ class GHOST_WindowWin32 : public GHOST_Window {
*/
void resetPointerPenInfo();
+ void setPointerPenInfo();
+
/**
* Retrieves pointer to Wintab if Wintab is the set Tablet API.
* \return Pointer to Wintab member.
diff --git a/intern/ghost/intern/GHOST_Wintab.cpp b/intern/ghost/intern/GHOST_Wintab.cpp
index cf0309b1521..6fad57ab8c6 100644
--- a/intern/ghost/intern/GHOST_Wintab.cpp
+++ b/intern/ghost/intern/GHOST_Wintab.cpp
@@ -63,6 +63,17 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
return nullptr;
}
+ auto dataGet = (GHOST_WIN32_WTDataGet)::GetProcAddress(handle.get(), "WTDataGet");
+ if (!dataGet) {
+ return nullptr;
+ }
+
+ auto queuePacketsEx = (GHOST_WIN32_WTQueuePacketsEx)::GetProcAddress(handle.get(),
+ "WTQueuePacketsEx");
+ if (!queuePacketsEx) {
+ return nullptr;
+ }
+
auto queueSizeGet = (GHOST_WIN32_WTQueueSizeGet)::GetProcAddress(handle.get(), "WTQueueSizeGet");
if (!queueSizeGet) {
return nullptr;
@@ -136,6 +147,8 @@ GHOST_Wintab *GHOST_Wintab::loadWintab(HWND hwnd)
get,
set,
packetsGet,
+ dataGet,
+ queuePacketsEx,
enable,
overlap,
std::move(hctx),
@@ -180,6 +193,8 @@ GHOST_Wintab::GHOST_Wintab(HWND hwnd,
GHOST_WIN32_WTGet get,
GHOST_WIN32_WTSet set,
GHOST_WIN32_WTPacketsGet packetsGet,
+ GHOST_WIN32_WTDataGet dataGet,
+ GHOST_WIN32_WTQueuePacketsEx queuePacketsEx,
GHOST_WIN32_WTEnable enable,
GHOST_WIN32_WTOverlap overlap,
unique_hctx hctx,
@@ -191,6 +206,8 @@ GHOST_Wintab::GHOST_Wintab(HWND hwnd,
m_fpGet{get},
m_fpSet{set},
m_fpPacketsGet{packetsGet},
+ m_fpDataGet{dataGet},
+ m_fpQueuePacketsEx{queuePacketsEx},
m_fpEnable{enable},
m_fpOverlap{overlap},
m_context{std::move(hctx)},
@@ -244,7 +261,16 @@ void GHOST_Wintab::leaveRange()
/* Set to none to indicate tablet is inactive. */
m_lastTabletData = GHOST_TABLET_DATA_NONE;
/* Clear the packet queue. */
- m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+ // XXX proximity may return before proximity leave is processed, this would thus clear valid
+ // events.
+ // m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+}
+
+void GHOST_Wintab::enterRange()
+{
+ /* Dummy until input arrives. */
+ m_lastTabletData.Active = GHOST_kTabletModeStylus;
+ m_firstProximity = true;
}
void GHOST_Wintab::remapCoordinates()
@@ -295,10 +321,29 @@ GHOST_TabletData GHOST_Wintab::getLastTabletData()
return m_lastTabletData;
}
-void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo)
+void GHOST_Wintab::getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo, UINT genSerial)
{
- const int numPackets = m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+ // const int numPackets = m_fpPacketsGet(m_context.get(), m_pkts.size(), m_pkts.data());
+ // outWintabInfo.resize(numPackets);
+ UINT beginSerial, unusedEndSerial;
+ if (!m_fpQueuePacketsEx(m_context.get(), &beginSerial, &unusedEndSerial)) {
+ return;
+ }
+ int numPackets;
+ m_fpDataGet(m_context.get(), beginSerial, genSerial, m_pkts.size(), m_pkts.data(), &numPackets);
+
+ /* If this is the first event since a proximity event, we want to skip all events prior to the
+ * one which triggered the WT_PACKET event so that we don't use events from the last time the
+ * stylus was in range. */
+ if (m_firstProximity) {
+ m_firstProximity = false;
+
+ m_pkts[0] = m_pkts[numPackets - 1];
+ numPackets = 1;
+ }
+
outWintabInfo.resize(numPackets);
+
size_t outExtent = 0;
for (int i = 0; i < numPackets; i++) {
diff --git a/intern/ghost/intern/GHOST_Wintab.h b/intern/ghost/intern/GHOST_Wintab.h
index 443c726d270..5716b893b49 100644
--- a/intern/ghost/intern/GHOST_Wintab.h
+++ b/intern/ghost/intern/GHOST_Wintab.h
@@ -46,6 +46,8 @@ typedef BOOL(API *GHOST_WIN32_WTSet)(HCTX, LPLOGCONTEXTA);
typedef HCTX(API *GHOST_WIN32_WTOpen)(HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL(API *GHOST_WIN32_WTClose)(HCTX);
typedef int(API *GHOST_WIN32_WTPacketsGet)(HCTX, int, LPVOID);
+typedef BOOL(API *GHOST_WIN32_WTQueuePacketsEx)(HCTX, UINT FAR *, UINT FAR *);
+typedef int(API *GHOST_WIN32_WTDataGet)(HCTX, UINT, UINT, int, LPVOID, LPINT);
typedef int(API *GHOST_WIN32_WTQueueSizeGet)(HCTX);
typedef BOOL(API *GHOST_WIN32_WTQueueSizeSet)(HCTX, int);
typedef BOOL(API *GHOST_WIN32_WTEnable)(HCTX, BOOL);
@@ -91,6 +93,8 @@ class GHOST_Wintab {
*/
void loseFocus();
+ void enterRange();
+
/**
* Clean up when Wintab leaves tracking range.
*/
@@ -130,8 +134,9 @@ class GHOST_Wintab {
/**
* Translate Wintab packets into GHOST_WintabInfoWin32 structs.
* \param outWintabInfo: Storage to return resulting GHOST_WintabInfoWin32 data.
+ * \param TODO
*/
- void getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo);
+ void getInput(std::vector<GHOST_WintabInfoWin32> &outWintabInfo, UINT genSerial);
/**
* Whether Wintab coordinates should be trusted.
@@ -167,6 +172,8 @@ class GHOST_Wintab {
GHOST_WIN32_WTGet m_fpGet = nullptr;
GHOST_WIN32_WTSet m_fpSet = nullptr;
GHOST_WIN32_WTPacketsGet m_fpPacketsGet = nullptr;
+ GHOST_WIN32_WTDataGet m_fpDataGet = nullptr;
+ GHOST_WIN32_WTQueuePacketsEx m_fpQueuePacketsEx = nullptr;
GHOST_WIN32_WTEnable m_fpEnable = nullptr;
GHOST_WIN32_WTOverlap m_fpOverlap = nullptr;
@@ -176,6 +183,7 @@ class GHOST_Wintab {
bool m_enabled = false;
/** Whether the context has focus and is at the top of overlap order. */
bool m_focused = false;
+ bool m_firstProximity = false;
/** Pressed button map. */
uint8_t m_buttons = 0;
@@ -219,6 +227,8 @@ class GHOST_Wintab {
GHOST_WIN32_WTGet get,
GHOST_WIN32_WTSet set,
GHOST_WIN32_WTPacketsGet packetsGet,
+ GHOST_WIN32_WTDataGet dataGet,
+ GHOST_WIN32_WTQueuePacketsEx queuePacketsEx,
GHOST_WIN32_WTEnable enable,
GHOST_WIN32_WTOverlap overlap,
unique_hctx hctx,
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 50d3a856cbe..f6abf1c7818 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -271,9 +271,7 @@ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4])
if ((G.debug & G_DEBUG) == 0) {
if (win->ghostwin) {
- if (win->eventstate->tablet.is_motion_absolute == false) {
- GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL);
- }
+ GHOST_SetCursorGrab(win->ghostwin, mode, mode_axis, bounds, NULL);
win->grabcursor = mode;
}