1
1

Compare commits

...

11 Commits

Author SHA1 Message Date
578f82d2ee Add tablet data to mouse input. 2021-09-05 20:17:28 -07:00
1a419c9f4e [WIP] Continuous grab for tablets
This revision modifies mouse and tablet handling to allow both to interchangably accumulate during continuous grab. For tablet input in pen mode, grab accumulates over the change in position while the tablet is in range. For a tablet in mouse mode, grab accumulates as a normal mouse accumulates.

Also adds ability for operators to force continuous grab. This is necessary for the walk operator which has been rewritten to take advantage of tablet continuous grab.

Differential Revision: https://developer.blender.org/D12408
2021-09-05 20:12:00 -07:00
3af3e77e67 Cleanup 2021-09-05 16:41:33 -07:00
1a00134ab0 Converted walk operator to use continuous grab. Mouse and tablet are now opaque to the operator handling.
Continous grab has to be forced even if user has disabled it.
2021-09-05 11:51:43 -07:00
a8f7bfa213 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
2021-09-05 11:51:43 -07:00
ccd5264344 Consolidate repeat actions. 2021-09-04 18:18:56 -07:00
d06fb5a92b Improve cursor wrap reliability. 2021-09-04 18:18:56 -07:00
aea5b4fbfa Cleanup: remove unmodified return variable. 2021-09-04 18:18:56 -07:00
fa80af4455 Fix Windows cursor wrap jumps. 2021-09-04 18:18:56 -07:00
bcab006892 Supply tablet data with 2021-09-04 18:18:56 -07:00
fa0e0bcf32 Cleanup: replace defines with static const in walk/fly operators.
No functional changes.
2021-09-04 18:18:56 -07:00
12 changed files with 493 additions and 218 deletions

View File

