Changeset View
Standalone View
intern/ghost/intern/GHOST_SystemWin32.cpp
| Show First 20 Lines • Show All 860 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, | GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, | ||||
| GHOST_WindowWin32 *window, | GHOST_WindowWin32 *window, | ||||
| GHOST_TButtonMask mask) | GHOST_TButtonMask mask) | ||||
| { | { | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| if (type == GHOST_kEventButtonDown) { | GHOST_TabletData td = window->getTabletData(); | ||||
| /* Move mouse to button event position. */ | |||||
| if (window->getTabletData().Active != GHOST_kTabletModeNone) { | |||||
| /* Tablet should be handling inbetween mouse moves, only move to event position. */ | |||||
| DWORD msgPos = ::GetMessagePos(); | |||||
| int msgPosX = GET_X_LPARAM(msgPos); | |||||
| int msgPosY = GET_Y_LPARAM(msgPos); | |||||
| system->pushEvent(new GHOST_EventCursor( | |||||
| ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td)); | |||||
brecht: I guess this event is often redundant, and already handed through a mouse move event?
Do we… | |||||
Done Inline ActionsThis would not generally be redundant because tablet events (Wintab and WinPointer iirc) are asynchronously ordered from mouse events. If we're receiving a button event while a tablet is present, either Wintab handling failed to steal the event from Windows event queue (common case) or the mouse event was not generated from the stylus (e.g. a tablet pad's express buttons). In general operators should be tolerant of spurious mouse events because 1. variable pressure without motion requires this and 2. Windows intentionally generates spurious mouse movements which are currently not filtered out. nicholas_rishel: This would not generally be redundant because tablet events (Wintab and WinPointer iirc) are… | |||||
Not Done Inline ActionsAh, I missed that this code only runs for tablets. It seems reasonable then. I guess at worst on the WM side it will generate an extra inbetween mousemove event, which is not a problem. brecht: Ah, I missed that this code only runs for tablets. It seems reasonable then. I guess at worst… | |||||
| } | |||||
| window->updateMouseCapture(type == GHOST_kEventButtonDown ? MousePressed : MouseReleased); | |||||
| return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); | |||||
| } | |||||
| void GHOST_SystemWin32::processWintabEvent(GHOST_WindowWin32 *window) | |||||
| { | |||||
| GHOST_Wintab *wt = window->getWintab(); | |||||
| if (!wt) { | |||||
| return; | |||||
| } | |||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | |||||
| std::vector<GHOST_WintabInfoWin32> wintabInfo; | |||||
| wt->getInput(wintabInfo); | |||||
| bool mouseUpdated = wt->trustCoordinates(); | |||||
| for (auto info : wintabInfo) { | |||||
| switch (info.type) { | |||||
| case GHOST_kEventCursorMove: { | |||||
| if (!wt->trustCoordinates()) { | |||||
| continue; | |||||
| } | |||||
| wt->mapWintabToSysCoordinates(info.x, info.y, info.x, info.y); | |||||
| system->pushEvent(new GHOST_EventCursor( | |||||
| info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); | |||||
| break; | |||||
| } | |||||
| case GHOST_kEventButtonDown: { | |||||
| /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is | |||||
| * in. Only issue button events if we can steal an equivalent Win32 button event from the | |||||
| * event queue. */ | |||||
| UINT message; | |||||
| switch (info.button) { | |||||
| case GHOST_kButtonMaskLeft: | |||||
| message = WM_LBUTTONDOWN; | |||||
| break; | |||||
| case GHOST_kButtonMaskRight: | |||||
| message = WM_RBUTTONDOWN; | |||||
| break; | |||||
| case GHOST_kButtonMaskMiddle: | |||||
| message = WM_MBUTTONDOWN; | |||||
| break; | |||||
| default: | |||||
| continue; | |||||
| } | |||||
| MSG msg; | |||||
| if (PeekMessage(&msg, window->getHWND(), message, message, PM_NOYIELD) && | |||||
| WM_QUIT != msg.message) { | |||||
LazyDodoUnsubmitted Not Done Inline ActionsThere's quite a few comparisons in the [constant] [comparison] [variable] form, while it is sometimes advocated as "the safe way, just in case you make a typo, and ignore all warnings the compiler emits about that" it also makes the code harder to read than necessary. I don't think we have any guidance in the code-style guide, given my personal preferences commonly being at odds with our code-style I'm going to defer the final decision here to @Brecht Van Lommel (brecht) Whatever way is chosen though, its application at this point is inconsistent [constant] [comparison] [variable] and [variable] [comparison] [constant] both appear in newly added code. LazyDodo: There's quite a few comparisons in the `[constant] [comparison] [variable]` form, while it is… | |||||
brechtUnsubmitted Not Done Inline Actions[variable] [comparison] [constant] is most common in the code and I would consider that the implicit convention that is suggested to be followed. brecht: [variable] [comparison] [constant] is most common in the code and I would consider that the… | |||||
| if (wt->testCoordinates(msg.pt.x, msg.pt.y, info.x, info.y)) { | |||||
| PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD); | |||||
| /* 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); | |||||
| system->pushEvent(new GHOST_EventCursor( | |||||
| info.time, GHOST_kEventCursorMove, window, info.x, info.y, info.tabletData)); | |||||
| window->updateMouseCapture(MousePressed); | window->updateMouseCapture(MousePressed); | ||||
| system->pushEvent( | |||||
| new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); | |||||
| mouseUpdated = true; | |||||
| } | |||||
| } | |||||
| break; | |||||
| } | |||||
| case GHOST_kEventButtonUp: { | |||||
| if (!wt->trustCoordinates()) { | |||||
| continue; | |||||
| } | } | ||||
| else if (type == GHOST_kEventButtonUp) { | |||||
| /* Wintab buttons are modal, but the API does not inform us what mode a pressed button is | |||||
| * in. Only issue button events if we can steal an equivalent Win32 button event from the | |||||
| * event queue. */ | |||||
| UINT message; | |||||
| switch (info.button) { | |||||
| case GHOST_kButtonMaskLeft: | |||||
| message = WM_LBUTTONUP; | |||||
| break; | |||||
| case GHOST_kButtonMaskRight: | |||||
| message = WM_RBUTTONUP; | |||||
| break; | |||||
| case GHOST_kButtonMaskMiddle: | |||||
| message = WM_MBUTTONUP; | |||||
| break; | |||||
| default: | |||||
| continue; | |||||
| } | |||||
| MSG msg; | |||||
| if (PeekMessage(&msg, window->getHWND(), message, message, PM_REMOVE | PM_NOYIELD) && | |||||
| WM_QUIT != msg.message) { | |||||
| window->updateMouseCapture(MouseReleased); | window->updateMouseCapture(MouseReleased); | ||||
| system->pushEvent( | |||||
| new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData)); | |||||
| } | |||||
| break; | |||||
| } | |||||
| default: | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| return new GHOST_EventButton( | /* Fallback mouse movement if Wintab provided coodinates are untrusted. */ | ||||
| system->getMilliSeconds(), type, window, mask, window->getTabletData()); | if (!mouseUpdated) { | ||||
| DWORD pos = GetMessagePos(); | |||||
| int x = GET_X_LPARAM(pos); | |||||
| int y = GET_Y_LPARAM(pos); | |||||
| /* TODO supply tablet data */ | |||||
Done Inline ActionsI would like to leave this unpopulated for a short time to get feedback from nightly users when coordinate mapping has failed. nicholas_rishel: I would like to leave this unpopulated for a short time to get feedback from nightly users when… | |||||
| system->pushEvent(new GHOST_EventCursor( | |||||
| system->getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, GHOST_TABLET_DATA_NONE)); | |||||
| } | |||||
| } | } | ||||
| void GHOST_SystemWin32::processPointerEvent( | void GHOST_SystemWin32::processPointerEvent( | ||||
| UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) | UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventHandled) | ||||
| { | { | ||||
| /* Pointer events might fire when changing windows for a device which is set to use Wintab, even | /* Pointer events might fire when changing windows for a device which is set to use Wintab, even | ||||
| * when when Wintab is left enabled but set to the bottom of Wintab overlap order. */ | * when when Wintab is left enabled but set to the bottom of Wintab overlap order. */ | ||||
| if (!window->useTabletAPI(GHOST_kTabletNative)) { | if (!window->usingTabletAPI(GHOST_kTabletWinPointer)) { | ||||
| return; | return; | ||||
| } | } | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| std::vector<GHOST_PointerInfoWin32> pointerInfo; | std::vector<GHOST_PointerInfoWin32> pointerInfo; | ||||
| if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) { | if (window->getPointerInfo(pointerInfo, wParam, lParam) != GHOST_kSuccess) { | ||||
| return; | return; | ||||
| } | } | ||||
| if (!pointerInfo[0].isPrimary) { | |||||
| eventHandled = true; | |||||
| return; // For multi-touch displays we ignore these events | |||||
| } | |||||
| switch (type) { | switch (type) { | ||||
| case WM_POINTERENTER: | case WM_POINTERUPDATE: | ||||
| window->m_tabletInRange = true; | /* Coalesced pointer events are reverse chronological order, reorder chronologically. | ||||
| system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, | * Only contiguous move events are coalesced. */ | ||||
| for (GHOST_TUns32 i = pointerInfo.size(); i-- > 0;) { | |||||
| system->pushEvent(new GHOST_EventCursor(pointerInfo[i].time, | |||||
| GHOST_kEventCursorMove, | GHOST_kEventCursorMove, | ||||
| window, | window, | ||||
| pointerInfo[0].pixelLocation.x, | pointerInfo[i].pixelLocation.x, | ||||
| pointerInfo[0].pixelLocation.y, | pointerInfo[i].pixelLocation.y, | ||||
| pointerInfo[0].tabletData)); | pointerInfo[i].tabletData)); | ||||
| } | |||||
| break; | break; | ||||
| case WM_POINTERDOWN: | case WM_POINTERDOWN: | ||||
| /* Move cursor to point of contact because GHOST_EventButton does not include position. */ | /* Move cursor to point of contact because GHOST_EventButton does not include position. */ | ||||
| system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, | system->pushEvent(new GHOST_EventCursor(pointerInfo[0].time, | ||||
| GHOST_kEventCursorMove, | GHOST_kEventCursorMove, | ||||
| window, | window, | ||||
| pointerInfo[0].pixelLocation.x, | pointerInfo[0].pixelLocation.x, | ||||
| pointerInfo[0].pixelLocation.y, | pointerInfo[0].pixelLocation.y, | ||||
| pointerInfo[0].tabletData)); | pointerInfo[0].tabletData)); | ||||
| system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, | system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, | ||||
| GHOST_kEventButtonDown, | GHOST_kEventButtonDown, | ||||
| window, | window, | ||||
| pointerInfo[0].buttonMask, | pointerInfo[0].buttonMask, | ||||
| pointerInfo[0].tabletData)); | pointerInfo[0].tabletData)); | ||||
| window->updateMouseCapture(MousePressed); | window->updateMouseCapture(MousePressed); | ||||
| break; | break; | ||||
| case WM_POINTERUPDATE: | |||||
| /* Coalesced pointer events are reverse chronological order, reorder chronologically. | |||||
| * Only contiguous move events are coalesced. */ | |||||
| for (GHOST_TUns32 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)); | |||||
| } | |||||
| break; | |||||
| case WM_POINTERUP: | case WM_POINTERUP: | ||||
| system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, | system->pushEvent(new GHOST_EventButton(pointerInfo[0].time, | ||||
| GHOST_kEventButtonUp, | GHOST_kEventButtonUp, | ||||
| window, | window, | ||||
| pointerInfo[0].buttonMask, | pointerInfo[0].buttonMask, | ||||
| pointerInfo[0].tabletData)); | pointerInfo[0].tabletData)); | ||||
| window->updateMouseCapture(MouseReleased); | window->updateMouseCapture(MouseReleased); | ||||
| break; | break; | ||||
| case WM_POINTERLEAVE: | |||||
| window->m_tabletInRange = false; | |||||
| break; | |||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| eventHandled = true; | eventHandled = true; | ||||
| system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y); | system->setCursorPosition(pointerInfo[0].pixelLocation.x, pointerInfo[0].pixelLocation.y); | ||||
| } | } | ||||
| GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) | GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) | ||||
| { | { | ||||
| GHOST_TInt32 x_screen, y_screen; | GHOST_TInt32 x_screen, y_screen; | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| if (window->m_tabletInRange) { | if (window->getTabletData().Active != GHOST_kTabletModeNone) { | ||||
| if (window->useTabletAPI(GHOST_kTabletNative)) { | |||||
| /* Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet | /* Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet | ||||
| * input aren't normally generated when using WM_POINTER events, but manually moving the | * input aren't normally generated when using WM_POINTER events, but manually moving the | ||||
| * system cursor as we do in WM_POINTER handling does. */ | * system cursor as we do in WM_POINTER handling does. */ | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | |||||
| system->getCursorPosition(x_screen, y_screen); | system->getCursorPosition(x_screen, y_screen); | ||||
| if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { | if (window->getCursorGrabModeIsWarp()) { | ||||
| GHOST_TInt32 x_new = x_screen; | GHOST_TInt32 x_new = x_screen; | ||||
| GHOST_TInt32 y_new = y_screen; | GHOST_TInt32 y_new = y_screen; | ||||
| GHOST_TInt32 x_accum, y_accum; | GHOST_TInt32 x_accum, y_accum; | ||||
| GHOST_Rect bounds; | GHOST_Rect bounds; | ||||
| /* Fallback to window bounds. */ | /* Fallback to window bounds. */ | ||||
| if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { | if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) { | ||||
| window->getClientBounds(bounds); | window->getClientBounds(bounds); | ||||
| } | } | ||||
| /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. | /* Could also clamp to screen bounds wrap with a window outside the view will fail atm. | ||||
| * Use offset of 8 in case the window is at screen bounds. */ | * Use inset in case the window is at screen bounds. */ | ||||
| bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); | bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); | ||||
| window->getCursorGrabAccum(x_accum, y_accum); | window->getCursorGrabAccum(x_accum, y_accum); | ||||
| if (x_new != x_screen || y_new != y_screen) { | 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 | /* When wrapping we don't need to add an event because the setCursorPosition call will cause | ||||
| * a new event after. */ | * a new event after. */ | ||||
| system->setCursorPosition(x_new, y_new); /* wrap */ | system->setCursorPosition(x_new, y_new); /* wrap */ | ||||
| window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); | window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); | ||||
| } | } | ||||
| else { | else { | ||||
| return new GHOST_EventCursor(system->getMilliSeconds(), | return new GHOST_EventCursor(system->getMilliSeconds(), | ||||
| GHOST_kEventCursorMove, | GHOST_kEventCursorMove, | ||||
| window, | window, | ||||
| x_screen + x_accum, | x_screen + x_accum, | ||||
| y_screen + y_accum, | y_screen + y_accum, | ||||
| window->getTabletData()); | GHOST_TABLET_DATA_NONE); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| return new GHOST_EventCursor(system->getMilliSeconds(), | return new GHOST_EventCursor(system->getMilliSeconds(), | ||||
| GHOST_kEventCursorMove, | GHOST_kEventCursorMove, | ||||
| window, | window, | ||||
| x_screen, | x_screen, | ||||
| y_screen, | y_screen, | ||||
| window->getTabletData()); | GHOST_TABLET_DATA_NONE); | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam) | void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam) | ||||
| { | { | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| ▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw) | ||||
| } | } | ||||
| else { | else { | ||||
| event = NULL; | event = NULL; | ||||
| } | } | ||||
| return event; | return event; | ||||
| } | } | ||||
| GHOST_Event *GHOST_SystemWin32::processWindowSizeEvent(GHOST_WindowWin32 *window) | |||||
| { | |||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | |||||
| GHOST_Event *sizeEvent = new GHOST_Event( | |||||
| system->getMilliSeconds(), GHOST_kEventWindowSize, window); | |||||
| /* We get WM_SIZE before we fully init. Do not dispatch before we are continuously resizing. */ | |||||
| if (window->m_inLiveResize) { | |||||
| system->pushEvent(sizeEvent); | |||||
| system->dispatchEvents(); | |||||
| return NULL; | |||||
| } | |||||
| else { | |||||
| return sizeEvent; | |||||
| } | |||||
| } | |||||
| GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, | GHOST_Event *GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, | ||||
| GHOST_WindowWin32 *window) | GHOST_WindowWin32 *window) | ||||
| { | { | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| if (type == GHOST_kEventWindowActivate) { | if (type == GHOST_kEventWindowActivate) { | ||||
| system->getWindowManager()->setActiveWindow(window); | system->getWindowManager()->setActiveWindow(window); | ||||
| window->bringTabletContextToFront(); | |||||
| } | } | ||||
| return new GHOST_Event(system->getMilliSeconds(), type, window); | return new GHOST_Event(system->getMilliSeconds(), type, window); | ||||
| } | } | ||||
| #ifdef WITH_INPUT_IME | #ifdef WITH_INPUT_IME | ||||
| GHOST_Event *GHOST_SystemWin32::processImeEvent(GHOST_TEventType type, | GHOST_Event *GHOST_SystemWin32::processImeEvent(GHOST_TEventType type, | ||||
| GHOST_WindowWin32 *window, | GHOST_WindowWin32 *window, | ||||
| Show All 11 Lines | GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType, | ||||
| int mouseY, | int mouseY, | ||||
| void *data) | void *data) | ||||
| { | { | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| return system->pushEvent(new GHOST_EventDragnDrop( | return system->pushEvent(new GHOST_EventDragnDrop( | ||||
| system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data)); | system->getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, data)); | ||||
| } | } | ||||
| void GHOST_SystemWin32::setTabletAPI(GHOST_TTabletAPI api) | |||||
| { | |||||
| GHOST_System::setTabletAPI(api); | |||||
| /* If API is set to WinPointer (Windows Ink), unload Wintab so that trouble drivers don't disable | |||||
| * Windows Ink. Load Wintab when API is Automatic because decision logic relies on knowing | |||||
| * whether a Wintab device is present. */ | |||||
| const bool loadWintab = GHOST_kTabletWinPointer != api; | |||||
| GHOST_WindowManager *wm = getWindowManager(); | |||||
| for (GHOST_IWindow *win : wm->getWindows()) { | |||||
| GHOST_WindowWin32 *windowWin32 = (GHOST_WindowWin32 *)win; | |||||
| if (loadWintab) { | |||||
| windowWin32->loadWintab(GHOST_kWindowStateMinimized != windowWin32->getState()); | |||||
| if (windowWin32->usingTabletAPI(GHOST_kTabletWintab)) { | |||||
| windowWin32->resetPointerPenInfo(); | |||||
| } | |||||
| } | |||||
| else { | |||||
| windowWin32->closeWintab(); | |||||
| } | |||||
| } | |||||
| } | |||||
| void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax) | void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO *minmax) | ||||
| { | { | ||||
| minmax->ptMinTrackSize.x = 320; | minmax->ptMinTrackSize.x = 320; | ||||
| minmax->ptMinTrackSize.y = 240; | minmax->ptMinTrackSize.y = 240; | ||||
| } | } | ||||
| #ifdef WITH_INPUT_NDOF | #ifdef WITH_INPUT_NDOF | ||||
| bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw) | bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw) | ||||
| ▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | #endif /* WITH_INPUT_IME */ | ||||
| * Note that the four low-order bits of the wParam parameter are used internally by the | * Note that the four low-order bits of the wParam parameter are used internally by the | ||||
| * OS. To obtain the correct result when testing the value of wParam, an application | * OS. To obtain the correct result when testing the value of wParam, an application | ||||
| * must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator. | * must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator. | ||||
| */ | */ | ||||
| switch (wParam & 0xFFF0) { | switch (wParam & 0xFFF0) { | ||||
| case SC_KEYMENU: | case SC_KEYMENU: | ||||
| eventHandled = true; | eventHandled = true; | ||||
| break; | break; | ||||
| case SC_RESTORE: | case SC_RESTORE: { | ||||
| ::ShowWindow(hwnd, SW_RESTORE); | ::ShowWindow(hwnd, SW_RESTORE); | ||||
| window->setState(window->getState()); | window->setState(window->getState()); | ||||
| GHOST_Wintab *wt = window->getWintab(); | |||||
Done Inline ActionsDon't do assignments in conditionals like this. It's not generally something we do in Blender code, better to follow the (implicit) convention. Also don't use auto unless it's a specifically long type name like an STL iterator. brecht: Don't do assignments in conditionals like this. It's not generally something we do in Blender… | |||||
Done Inline ActionsWould auto be appropriate when assigning from constructors and/or casts? For instance auto info = (GHOST_WIN32_WTInfo)::GetProcAddress(handle.get(), "WTInfoA");
if (!info) {
return nullptr;
}
auto open = (GHOST_WIN32_WTOpen)::GetProcAddress(handle.get(), "WTOpenA");
if (!open) {
return nullptr;
}and auto pointerPenInfo = std::vector<POINTER_PEN_INFO>(outCount); nicholas_rishel: Would `auto` be appropriate when assigning from constructors and/or casts?
For instance
```… | |||||
| if (wt) { | |||||
| wt->enable(); | |||||
| } | |||||
| eventHandled = true; | eventHandled = true; | ||||
| break; | break; | ||||
| } | } | ||||
| case SC_MAXIMIZE: { | |||||
| GHOST_Wintab *wt = window->getWintab(); | |||||
| if (wt) { | |||||
| wt->enable(); | |||||
| } | |||||
| /* Don't report event as handled so that default handling occurs. */ | |||||
| break; | |||||
| } | |||||
| case SC_MINIMIZE: { | |||||
| GHOST_Wintab *wt = window->getWintab(); | |||||
| if (wt) { | |||||
| wt->disable(); | |||||
| } | |||||
| /* Don't report event as handled so that default handling occurs. */ | |||||
| break; | |||||
| } | |||||
| } | |||||
| break; | break; | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| // Wintab events, processed | // Wintab events, processed | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| case WT_PACKET: | |||||
| window->processWin32TabletEvent(wParam, lParam); | |||||
| break; | |||||
| case WT_CSRCHANGE: | case WT_CSRCHANGE: | ||||
| case WT_PROXIMITY: | if (GHOST_Wintab *wt = window->getWintab()) { | ||||
| window->processWin32TabletInitEvent(); | wt->updateCursorInfo(); | ||||
| } | |||||
| eventHandled = true; | |||||
| break; | |||||
| case WT_PROXIMITY: { | |||||
| if (GHOST_Wintab *wt = window->getWintab()) { | |||||
| bool inRange = LOWORD(lParam); | |||||
| if (inRange) { | |||||
| /* Some devices don't emit WT_CSRCHANGE events, so update cursor info here. */ | |||||
| wt->updateCursorInfo(); | |||||
| } | |||||
| else { | |||||
| wt->leaveRange(); | |||||
| } | |||||
| } | |||||
| eventHandled = true; | |||||
| break; | |||||
| } | |||||
| case WT_INFOCHANGE: | |||||
| if (GHOST_Wintab *wt = window->getWintab()) { | |||||
| wt->processInfoChange(lParam); | |||||
| if (window->usingTabletAPI(GHOST_kTabletWintab)) { | |||||
| window->resetPointerPenInfo(); | |||||
| } | |||||
| } | |||||
| eventHandled = true; | |||||
| break; | |||||
| case WT_PACKET: | |||||
| processWintabEvent(window); | |||||
| eventHandled = true; | |||||
| break; | break; | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| // Pointer events, processed | // Pointer events, processed | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| case WM_POINTERENTER: | |||||
| case WM_POINTERDOWN: | |||||
| case WM_POINTERUPDATE: | case WM_POINTERUPDATE: | ||||
| case WM_POINTERDOWN: | |||||
| case WM_POINTERUP: | case WM_POINTERUP: | ||||
| case WM_POINTERLEAVE: | |||||
| processPointerEvent(msg, window, wParam, lParam, eventHandled); | processPointerEvent(msg, window, wParam, lParam, eventHandled); | ||||
| break; | break; | ||||
| case WM_POINTERLEAVE: | |||||
| window->resetPointerPenInfo(); | |||||
| eventHandled = true; | |||||
| break; | |||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| // Mouse events, processed | // Mouse events, processed | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| case WM_LBUTTONDOWN: | case WM_LBUTTONDOWN: | ||||
| event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); | event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskLeft); | ||||
| break; | break; | ||||
| case WM_MBUTTONDOWN: | case WM_MBUTTONDOWN: | ||||
| event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); | event = processButtonEvent(GHOST_kEventButtonDown, window, GHOST_kButtonMaskMiddle); | ||||
| Show All 22 Lines | #endif /* WITH_INPUT_IME */ | ||||
| if ((short)HIWORD(wParam) == XBUTTON1) { | if ((short)HIWORD(wParam) == XBUTTON1) { | ||||
| event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); | event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton4); | ||||
| } | } | ||||
| else if ((short)HIWORD(wParam) == XBUTTON2) { | else if ((short)HIWORD(wParam) == XBUTTON2) { | ||||
| event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); | event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); | ||||
| } | } | ||||
| break; | break; | ||||
| case WM_MOUSEMOVE: | case WM_MOUSEMOVE: | ||||
| if (!window->m_mousePresent) { | |||||
| TRACKMOUSEEVENT tme = {sizeof(tme)}; | |||||
| tme.dwFlags = TME_LEAVE; | |||||
| tme.hwndTrack = hwnd; | |||||
| TrackMouseEvent(&tme); | |||||
| window->m_mousePresent = true; | |||||
| if (GHOST_Wintab *wt = window->getWintab()) { | |||||
| wt->gainFocus(); | |||||
| } | |||||
| } | |||||
| event = processCursorEvent(window); | event = processCursorEvent(window); | ||||
| break; | break; | ||||
| case WM_MOUSEWHEEL: { | case WM_MOUSEWHEEL: { | ||||
| /* The WM_MOUSEWHEEL message is sent to the focus window | /* The WM_MOUSEWHEEL message is sent to the focus window | ||||
| * when the mouse wheel is rotated. The DefWindowProc | * when the mouse wheel is rotated. The DefWindowProc | ||||
| * function propagates the message to the window's parent. | * function propagates the message to the window's parent. | ||||
| * There should be no internal forwarding of the message, | * There should be no internal forwarding of the message, | ||||
| * since DefWindowProc propagates it up the parent chain | * since DefWindowProc propagates it up the parent chain | ||||
| * until it finds a window that processes it. | * until it finds a window that processes it. | ||||
| Show All 18 Lines | #endif | ||||
| // Bypass call to DefWindowProc | // Bypass call to DefWindowProc | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| else { | else { | ||||
| // Outside of client area show standard cursor | // Outside of client area show standard cursor | ||||
| window->loadCursor(true, GHOST_kStandardCursorDefault); | window->loadCursor(true, GHOST_kStandardCursorDefault); | ||||
| } | } | ||||
| break; | break; | ||||
| case WM_MOUSELEAVE: | |||||
| window->m_mousePresent = false; | |||||
| if (window->getTabletData().Active == GHOST_kTabletModeNone) { | |||||
| processCursorEvent(window); | |||||
| } | |||||
| if (GHOST_Wintab *wt = window->getWintab()) { | |||||
| wt->loseFocus(); | |||||
| } | |||||
| break; | |||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| // Mouse events, ignored | // Mouse events, ignored | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| case WM_NCMOUSEMOVE: | case WM_NCMOUSEMOVE: | ||||
| /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved | /* The WM_NCMOUSEMOVE message is posted to a window when the cursor is moved | ||||
| * within the non-client area of the window. This message is posted to the window that | * within the non-client area of the window. This message is posted to the window that | ||||
| * contains the cursor. If a window has captured the mouse, this message is not posted. | * contains the cursor. If a window has captured the mouse, this message is not posted. | ||||
| */ | */ | ||||
| Show All 31 Lines | #endif | ||||
| system->m_keycode_last_repeat_key = 0; | system->m_keycode_last_repeat_key = 0; | ||||
| event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : | event = processWindowEvent(LOWORD(wParam) ? GHOST_kEventWindowActivate : | ||||
| GHOST_kEventWindowDeactivate, | GHOST_kEventWindowDeactivate, | ||||
| window); | window); | ||||
| /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL | /* WARNING: Let DefWindowProc handle WM_ACTIVATE, otherwise WM_MOUSEWHEEL | ||||
| * will not be dispatched to OUR active window if we minimize one of OUR windows. */ | * 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(); | window->lostMouseCapture(); | ||||
| window->processWin32TabletActivateEvent(GET_WM_ACTIVATE_STATE(wParam, lParam)); | |||||
| lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); | lResult = ::DefWindowProc(hwnd, msg, wParam, lParam); | ||||
| break; | break; | ||||
| } | } | ||||
| case WM_ENTERSIZEMOVE: | case WM_ENTERSIZEMOVE: | ||||
| /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving | /* The WM_ENTERSIZEMOVE message is sent one time to a window after it enters the moving | ||||
| * or sizing modal loop. The window enters the moving or sizing modal loop when the user | * or sizing modal loop. The window enters the moving or sizing modal loop when the user | ||||
| * clicks the window's title bar or sizing border, or when the window passes the | * clicks the window's title bar or sizing border, or when the window passes the | ||||
| * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the | * WM_SYSCOMMAND message to the DefWindowProc function and the wParam parameter of the | ||||
| Show All 25 Lines | #endif | ||||
| * position of the window is about to change. An application can use | * position of the window is about to change. An application can use | ||||
| * this message to override the window's default maximized size and | * this message to override the window's default maximized size and | ||||
| * position, or its default minimum or maximum tracking size. | * position, or its default minimum or maximum tracking size. | ||||
| */ | */ | ||||
| processMinMaxInfo((MINMAXINFO *)lParam); | processMinMaxInfo((MINMAXINFO *)lParam); | ||||
| /* Let DefWindowProc handle it. */ | /* Let DefWindowProc handle it. */ | ||||
| break; | break; | ||||
| case WM_SIZING: | case WM_SIZING: | ||||
| event = processWindowSizeEvent(window); | |||||
| break; | |||||
| case WM_SIZE: | case WM_SIZE: | ||||
| /* The WM_SIZE message is sent to a window after its size has changed. | /* The WM_SIZE message is sent to a window after its size has changed. | ||||
| * The WM_SIZE and WM_MOVE messages are not sent if an application handles the | * The WM_SIZE and WM_MOVE messages are not sent if an application handles the | ||||
| * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient | * WM_WINDOWPOSCHANGED message without calling DefWindowProc. It is more efficient | ||||
| * to perform any move or size change processing during the WM_WINDOWPOSCHANGED | * to perform any move or size change processing during the WM_WINDOWPOSCHANGED | ||||
| * message without calling DefWindowProc. | * message without calling DefWindowProc. | ||||
| */ | */ | ||||
| /* we get first WM_SIZE before we fully init. | event = processWindowSizeEvent(window); | ||||
| * So, do not dispatch before we continuously resizing. */ | |||||
| if (window->m_inLiveResize) { | |||||
| system->pushEvent(processWindowEvent(GHOST_kEventWindowSize, window)); | |||||
| system->dispatchEvents(); | |||||
| } | |||||
| else { | |||||
| event = processWindowEvent(GHOST_kEventWindowSize, window); | |||||
| } | |||||
| break; | break; | ||||
| case WM_CAPTURECHANGED: | case WM_CAPTURECHANGED: | ||||
| window->lostMouseCapture(); | window->lostMouseCapture(); | ||||
| break; | break; | ||||
| case WM_MOVING: | case WM_MOVING: | ||||
| /* The WM_MOVING message is sent to a window that the user is moving. By processing | /* The WM_MOVING message is sent to a window that the user is moving. By processing | ||||
| * this message, an application can monitor the size and position of the drag rectangle | * this message, an application can monitor the size and position of the drag rectangle | ||||
| * and, if needed, change its size or position. | * and, if needed, change its size or position. | ||||
| Show All 34 Lines | #endif | ||||
| NULL, | NULL, | ||||
| suggestedWindowRect->left, | suggestedWindowRect->left, | ||||
| suggestedWindowRect->top, | suggestedWindowRect->top, | ||||
| suggestedWindowRect->right - suggestedWindowRect->left, | suggestedWindowRect->right - suggestedWindowRect->left, | ||||
| suggestedWindowRect->bottom - suggestedWindowRect->top, | suggestedWindowRect->bottom - suggestedWindowRect->top, | ||||
| SWP_NOZORDER | SWP_NOACTIVATE); | SWP_NOZORDER | SWP_NOACTIVATE); | ||||
| } | } | ||||
| break; | break; | ||||
| case WM_DISPLAYCHANGE: | |||||
| for (GHOST_IWindow *iter_win : system->getWindowManager()->getWindows()) { | |||||
| GHOST_WindowWin32 *iter_win32win = (GHOST_WindowWin32 *)iter_win; | |||||
| if (GHOST_Wintab *wt = iter_win32win->getWintab()) { | |||||
| wt->remapCoordinates(); | |||||
| } | |||||
| } | |||||
| break; | |||||
| case WM_KILLFOCUS: | |||||
| /* The WM_KILLFOCUS message is sent to a window immediately before it loses the keyboard | |||||
| * focus. We want to prevent this if a window is still active and it loses focus to | |||||
| * nowhere. */ | |||||
| if (!wParam && hwnd == ::GetActiveWindow()) { | |||||
| ::SetFocus(hwnd); | |||||
| } | |||||
| break; | |||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| // Window events, ignored | // Window events, ignored | ||||
| //////////////////////////////////////////////////////////////////////// | //////////////////////////////////////////////////////////////////////// | ||||
| case WM_WINDOWPOSCHANGED: | case WM_WINDOWPOSCHANGED: | ||||
| /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place | /* The WM_WINDOWPOSCHANGED message is sent to a window whose size, position, or place | ||||
| * in the Z order has changed as a result of a call to the SetWindowPos function or | * in the Z order has changed as a result of a call to the SetWindowPos function or | ||||
| * another window-management function. | * another window-management function. | ||||
| * The WM_SIZE and WM_MOVE messages are not sent if an application handles the | * The WM_SIZE and WM_MOVE messages are not sent if an application handles the | ||||
| Show All 20 Lines | #endif | ||||
| * be assumed that all child windows still exist. */ | * be assumed that all child windows still exist. */ | ||||
| case WM_NCDESTROY: | case WM_NCDESTROY: | ||||
| /* The WM_NCDESTROY message informs a window that its non-client area is being | /* The WM_NCDESTROY message informs a window that its non-client area is being | ||||
| * destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window | * destroyed. The DestroyWindow function sends the WM_NCDESTROY message to the window | ||||
| * following the WM_DESTROY message. WM_DESTROY is used to free the allocated memory | * following the WM_DESTROY message. WM_DESTROY is used to free the allocated memory | ||||
| * object associated with the window. | * object associated with the window. | ||||
| */ | */ | ||||
| break; | break; | ||||
| case WM_KILLFOCUS: | |||||
| /* The WM_KILLFOCUS message is sent to a window immediately before it loses the | |||||
| * keyboard focus. We want to prevent this if a window is still active and it loses | |||||
| * focus to nowhere. */ | |||||
| if (!wParam && hwnd == ::GetActiveWindow()) | |||||
| ::SetFocus(hwnd); | |||||
| case WM_SHOWWINDOW: | case WM_SHOWWINDOW: | ||||
| /* The WM_SHOWWINDOW message is sent to a window when the window is | /* The WM_SHOWWINDOW message is sent to a window when the window is | ||||
| * about to be hidden or shown. */ | * about to be hidden or shown. */ | ||||
| case WM_WINDOWPOSCHANGING: | case WM_WINDOWPOSCHANGING: | ||||
| /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in | /* The WM_WINDOWPOSCHANGING message is sent to a window whose size, position, or place in | ||||
| * the Z order is about to change as a result of a call to the SetWindowPos function or | * the Z order is about to change as a result of a call to the SetWindowPos function or | ||||
| * another window-management function. | * another window-management function. | ||||
| */ | */ | ||||
| ▲ Show 20 Lines • Show All 294 Lines • Show Last 20 Lines | |||||
I guess this event is often redundant, and already handed through a mouse move event?
Do we know it gets filtered out in the window manager, or does it lead to double event handling?