Changeset View
Changeset View
Standalone View
Standalone View
intern/ghost/intern/GHOST_SystemWin32.cpp
| Show First 20 Lines • Show All 219 Lines • ▼ Show 20 Lines | GHOST_SystemWin32::GHOST_SystemWin32() | ||||
| // generates VK_OEM_8 for their exclamation key (key left of right shift) | // generates VK_OEM_8 for their exclamation key (key left of right shift) | ||||
| this->handleKeyboardChange(); | this->handleKeyboardChange(); | ||||
| // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32. | // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32. | ||||
| OleInitialize(0); | OleInitialize(0); | ||||
| #ifdef WITH_INPUT_NDOF | #ifdef WITH_INPUT_NDOF | ||||
| m_ndofManager = new GHOST_NDOFManagerWin32(*this); | m_ndofManager = new GHOST_NDOFManagerWin32(*this); | ||||
| #endif | #endif | ||||
| getCursorPosition(m_mousePosX, m_mousePosY); | |||||
| m_mouseTimestamp = ::GetTickCount(); | |||||
| } | } | ||||
| GHOST_SystemWin32::~GHOST_SystemWin32() | GHOST_SystemWin32::~GHOST_SystemWin32() | ||||
| { | { | ||||
| // Shutdown COM | // Shutdown COM | ||||
| OleUninitialize(); | OleUninitialize(); | ||||
| toggleConsole(1); | toggleConsole(1); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 697 Lines • ▼ Show 20 Lines | GHOST_EventButton *GHOST_SystemWin32::processButtonEvent(GHOST_TEventType type, | ||||
| GHOST_TButtonMask mask) | GHOST_TButtonMask mask) | ||||
| { | { | ||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| GHOST_TabletData td = GHOST_TABLET_DATA_NONE; | GHOST_TabletData td = GHOST_TABLET_DATA_NONE; | ||||
| if (window->m_tabletInRange) { | if (window->m_tabletInRange) { | ||||
| td = window->getTabletData(); | td = window->getTabletData(); | ||||
| /* Check if tablet cursor position is in sync with Win32 cursor position, if not then move | |||||
| * cursor to position where button event occurred. */ | |||||
| DWORD msgPos = ::GetMessagePos(); | |||||
| int msgPosX = GET_X_LPARAM(msgPos); | |||||
| int msgPosY = GET_Y_LPARAM(msgPos); | |||||
| if (msgPosX != system->m_mousePosX || msgPosY != system->m_mousePosY) { | |||||
| system->pushEvent(new GHOST_EventCursor( | |||||
| ::GetMessageTime(), GHOST_kEventCursorMove, window, msgPosX, msgPosY, td)); | |||||
| } | |||||
| } | } | ||||
| return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); | return new GHOST_EventButton(system->getMilliSeconds(), type, window, mask, td); | ||||
| } | } | ||||
| 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) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | switch (type) { | ||||
| 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); | ||||
| } | } | ||||
| void GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) | GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *window) | ||||
| { | { | ||||
| if (window->m_tabletInRange && window->useTabletAPI(GHOST_kTabletNative)) { | GHOST_TInt32 x_screen, y_screen; | ||||
| /* Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet | |||||
| * input aren't normally generated when using WM_POINTER events, but manually moving the | |||||
| * system cursor as we do in WM_POINTER handling does. */ | |||||
| return; | |||||
| } | |||||
| GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); | ||||
| GHOST_TabletData td = window->getTabletData(); | |||||
| DWORD msgPos = ::GetMessagePos(); | |||||
| LONG msgTime = ::GetMessageTime(); | |||||
| /* GetMessagePointsEx processes points as 16 bit integers and can fail or return erroneous values | |||||
| * if negative input is not truncated. */ | |||||
| int msgPosX = GET_X_LPARAM(msgPos) & 0x0000FFFF; | |||||
| int msgPosY = GET_Y_LPARAM(msgPos) & 0x0000FFFF; | |||||
| const int maxPoints = 64; | |||||
| MOUSEMOVEPOINT currentPoint = {msgPosX, msgPosY, (DWORD)msgTime, 0}; | |||||
| MOUSEMOVEPOINT points[maxPoints] = {0}; | |||||
| /* GetMouseMovePointsEx returns the number of points returned that are less than or equal to the | |||||
| * requested point. If the requested point is the most recent, this returns up to 64 requested | |||||
| * points. */ | |||||
| int numPoints = ::GetMouseMovePointsEx( | |||||
| sizeof(MOUSEMOVEPOINT), ¤tPoint, points, maxPoints, GMMP_USE_DISPLAY_POINTS); | |||||
| if (numPoints == -1) { | |||||
| /* Points at edge of screen are often not in the queue, use the message's point instead. */ | |||||
| numPoints = 1; | |||||
| points[0] = currentPoint; | |||||
| } | |||||
| GHOST_TInt32 x_accum = 0, y_accum = 0; | if (window->m_tabletInRange) { | ||||
| window->getCursorGrabAccum(x_accum, y_accum); | if (window->useTabletAPI(GHOST_kTabletNative)) { | ||||
| // Tablet input handled in WM_POINTER* events. WM_MOUSEMOVE events in response to tablet | |||||
| /* Points are in reverse chronological order. Find least recent, unprocessed mouse move. */ | // input aren't normally generated when using WM_POINTER events, but manually moving the | ||||
| int i; | // system cursor as we do in WM_POINTER handling does. | ||||
| for (i = 0; i < numPoints; i++) { | return NULL; | ||||
| if (points[i].time < system->m_mouseTimestamp) { | |||||
| break; | |||||
| } | |||||
| /* GetMouseMovePointsEx returns 16 bit number as 32 bit. If negative, we need to sign extend. | |||||
| */ | |||||
| points[i].x = points[i].x > 32767 ? points[i].x | 0xFFFF0000 : points[i].x; | |||||
| points[i].y = points[i].y > 32767 ? points[i].y | 0xFFFF0000 : points[i].y; | |||||
| if (points[i].time == system->m_mouseTimestamp && points[i].x == system->m_mousePosX && | |||||
| points[i].y == system->m_mousePosY) { | |||||
| break; | |||||
| } | |||||
| } | } | ||||
| while (--i >= 0) { | |||||
| system->pushEvent(new GHOST_EventCursor(system->getMilliSeconds(), | |||||
| GHOST_kEventCursorMove, | |||||
| window, | |||||
| points[i].x + x_accum, | |||||
| points[i].y + y_accum, | |||||
| td)); | |||||
| } | } | ||||
| DWORD lastTimestamp = points[0].time; | system->getCursorPosition(x_screen, y_screen); | ||||
| /* Check if we need to wrap the cursor. */ | |||||
| if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { | if (window->getCursorGrabModeIsWarp() && !window->m_tabletInRange) { | ||||
| /* Wrap based on current cursor position in case Win32 mouse move queue is out of order due to | GHOST_TInt32 x_new = x_screen; | ||||
| * prior wrap. */ | GHOST_TInt32 y_new = y_screen; | ||||
| POINT point; | GHOST_TInt32 x_accum, y_accum; | ||||
| ::GetCursorPos(&point); | |||||
| GHOST_TInt32 x_current = point.x; | |||||
| GHOST_TInt32 y_current = point.y; | |||||
| GHOST_TInt32 x_wrap = point.x; | |||||
| GHOST_TInt32 y_wrap = point.y; | |||||
| 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 offset of 8 in case the window is at screen bounds. */ | ||||
| bounds.wrapPoint(x_wrap, y_wrap, 2, window->getCursorGrabAxis()); | bounds.wrapPoint(x_new, y_new, 2, window->getCursorGrabAxis()); | ||||
| if (x_wrap != x_current || y_wrap != y_current) { | window->getCursorGrabAccum(x_accum, y_accum); | ||||
| system->setCursorPosition(x_wrap, y_wrap); | if (x_new != x_screen || y_new != y_screen) { | ||||
| window->setCursorGrabAccum(x_accum + (x_current - x_wrap), y_accum + (y_current - y_wrap)); | /* when wrapping we don't need to add an event because the | ||||
| * setCursorPosition call will cause a new event after */ | |||||
| /* First message after SendInput wrap is invalid for unknown reasons, skip events until one | system->setCursorPosition(x_new, y_new); /* wrap */ | ||||
| * tick after SendInput event time. */ | window->setCursorGrabAccum(x_accum + (x_screen - x_new), y_accum + (y_screen - y_new)); | ||||
| lastTimestamp = ::GetTickCount() + 1; | |||||
| } | } | ||||
| else { | |||||
| return new GHOST_EventCursor(system->getMilliSeconds(), | |||||
| GHOST_kEventCursorMove, | |||||
| window, | |||||
| x_screen + x_accum, | |||||
| y_screen + y_accum, | |||||
| window->getTabletData()); | |||||
| } | } | ||||
| system->m_mousePosX = points[0].x; | |||||
| system->m_mousePosY = points[0].y; | |||||
| /* Use latest time, checking for overflow. */ | |||||
| if (lastTimestamp > system->m_mouseTimestamp || ::GetTickCount() < system->m_mouseTimestamp) { | |||||
| system->m_mouseTimestamp = lastTimestamp; | |||||
| } | } | ||||
| else { | |||||
| return new GHOST_EventCursor(system->getMilliSeconds(), | |||||
| GHOST_kEventCursorMove, | |||||
| window, | |||||
| x_screen, | |||||
| y_screen, | |||||
| window->getTabletData()); | |||||
| } | |||||
| 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(); | ||||
| int acc = system->m_wheelDeltaAccum; | int acc = system->m_wheelDeltaAccum; | ||||
| int delta = GET_WHEEL_DELTA_WPARAM(wParam); | int delta = GET_WHEEL_DELTA_WPARAM(wParam); | ||||
| ▲ Show 20 Lines • Show All 434 Lines • ▼ Show 20 Lines | #endif /* WITH_INPUT_IME */ | ||||
| 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) { | ||||
| window->updateMouseCapture(MouseReleased); | window->updateMouseCapture(MouseReleased); | ||||
| event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); | event = processButtonEvent(GHOST_kEventButtonUp, window, GHOST_kButtonMaskButton5); | ||||
| } | } | ||||
| break; | break; | ||||
| case WM_MOUSEMOVE: | case WM_MOUSEMOVE: | ||||
| processCursorEvent(window); | event = processCursorEvent(window); | ||||
| eventHandled = true; | |||||
| 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 20 Lines • Show All 531 Lines • Show Last 20 Lines | |||||