@@ -108,29 +108,35 @@
static void initRawInput()
{
#ifdef WITH_INPUT_NDOF
# define DEVICE_COUNT 2
# define DEVICE_COUNT 3
#else
# define DEVICE_COUNT 1
# define DEVICE_COUNT 2
#endif
RAWINPUTDEVICE devices[DEVICE_COUNT];
memset(devices, 0, DEVICE_COUNT * sizeof(RAWINPUTDEVICE));
// Initiates WM_INPUT messages from keyboard
// That way GHOST can retrieve true keys
/* Initiates WM_INPUT messages from keyboard.
* That way GHOST can retrieve true keys.
*/
devices[0].usUsagePage = 0x01;
devices[0].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
#ifdef WITH_INPUT_NDOF
// multi-axis mouse (SpaceNavigator, etc.)
/* Initiates WM_INPUT messages for mouse.
* Used to differentiate absolute and relative cursor movement.
* */
devices[1].usUsagePage = 0x01;
devices[1].usUsage = 0x08;
devices[1].usUsage = 0x02;
#ifdef WITH_INPUT_NDOF
/* multi - axis mouse(SpaceNavigator, etc.) */
devices[2].usUsagePage = 0x01;
devices[2].usUsage = 0x08;
#endif
if (RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE)))
; // yay!
else
if (!RegisterRawInputDevices(devices, DEVICE_COUNT, sizeof(RAWINPUTDEVICE))) {
GHOST_PRINTF("could not register for RawInput: %d\n", (int)GetLastError());
}
#undef DEVICE_COUNT
}
@@ -150,6 +156,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 +168,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()
@@ -461,6 +474,8 @@ GHOST_TSuccess GHOST_SystemWin32::getCursorPosition(int32_t &x, int32_t &y) cons
GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(int32_t x, int32_t y)
{
/* Don't use SendInput or mouse_event functions. Unlike SetCursorPos, they are received by
* WM_INPUT processing and interrupt differentiating absolute vs relative mouse input. */
if (!::GetActiveWindow())
return GHOST_kFailure;
return ::SetCursorPos(x, y) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
@@ -878,7 +893,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 +903,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
@@ -896,9 +911,7 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
*
* If Wintab was never trusted while processing this Win32 event, a fallback Ghost cursor move
* event is created at the position of the Win32 WT_PACKET event. */
bool mouseMoveHandled;
bool useWintabPos;
mouseMoveHandled = useWintabPos = wt->trustCoordinates();
bool useWintabPos = wt->trustCoordinates();
for (GHOST_WintabInfoWin32 &info : wintabInfo) {
switch (info.type) {
@@ -908,8 +921,30 @@ 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;
if (window->getCursorGrabModeIsWarp()) {
system->warpGrabAccum(window, 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));
system->m_lastX = info.x;
system->m_lastY = info.y;
break;
}
@@ -948,14 +983,23 @@ 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(
new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
mouseMoveHandled = true;
break;
}
}
@@ -996,25 +1040,18 @@ void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window)
break;
}
}
/* Fallback cursor movement if Wintab position were never trusted while processing this event. */
if (!mouseMoveHandled) {
DWORD pos = GetMessagePos();
int x = GET_X_LPARAM(pos);
int y = GET_Y_LPARAM(pos);
/* TODO supply tablet data */
system->pushEvent(new GHOST_EventCursor(
system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, GHOST_TABLET_DATA_NONE));
}
}
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;
}
@@ -1022,6 +1059,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);
if (event) {
system->pushEvent(event);
eventHandled = true;
}
}
return;
}
@@ -1030,25 +1074,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,
@@ -1060,6 +1122,7 @@ void GHOST_SystemWin32::processPointerEvent(
eventHandled = true;
break;
}
case WM_POINTERUP:
system->pushEvent(new GHOST_EventButton(pointerInfo[0].time,
GHOST_kEventButtonUp,
@@ -1079,20 +1142,49 @@ void GHOST_SystemWin32::processPointerEvent(
GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window)
{
int32_t x_screen, y_screen;
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
if (window->getTabletData().Active != GHOST_kTabletModeNone) {
/* While pen devices are in range, cursor movement is handled by tablet input processing. */
return NULL;
/* Don't use GetPointerInfo to obtain mouse position. It is identical to GetMessagePos for
* WM_POINTERUPDATE messages, but returns outdated position for WM_POINTERLEAVE messages thus
* doesn't warp when it should.
* This difference only seems to occur while RAWINPUT mouse processing is enabled. */
DWORD pos = ::GetMessagePos();
int32_t x_screen = GET_X_LPARAM(pos);
int32_t y_screen = GET_Y_LPARAM(pos);
/* TODO supply tablet data */
GHOST_TabletData td = window->getTabletData();
td.Pressure = 1.0f;
if (td.Active != GHOST_kTabletModeNone) {
GHOST_Wintab *wt = window->getWintab();
if (window->usingTabletAPI(GHOST_kTabletWintab) && wt && !wt->trustCoordinates()) {
/* Fallback cursor movement if Wintab position were never trusted while processing this
* event. This may happen if the tablet coordinate scaling is off, hasn't yet been
verified,
* or if the tablet is in mouse mode. */
if (system->m_firstProximity) {
system->m_firstProximity = false;
if (window->getCursorGrabModeIsWarp()) {
system->warpGrabAccum(window, x_screen, y_screen);
}
}
}
else {
/* While pen devices are in range, cursor movement is handled by tablet input processing.
*/
return NULL;
}
}
system->getCursorPosition(x_screen, y_screen);
int32_t x_accum = 0;
int32_t y_accum = 0;
if (window->getCursorGrabModeIsWarp()) {
int32_t x_new = x_screen;
int32_t y_new = y_screen;
int32_t x_accum, y_accum;
GHOST_Rect bounds;
/* Fallback to window bounds. */
@@ -1105,30 +1197,45 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind
bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis());
window->getCursorGrabAccum(x_accum, y_accum);
if (x_new != x_screen || y_new != y_screen) {
/* When wrapping we don't need to add an event because the setCursorPosition call will cause
* a new event after. */
int32_t warpX = x_new - x_screen;
int32_t warpY = y_new - y_screen;
if ((warpX || warpY) && !system->m_absoluteCursor) {
system->setCursorPosition(x_new, y_new); /* wrap */
window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new));
/* 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) {
x_accum -= warpX;
}
if (window->m_activeWarpY >= 0 && warpY < 0 || window->m_activeWarpY <= 0 && warpY > 0) {
y_accum -= warpY;
}
window->setCursorGrabAccum(x_accum, y_accum);
window->m_activeWarpX = warpX;
window->m_activeWarpY = warpY;
/* Accum not relative to new cursor position, update screen position so the event will be
* placed correctly. */
x_screen = x_new;
y_screen = y_new;
}
else {
return new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_screen + x_accum,
y_screen + y_accum,
GHOST_TABLET_DATA_NONE);
window->m_activeWarpX = 0;
window->m_activeWarpY = 0;
}
}
else {
return new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_screen,
y_screen,
GHOST_TABLET_DATA_NONE);
}
return NULL;
system->m_lastX = x_screen;
system->m_lastY = y_screen;
return new GHOST_EventCursor(system->getMilliSeconds(),
GHOST_kEventCursorMove,
window,
x_screen + x_accum,
y_screen + y_accum,
td);
}
void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
@@ -1454,6 +1561,18 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
eventHandled = true;
}
break;
case RIM_TYPEMOUSE: {
/* We would like to correlate absolute/relative input to specific devices in
* WM_POINTER, but all PT_MOUSE pointers' device handle contains the same virtual
* mouse thus loose device information. */
bool now = raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE;
if (system->m_absoluteCursor ^ now) {
printf("%d\n", now);
}
system->m_absoluteCursor = raw.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE;
eventHandled = true;
break;
}
#endif
}
break;
@@ -1606,9 +1725,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;
@@ -1627,29 +1776,145 @@ 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) {
/* Wintab asynchronously generates mouse events, if a pen briefly enters then leaves
* outside of the window the associated mouse movements may arrive late, thus we will
* wrap the cursor, leading to an unintuitive jump. */
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;
system->warpGrabAccum(window, x, y);
}
}
processPointerEvent(msg, window, wParam, lParam, eventHandled);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
processPointerEvent(msg, window, wParam, lParam, eventHandled);
break;
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_INPUT_TYPE type;
if (!GetPointerType(pointerId, &type)) {
break;
}
/* 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 = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
// XXX clienttoscreen?
system->warpGrabAccum(window, x, y);
window->m_activeWarpX = 0;
window->m_activeWarpY = 0;
}
break;
}
case WM_POINTERLEAVE: {
uint32_t pointerId = GET_POINTERID_WPARAM(wParam);
POINTER_INFO pointerInfo;
if (!GetPointerInfo(pointerId, &pointerInfo)) {
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;
}
else if (type == PT_MOUSE && window->m_mousePresent) {
/* XXX this fires when a mouse is moved after having left from a pen device entering
* while outside of the window. */
window->m_mousePresent = false;
/* Check for tablet data in case mouse movement is actually a Wintab device. */
if (window->getCursorGrabModeIsWarp()) {
event = processCursorEvent(window);
}
else {
GHOST_Wintab *wt = window->getWintab();
if (wt) {
wt->loseFocus();
}
}
eventHandled = true;
}
break;
}
////////////////////////////////////////////////////////////////////////
@@ -1690,20 +1955,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
@@ -1739,17 +1990,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:
@@ -1794,9 +2036,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;
}
@@ -2250,3 +2498,12 @@ int GHOST_SystemWin32::toggleConsole(int action)
return m_consoleStatus;
}
void GHOST_SystemWin32::warpGrabAccum(GHOST_WindowWin32 *win, int32_t x, int32_t y)
{
int32_t x_accum, y_accum;
win->getCursorGrabAccum(x_accum, y_accum);
x_accum -= x - this->m_lastX;
y_accum -= y - this->m_lastY;
win->setCursorGrabAccum(x_accum, y_accum);
}

