Compare commits
11 Commits
temp-llvm-
...
grab_walk_
Author | SHA1 | Date | |
---|---|---|---|
578f82d2ee | |||
1a419c9f4e | |||
3af3e77e67 | |||
1a00134ab0 | |||
a8f7bfa213 | |||
ccd5264344 | |||
d06fb5a92b | |||
aea5b4fbfa | |||
fa80af4455 | |||
bcab006892 | |||
fa0e0bcf32 |
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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++) {
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@@ -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. */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) ||
|
||||
|
Reference in New Issue
Block a user