View File

@@ -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.
@@ -471,6 +472,13 @@ class GHOST_SystemWin32 : public GHOST_System {
/** Wheel delta accumulator. */
int m_wheelDeltaAccum;
int32_t m_lastX;
int32_t m_lastY;
bool m_firstProximity = false;
bool m_absoluteCursor = false;
void warpGrabAccum(GHOST_WindowWin32 *win, int32_t x, int32_t y);
};
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys &keys) const

View File

@@ -1072,8 +1072,6 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
GHOST_TSuccess err = GHOST_kSuccess;
if (mode != GHOST_kGrabDisable) {
// No need to perform grab without warp as it is always on in OS X
if (mode != GHOST_kGrabNormal) {
@@ -1103,7 +1101,8 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode
setCursorGrabAccum(0, 0);
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
}
return err;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)

View File

@@ -75,6 +75,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_isDialog(dialog),
m_hasMouseCaptured(false),
m_hasGrabMouse(false),
m_activeWarpX(0),
m_activeWarpY(0),
m_nPressedButtons(0),
m_customCursor(0),
m_wantAlphaBackground(alphaBackground),
@@ -192,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);
@@ -625,6 +629,7 @@ void GHOST_WindowWin32::lostMouseCapture()
m_hasGrabMouse = false;
m_nPressedButtons = 0;
m_hasMouseCaptured = false;
m_mousePresent = false; // XXX necessary?
}
}
@@ -820,6 +825,8 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
if (mode != GHOST_kGrabNormal) {
m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
setCursorGrabAccum(0, 0);
m_activeWarpX = 0;
m_activeWarpY = 0;
if (mode == GHOST_kGrabHide)
setWindowCursorVisibility(false);
@@ -843,6 +850,8 @@ GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode
/* Almost works without but important otherwise the mouse GHOST location
* can be incorrect on exit. */
setCursorGrabAccum(0, 0);
m_activeWarpX = 0;
m_activeWarpY = 0;
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
updateMouseCapture(OperatorUngrab);
}
@@ -872,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;
}
@@ -950,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;

View File

@@ -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.
@@ -307,6 +309,10 @@ class GHOST_WindowWin32 : public GHOST_Window {
/** True if the mouse is either over or captured by the window. */
bool m_mousePresent;
/** Active cursor warp in x axis. */
int32_t m_activeWarpX;
/** Active cursor warp in y axis. */
int32_t m_activeWarpY;
/** True if the window currently resizing. */
bool m_inLiveResize;

View File

@@ -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++) {

View File

@@ -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,

View File

@@ -752,10 +752,14 @@ static void flyMoveCamera(bContext *C,
static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
{
#define FLY_ROTATE_FAC 10.0f /* more is faster */
#define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */
#define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */
#define FLY_SMOOTH_FAC 20.0f /* higher value less lag */
/* Higher is faster. */
static const float fly_rotate_factor = 10.0f;
/* Amount to correct per step. */
static const float fly_z_up_correct_factor = 0.1f;
/* Increase upright momentum each step. */
static const float fly_z_up_correct_accel = 0.05f;
/* Higher is less lag. */
static const float fly_smooth_factor = 20.0f;
RegionView3D *rv3d = fly->rv3d;
@@ -875,7 +879,7 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f);
mul_m3_v3(mat, upvec);
/* Rotate about the relative up vec */
axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC);
axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -fly_rotate_factor);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF) {
@@ -908,7 +912,7 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
}
/* Rotate about the relative up vec */
axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC);
axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * fly_rotate_factor);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
if (fly->xlock != FLY_AXISLOCK_STATE_OFF) {
@@ -934,10 +938,10 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
axis_angle_to_quat(tmp_quat,
upvec,
roll * time_redraw_clamped * fly->zlock_momentum *
FLY_ZUP_CORRECT_FAC);
fly_z_up_correct_factor);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL;
fly->zlock_momentum += fly_z_up_correct_accel;
}
else {
/* don't check until the view rotates again */
@@ -996,7 +1000,7 @@ static int flyApply(bContext *C, FlyInfo *fly, bool is_confirm)
/* impose a directional lag */
interp_v3_v3v3(
dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC))));
dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * fly_smooth_factor))));
add_v3_v3(rv3d->ofs, dvec);

View File

@@ -284,9 +284,6 @@ typedef struct WalkInfo {
bool is_reversed;
#ifdef USE_TABLET_SUPPORT
/** Check if we had a cursor event before. */
bool is_cursor_first;
/** Tablet devices (we can't relocate the cursor). */
bool is_cursor_absolute;
#endif
@@ -495,7 +492,7 @@ enum {
static float base_speed = -1.0f;
static float userdef_speed = -1.0f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op, wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -537,6 +534,8 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
userdef_speed = U.walk_navigation.walk_speed;
}
walk->moffset[0] = 0;
walk->moffset[1] = 0;
walk->speed = 0.0f;
walk->is_fast = false;
walk->is_slow = false;
@@ -573,8 +572,6 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
#ifdef USE_TABLET_SUPPORT
walk->is_cursor_first = true;
walk->is_cursor_absolute = false;
#endif
@@ -622,11 +619,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->center_mval[1] -= walk->region->winrct.ymin;
#endif
copy_v2_v2_int(walk->prev_mval, walk->center_mval);
WM_cursor_warp(win,
walk->region->winrct.xmin + walk->center_mval[0],
walk->region->winrct.ymin + walk->center_mval[1]);
copy_v2_v2_int(walk->prev_mval, event->mval);
/* remove the mouse cursor temporarily */
WM_cursor_modal_set(win, WM_CURSOR_NONE);
@@ -706,59 +699,13 @@ static void walkEvent(bContext *C, WalkInfo *walk, const wmEvent *event)
walk->redraw = true;
}
else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_first) {
/* wait until we get the 'warp' event */
if ((walk->center_mval[0] == event->mval[0]) && (walk->center_mval[1] == event->mval[1])) {
walk->is_cursor_first = false;
}
else {
/* NOTE: its possible the system isn't giving us the warp event
* ideally we shouldn't have to worry about this, see: T45361 */
wmWindow *win = CTX_wm_window(C);
WM_cursor_warp(win,
walk->region->winrct.xmin + walk->center_mval[0],
walk->region->winrct.ymin + walk->center_mval[1]);
}
return;
}
if ((walk->is_cursor_absolute == false) && event->tablet.is_motion_absolute) {
walk->is_cursor_absolute = true;
copy_v2_v2_int(walk->prev_mval, event->mval);
copy_v2_v2_int(walk->center_mval, event->mval);
}
#endif /* USE_TABLET_SUPPORT */
walk->moffset[0] += event->mval[0] - walk->prev_mval[0];
walk->moffset[1] += event->mval[1] - walk->prev_mval[1];
copy_v2_v2_int(walk->prev_mval, event->mval);
if ((walk->center_mval[0] != event->mval[0]) || (walk->center_mval[1] != event->mval[1])) {
if (walk->moffset[0] != 0 || walk->moffset[1] != 0) {
walk->redraw = true;
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
/* pass */
}
else
#endif
if (WM_event_is_last_mousemove(event)) {
wmWindow *win = CTX_wm_window(C);
#ifdef __APPLE__
if ((abs(walk->prev_mval[0] - walk->center_mval[0]) > walk->center_mval[0] / 2) ||
(abs(walk->prev_mval[1] - walk->center_mval[1]) > walk->center_mval[1] / 2))
#endif
{
WM_cursor_warp(win,
walk->region->winrct.xmin + walk->center_mval[0],
walk->region->winrct.ymin + walk->center_mval[1]);
copy_v2_v2_int(walk->prev_mval, walk->center_mval);
}
}
}
}
#ifdef WITH_INPUT_NDOF
@@ -1007,14 +954,16 @@ static float getVelocityZeroTime(const float gravity, const float velocity)
static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
{
#define WALK_ROTATE_TABLET_FAC 8.8f /* Higher is faster, relative to region size. */
#define WALK_ROTATE_CONSTANT_FAC DEG2RAD(0.15f) /* Higher is faster, radians per-pixel. */
#define WALK_TOP_LIMIT DEG2RADF(85.0f)
#define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f)
#define WALK_MOVE_SPEED base_speed
#define WALK_BOOST_FACTOR ((void)0, walk->speed_factor)
#define WALK_ZUP_CORRECT_FAC 0.1f /* Amount to correct per step. */
#define WALK_ZUP_CORRECT_ACCEL 0.05f /* Increase upright momentum each step. */
/* Higher is faster, relative to region size. */
static const float walk_rotate_tablet_factor = 8.8f;
/* Higher is faster, radians per-pixel. */
static const float walk_rotate_constant_factor = DEG2RAD(0.15f);
static const float walk_top_limit = DEG2RADF(85.0f);
static const float walk_bottom_limit = DEG2RADF(-80.0f);
/* Amount to correct per step. */
static const float walk_zup_correct_fac = 0.1f;
/* Increase upright momentum each step. */
static const float walk_zup_correct_accel = 0.05f;
RegionView3D *rv3d = walk->rv3d;
ARegion *region = walk->region;
@@ -1071,13 +1020,13 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
walk->time_lastdraw = time_current;
/* base speed in m/s */
walk->speed = WALK_MOVE_SPEED;
walk->speed = base_speed;
if (walk->is_fast) {
walk->speed *= WALK_BOOST_FACTOR;
walk->speed *= walk->speed_factor;
}
else if (walk->is_slow) {
walk->speed *= 1.0f / WALK_BOOST_FACTOR;
walk->speed *= 1.0f / walk->speed_factor;
}
copy_m3_m4(mat, rv3d->viewinv);
@@ -1093,16 +1042,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
y = (float)moffset[1];
/* Speed factor. */
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
y /= region->winy;
y *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
{
y *= WALK_ROTATE_CONSTANT_FAC;
}
y *= walk_rotate_constant_factor;
/* user adjustment factor */
y *= walk->mouse_speed;
@@ -1111,10 +1051,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* it ranges from 90.0f to -90.0f */
angle = -asinf(rv3d->viewmat[2][2]);
if (angle > WALK_TOP_LIMIT && y > 0.0f) {
if (angle > walk_top_limit && y > 0.0f) {
y = 0.0f;
}
else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f) {
else if (angle < walk_bottom_limit && y < 0.0f) {
y = 0.0f;
}
@@ -1142,16 +1082,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
x = (float)moffset[0];
/* Speed factor. */
#ifdef USE_TABLET_SUPPORT
if (walk->is_cursor_absolute) {
x /= region->winx;
x *= WALK_ROTATE_TABLET_FAC;
}
else
#endif
{
x *= WALK_ROTATE_CONSTANT_FAC;
}
x *= walk_rotate_constant_factor;
/* user adjustment factor */
x *= walk->mouse_speed;
@@ -1176,10 +1107,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
axis_angle_to_quat(tmp_quat,
upvec,
roll * time_redraw_clamped * walk->zlock_momentum *
WALK_ZUP_CORRECT_FAC);
walk_zup_correct_fac);
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
walk->zlock_momentum += WALK_ZUP_CORRECT_ACCEL;
walk->zlock_momentum += walk_zup_correct_accel;
}
else {
/* Lock fixed, don't need to check it ever again. */
@@ -1279,7 +1210,7 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
/* the distance we would fall naturally smoothly enough that we
* can manually drop the object without activating gravity */
fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR;
fall_distance = time_redraw * walk->speed * walk->speed_factor;
if (fabsf(difference) < fall_distance) {
/* slope/stairs */
@@ -1392,11 +1323,6 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
}
return OPERATOR_FINISHED;
#undef WALK_ROTATE_TABLET_FAC
#undef WALK_TOP_LIMIT
#undef WALK_BOTTOM_LIMIT
#undef WALK_MOVE_SPEED
#undef WALK_BOOST_FACTOR
}
#ifdef WITH_INPUT_NDOF
@@ -1445,7 +1371,7 @@ static int walk_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->customdata = walk;
if (initWalkInfo(C, walk, op) == false) {
if (initWalkInfo(C, walk, op, event) == false) {
MEM_freeN(op->customdata);
return OPERATOR_CANCELLED;
}
@@ -1524,7 +1450,7 @@ void VIEW3D_OT_walk(wmOperatorType *ot)
ot->poll = ED_operator_region_view3d_active;
/* flags */
ot->flag = OPTYPE_BLOCKING;
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR_XY | OPTYPE_GRAB_CURSOR_FORCE;
}
/** \} */

View File

@@ -184,6 +184,9 @@ enum {
OPTYPE_LOCK_BYPASS = (1 << 9),
/** Special type of undo which doesn't store itself multiple times. */
OPTYPE_UNDO_GROUPED = (1 << 10),
/** Force cursor warp. */
OPTYPE_GRAB_CURSOR_FORCE = (1 << 11),
};
/** For #WM_cursor_grab_enable wrap axis. */

View File

@@ -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;
}

View File

@@ -1397,7 +1397,7 @@ static int wm_operator_invoke(bContext *C,
int bounds[4] = {-1, -1, -1, -1};
int wrap = WM_CURSOR_WRAP_NONE;
if (event && (U.uiflag & USER_CONTINUOUS_MOUSE)) {
if (event && (U.uiflag & USER_CONTINUOUS_MOUSE || op->flag & OPTYPE_GRAB_CURSOR_FORCE)) {
const wmOperator *op_test = op->opm ? op->opm : op;
const wmOperatorType *ot_test = op_test->type;
if ((ot_test->flag & OPTYPE_GRAB_CURSOR_XY) ||