Changeset 30408 in vbox for trunk/src/VBox
- Timestamp:
- Jun 24, 2010 3:41:27 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 63034
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 13 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r30407 r30408 327 327 src/runtime/UIActionsPool.h \ 328 328 src/runtime/UIIndicatorsPool.h \ 329 src/runtime/UIMouseHandler.h \ 329 330 src/runtime/UIMachineLogic.h \ 330 331 src/runtime/UIMachineView.h \ … … 460 461 src/runtime/UIActionsPool.cpp \ 461 462 src/runtime/UIIndicatorsPool.cpp \ 463 src/runtime/UIMouseHandler.cpp \ 462 464 src/runtime/UIFrameBuffer.cpp \ 463 465 src/runtime/UIFrameBufferQGL.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp
r30330 r30408 24 24 #include "UIDownloaderAdditions.h" 25 25 #include "UIIconPool.h" 26 #include "UIMouseHandler.h" 26 27 #include "UIMachineLogic.h" 27 28 #include "UIMachineLogicFullscreen.h" … … 337 338 , m_pActionsPool(pActionsPool) 338 339 , m_visualStateType(visualStateType) 340 , m_pMouseHandler(0) 339 341 , m_pRunningActions(0) 340 342 , m_pRunningOrPausedActions(0) … … 370 372 { 371 373 m_machineWindowsList << pMachineWindow; 374 } 375 376 void UIMachineLogic::setMouseHandler(UIMouseHandler *pMouseHandler) 377 { 378 m_pMouseHandler = pMouseHandler; 372 379 } 373 380 … … 904 911 905 912 /* Disable/Enable mouse-integration for all view(s): */ 906 foreach(UIMachineWindow *pMachineWindow, machineWindows()) 907 pMachineWindow->machineView()->setMouseIntegrationEnabled(!fOff); 913 m_pMouseHandler->setMouseIntegrationEnabled(!fOff); 908 914 } 909 915 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h
r30330 r30408 39 39 class UISession; 40 40 class UIActionsPool; 41 class UIMouseHandler; 41 42 class UIMachineWindow; 42 43 class UIMachineView; … … 68 69 UIVisualStateType visualStateType() const { return m_visualStateType; } 69 70 const QList<UIMachineWindow*>& machineWindows() const { return m_machineWindowsList; } 71 UIMouseHandler* mouseHandler() const { return m_pMouseHandler; } 70 72 UIMachineWindow* mainMachineWindow() const; 71 73 UIMachineWindow* defaultMachineWindow() const; … … 100 102 101 103 /* Protected members: */ 104 void setMouseHandler(UIMouseHandler *pMouseHandler); 102 105 void addMachineWindow(UIMachineWindow *pMachineWindow); 103 106 void retranslateUi(); … … 192 195 UIActionsPool *m_pActionsPool; 193 196 UIVisualStateType m_visualStateType; 197 UIMouseHandler *m_pMouseHandler; 194 198 QList<UIMachineWindow*> m_machineWindowsList; 195 199 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
r30407 r30408 36 36 #include "UISession.h" 37 37 #include "UIActionsPool.h" 38 #include "UIMouseHandler.h" 38 39 #include "UIMachineLogic.h" 39 40 #include "UIMachineWindow.h" … … 157 158 } 158 159 159 int UIMachineView::mouseState() const160 {161 return (uisession()->isMouseCaptured() ? UIMouseStateType_MouseCaptured : 0) |162 (uisession()->isMouseSupportsAbsolute() ? UIMouseStateType_MouseAbsolute : 0) |163 (uisession()->isMouseIntegrated() ? 0 : UIMouseStateType_MouseAbsoluteDisabled);164 }165 166 void UIMachineView::setMouseIntegrationEnabled(bool fEnabled)167 {168 /* Do not change anything if its already so: */169 if (uisession()->isMouseIntegrated() == fEnabled)170 return;171 172 /* Store new mouse 'integrated' state value: */173 uisession()->setMouseIntegrated(fEnabled);174 175 /* We should capture/release mouse depending on mouse 'integrated' state value: */176 captureMouse(!uisession()->isMouseIntegrated(), false /* emit signal? */);177 178 /* Update mouse cursor shape: */179 updateMouseCursorShape();180 181 /* If mouse is integrated and supports absolute pointing182 * we should switch guest mouse to the absolute mode: */183 if (uisession()->isMouseIntegrated() && uisession()->isMouseSupportsAbsolute())184 {185 CMouse mouse = session().GetConsole().GetMouse();186 mouse.PutMouseEventAbsolute(-1, -1, 0, 0, 0);187 }188 189 /* Notify all listeners: */190 emitMouseStateChanged();191 }192 193 160 UIMachineView::UIMachineView( UIMachineWindow *pMachineWindow 194 161 #ifdef VBOX_WITH_VIDEOHWACCEL … … 205 172 , m_previousState(KMachineState_Null) 206 173 , m_desktopGeometryType(DesktopGeo_Invalid) 207 , m_iLastMouseWheelDelta(0)208 174 , m_bIsKeyboardCaptured(false) 209 175 , m_bIsHostkeyPressed(false) … … 215 181 , m_fAccelerate2DVideo(bAccelerate2DVideo) 216 182 #endif /* VBOX_WITH_VIDEOHWACCEL */ 217 #ifdef Q_WS_WIN218 , m_fItsMeWhoCapturedMouse(false)219 #endif220 183 #ifdef Q_WS_MAC 221 184 , m_darwinKeyModifiers(0) … … 385 348 machine.SetExtraData(strKey, strValue); 386 349 } 387 388 void UIMachineView::updateMouseCursorShape()389 {390 /* First of all, we should check if the host pointer should be visible.391 * We should hide host pointer in case of:392 * 1. mouse is 'captured' or393 * 2. mouse is 'not captured', 'integrated', 'absolute', host pointer is hidden by the guest. */394 if (uisession()->isMouseCaptured() ||395 (uisession()->isMouseIntegrated() &&396 uisession()->isMouseSupportsAbsolute() &&397 uisession()->isHidingHostPointer()))398 {399 viewport()->setCursor(Qt::BlankCursor);400 }401 402 else403 404 /* Otherwise we should show host pointer with guest shape assigned to it if:405 * mouse is 'integrated', 'absolute', valid pointer shape is present. */406 if (uisession()->isMouseIntegrated() &&407 uisession()->isMouseSupportsAbsolute() &&408 uisession()->isValidPointerShapePresent())409 {410 viewport()->setCursor(uisession()->cursor());411 }412 413 else414 415 /* There could be other states covering such situations as:416 * 1. mouse is 'not captured', 'integrated', 'not absolute' or417 * 2. mouse is 'not captured', 'not integrated', 'absolute'.418 * We have nothing to do with that except just unset the cursor. */419 viewport()->unsetCursor();420 }421 422 #ifdef Q_WS_WIN423 /* This method is actually required only because under win-host424 * we do not really grab the mouse in case of capturing it.425 * I have to check if its really need, may be just grabMouse() will be enought: */426 void UIMachineView::updateMouseCursorClipping()427 {428 if (m_fItsMeWhoCapturedMouse)429 {430 QRect r = viewport()->rect();431 r.moveTopLeft(viewport()->mapToGlobal(QPoint(0, 0)));432 RECT rect = { r.left(), r.top(), r.right() + 1, r.bottom() + 1 };433 ::ClipCursor(&rect);434 }435 }436 #endif437 350 438 351 void UIMachineView::updateSliders() … … 643 556 NOREF(ok); 644 557 #endif 558 559 /* Register mouse-handler: */ 560 machineLogic()->mouseHandler()->addMachineView(screenId(), this); 645 561 } 646 562 … … 662 578 /* Machine state-change updater: */ 663 579 connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged())); 664 665 /* Mouse pointer shape state-change updater: */666 connect(uisession(), SIGNAL(sigMousePointerShapeChange()), this, SLOT(sltMousePointerShapeChanged()));667 668 /* Mouse capability state-change updater: */669 connect(uisession(), SIGNAL(sigMouseCapabilityChange()), this, SLOT(sltMouseCapabilityChanged()));670 671 /* Mouse captivity status-change updater: */672 connect(uisession(), SIGNAL(sigMouseCapturedStatusChanged()), this, SLOT(sltMouseCapturedStatusChanged()));673 580 } 674 581 … … 708 615 void UIMachineView::cleanupCommon() 709 616 { 617 /* Unregister mouse-handler: */ 618 machineLogic()->mouseHandler()->delMachineView(screenId()); 619 710 620 #ifdef Q_WS_PM 711 621 bool ok = VBoxHlpUninstallKbdHook(0, winId(), UM_PREACCEL_CHAR); … … 953 863 bool UIMachineView::eventFilter(QObject *pWatched, QEvent *pEvent) 954 864 { 865 #ifdef VBOX_WITH_VIDEOHWACCEL 955 866 if (pWatched == viewport()) 956 867 { 957 868 switch (pEvent->type()) 958 869 { 959 case QEvent::MouseMove:960 case QEvent::MouseButtonRelease:961 {962 /* Check if we should propagate this event to another window: */963 QWidget *pWidgetAt = QApplication::widgetAt(QCursor::pos());964 if (pWidgetAt && pWidgetAt->window() && pWidgetAt->window()->inherits("UIMachineWindow") &&965 pWidgetAt->window() != machineWindowWrapper()->machineWindow())966 {967 /* Get current mouse-move event: */968 QMouseEvent *pOldMouseEvent = static_cast<QMouseEvent*>(pEvent);969 970 /* Get real destination window of that event: */971 UIMachineWindow *pMachineWindow =972 pWidgetAt->window()->inherits("UIMachineWindowNormal") ?973 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowNormal*>(pWidgetAt->window())) :974 pWidgetAt->window()->inherits("UIMachineWindowFullscreen") ?975 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowFullscreen*>(pWidgetAt->window())) :976 pWidgetAt->window()->inherits("UIMachineWindowSeamless") ?977 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowSeamless*>(pWidgetAt->window())) : 0;978 if (pMachineWindow)979 {980 /* Get viewport: */981 QWidget *pOtherViewport = pMachineWindow->machineView()->viewport();982 983 /* Prepare redirected mouse-move event: */984 QMouseEvent *pNewMouseEvent = new QMouseEvent(pOldMouseEvent->type(),985 pOtherViewport->mapFromGlobal(pOldMouseEvent->globalPos()),986 pOldMouseEvent->globalPos(),987 pOldMouseEvent->button(),988 pOldMouseEvent->buttons(),989 pOldMouseEvent->modifiers());990 991 /* Send that event to real destination: */992 QApplication::postEvent(pOtherViewport, pNewMouseEvent);993 994 /* Filter out that event: */995 return true;996 }997 }998 999 /* Check if we should activate window under cursor: */1000 if (QApplication::activeWindow() &&1001 QApplication::activeWindow()->inherits("UIMachineWindow") &&1002 QApplication::activeWindow() != machineWindowWrapper()->machineWindow())1003 {1004 /* Activating hovered machine window: */1005 machineWindowWrapper()->machineWindow()->activateWindow();1006 #ifdef Q_WS_X111007 /* On X11 its not enough to just activate window if you1008 * want to raise it also, so we will make it separately: */1009 machineWindowWrapper()->machineWindow()->raise();1010 #endif /* Q_WS_X11 */1011 }1012 1013 /* This event should be also processed using next 'case': */1014 }1015 case QEvent::MouseButtonPress:1016 case QEvent::MouseButtonDblClick:1017 {1018 QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);1019 m_iLastMouseWheelDelta = 0;1020 if (mouseEvent(pMouseEvent->type(), pMouseEvent->pos(), pMouseEvent->globalPos(),1021 pMouseEvent->buttons(), pMouseEvent->modifiers(), 0, Qt::Horizontal))1022 return true;1023 break;1024 }1025 case QEvent::Wheel:1026 {1027 QWheelEvent *pWheelEvent = static_cast<QWheelEvent*>(pEvent);1028 /* There are pointing devices which send smaller values for the delta than 120.1029 * Here we sum them up until we are greater than 120. This allows to have finer control1030 * over the speed acceleration & enables such devices to send a valid wheel event to our1031 * guest mouse device at all: */1032 int iDelta = 0;1033 m_iLastMouseWheelDelta += pWheelEvent->delta();1034 if (qAbs(m_iLastMouseWheelDelta) >= 120)1035 {1036 iDelta = m_iLastMouseWheelDelta;1037 m_iLastMouseWheelDelta = m_iLastMouseWheelDelta % 120;1038 }1039 if (mouseEvent(pWheelEvent->type(), pWheelEvent->pos(), pWheelEvent->globalPos(),1040 #ifdef QT_MAC_USE_COCOA1041 /* Qt Cocoa is buggy. It always reports a left button pressed when the1042 * mouse wheel event occurs. A workaround is to ask the application which1043 * buttons are pressed currently: */1044 QApplication::mouseButtons(),1045 #else /* QT_MAC_USE_COCOA */1046 pWheelEvent->buttons(),1047 #endif /* !QT_MAC_USE_COCOA */1048 pWheelEvent->modifiers(),1049 iDelta, pWheelEvent->orientation()))1050 return true;1051 break;1052 }1053 #ifdef Q_WS_MAC1054 case QEvent::Leave:1055 {1056 /* Enable mouse event compression if we leave the VM view. This is necessary for1057 * having smooth resizing of the VM/other windows: */1058 setMouseCoalescingEnabled(true);1059 break;1060 }1061 case QEvent::Enter:1062 {1063 /* Disable mouse event compression if we enter the VM view. So all mouse events are1064 * registered in the VM. Only do this if the keyboard/mouse is grabbed (this is when1065 * we have a valid event handler): */1066 setMouseCoalescingEnabled(false);1067 break;1068 }1069 #endif /* Q_WS_MAC */1070 870 case QEvent::Resize: 1071 871 { 1072 #ifdef Q_WS_WIN321073 updateMouseCursorClipping();1074 #endif1075 #ifdef VBOX_WITH_VIDEOHWACCEL1076 872 if (m_pFrameBuffer) 1077 {1078 873 m_pFrameBuffer->viewportResized(static_cast<QResizeEvent*>(pEvent)); 1079 }1080 #endif1081 874 break; 1082 875 } … … 1085 878 } 1086 879 } 1087 else if (pWatched == machineWindowWrapper()->machineWindow()) 880 #endif /* VBOX_WITH_VIDEOHWACCEL */ 881 if (pWatched == machineWindowWrapper()->machineWindow()) 1088 882 { 1089 883 switch (pEvent->type()) … … 1173 967 viewport()->repaint(); 1174 968 } 1175 /* Reuse the focus event handler to uncapture everything: */969 /* Reuse the focus event handler to uncapture keyboard: */ 1176 970 if (hasFocus()) 1177 971 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */); … … 1180 974 case KMachineState_Stuck: 1181 975 { 1182 /* Reuse the focus event handler to uncapture everything: */976 /* Reuse the focus event handler to uncapture keyboard: */ 1183 977 if (hasFocus()) 1184 978 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */); … … 1213 1007 } 1214 1008 1215 void UIMachineView::sltMousePointerShapeChanged()1216 {1217 /* Update mouse cursor: */1218 updateMouseCursorShape();1219 }1220 1221 void UIMachineView::sltMouseCapabilityChanged()1222 {1223 /* We should release mouse if guest notified us about it supports 'absolute' mouse1224 * and mouse is in 'integrated' mode, which could be chosen from main machine menu: */1225 if (uisession()->isMouseIntegrated() && uisession()->isMouseSupportsAbsolute())1226 {1227 CMouse mouse = session().GetConsole().GetMouse();1228 mouse.PutMouseEventAbsolute(-1, -1, 0, 0, 0);1229 captureMouse(false, false);1230 }1231 1232 /* Update mouse cursor shape: */1233 updateMouseCursorShape();1234 1235 /* Notify user about mouse 'absolute' state if method was called by signal: */1236 if (sender()) vboxProblem().remindAboutMouseIntegration(uisession()->isMouseSupportsAbsolute());1237 1238 /* Notify all listeners: */1239 emitMouseStateChanged();1240 }1241 1242 void UIMachineView::sltMouseCapturedStatusChanged()1243 {1244 /* If mouse 'captured' state value changed to 'false': */1245 if (!uisession()->isMouseCaptured())1246 {1247 /* Releasing grabbed mouse from that window: */1248 #ifdef Q_WS_WIN1249 m_fItsMeWhoCapturedMouse = false;1250 ::ClipCursor(NULL);1251 #else1252 viewport()->releaseMouse();1253 #endif /* Q_WS_WIN */1254 }1255 1256 /* Update mouse cursor shape: */1257 updateMouseCursorShape();1258 }1259 1260 1009 void UIMachineView::focusEvent(bool fHasFocus, bool fReleaseHostKey /* = true */) 1261 1010 { … … 1277 1026 else 1278 1027 { 1279 captureMouse(false);1280 1028 captureKbd(false, false); 1281 1029 releaseAllPressedKeys(fReleaseHostKey); … … 1352 1100 captureKbd(false); 1353 1101 if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated())) 1354 captureMouse(false);1102 machineLogic()->mouseHandler()->captureMouse(screenId()); 1355 1103 } 1356 1104 … … 1467 1215 qApp->processEvents(); 1468 1216 #endif 1469 captureMouse(m_bIsKeyboardCaptured); 1217 if (m_bIsKeyboardCaptured) 1218 machineLogic()->mouseHandler()->captureMouse(screenId()); 1219 else 1220 machineLogic()->mouseHandler()->releaseMouse(); 1470 1221 } 1471 1222 } … … 1562 1313 /* Grab the key from Qt: */ 1563 1314 return true; 1564 }1565 1566 bool UIMachineView::mouseEvent(int aType, const QPoint &aPos, const QPoint &aGlobalPos,1567 Qt::MouseButtons aButtons, Qt::KeyboardModifiers /* aModifiers */,1568 int aWheelDelta, Qt::Orientation aWheelDir)1569 {1570 int state = 0;1571 if (aButtons & Qt::LeftButton)1572 state |= KMouseButtonState_LeftButton;1573 if (aButtons & Qt::RightButton)1574 state |= KMouseButtonState_RightButton;1575 if (aButtons & Qt::MidButton)1576 state |= KMouseButtonState_MiddleButton;1577 if (aButtons & Qt::XButton1)1578 state |= KMouseButtonState_XButton1;1579 if (aButtons & Qt::XButton2)1580 state |= KMouseButtonState_XButton2;1581 1582 #ifdef Q_WS_MAC1583 /* Simulate the right click on Host+Left Mouse: */1584 if (m_bIsHostkeyPressed &&1585 m_bIsHostkeyAlone &&1586 state == KMouseButtonState_LeftButton)1587 state = KMouseButtonState_RightButton;1588 #endif /* Q_WS_MAC */1589 1590 int wheelVertical = 0;1591 int wheelHorizontal = 0;1592 if (aWheelDir == Qt::Vertical)1593 {1594 /* The absolute value of wheel delta is 120 units per every wheel move;1595 * positive deltas correspond to counterclockwize rotations (usually up),1596 * negative deltas correspond to clockwize (usually down). */1597 wheelVertical = - (aWheelDelta / 120);1598 }1599 else if (aWheelDir == Qt::Horizontal)1600 wheelHorizontal = aWheelDelta / 120;1601 1602 if (uisession()->isMouseCaptured())1603 {1604 #ifdef Q_WS_WIN321605 /* Send pending WM_PAINT events: */1606 ::UpdateWindow(viewport()->winId());1607 #endif1608 1609 CMouse mouse = session().GetConsole().GetMouse();1610 mouse.PutMouseEvent(aGlobalPos.x() - m_lastMousePos.x(),1611 aGlobalPos.y() - m_lastMousePos.y(),1612 wheelVertical, wheelHorizontal, state);1613 1614 #if defined (Q_WS_MAC)1615 /*1616 * Keep the mouse from leaving the widget.1617 *1618 * This is a bit tricky to get right because if it escapes we won't necessarily1619 * get mouse events any longer and can warp it back. So, we keep safety zone1620 * of up to 300 pixels around the borders of the widget to prevent this from1621 * happening. Also, the mouse is warped back to the center of the widget.1622 *1623 * (Note, aPos seems to be unreliable, it caused endless recursion here at one points...)1624 * (Note, synergy and other remote clients might not like this cursor warping.)1625 */1626 QRect rect = viewport()->visibleRegion().boundingRect();1627 QPoint pw = viewport()->mapToGlobal(viewport()->pos());1628 rect.translate(pw.x(), pw.y());1629 1630 QRect dpRect = QApplication::desktop()->screenGeometry(viewport());1631 if (rect.intersects (dpRect))1632 rect = rect.intersect(dpRect);1633 1634 int wsafe = rect.width() / 6;1635 rect.setWidth(rect.width() - wsafe * 2);1636 rect.setLeft(rect.left() + wsafe);1637 1638 int hsafe = rect.height() / 6;1639 rect.setWidth(rect.height() - hsafe * 2);1640 rect.setTop(rect.top() + hsafe);1641 1642 if (rect.contains(aGlobalPos, true))1643 m_lastMousePos = aGlobalPos;1644 else1645 {1646 m_lastMousePos = rect.center();1647 QCursor::setPos(m_lastMousePos);1648 }1649 #else /* !Q_WS_MAC */1650 1651 /* "jerk" the mouse by bringing it to the opposite side1652 * to simulate the endless moving */1653 1654 # ifdef Q_WS_WIN321655 int we = viewport()->width() - 1;1656 int he = viewport()->height() - 1;1657 QPoint p = aPos;1658 if (aPos.x() == 0)1659 p.setX(we - 1);1660 else if (aPos.x() == we)1661 p.setX(1);1662 if (aPos.y() == 0 )1663 p.setY(he - 1);1664 else if (aPos.y() == he)1665 p.setY(1);1666 1667 if (p != aPos)1668 {1669 m_lastMousePos = viewport()->mapToGlobal (p);1670 QCursor::setPos(m_lastMousePos);1671 }1672 else1673 {1674 m_lastMousePos = aGlobalPos;1675 }1676 # else1677 int we = QApplication::desktop()->width() - 1;1678 int he = QApplication::desktop()->height() - 1;1679 QPoint p = aGlobalPos;1680 if (aGlobalPos.x() == 0)1681 p.setX (we - 1);1682 else if (aGlobalPos.x() == we)1683 p.setX( 1 );1684 if (aGlobalPos.y() == 0)1685 p.setY (he - 1);1686 else if (aGlobalPos.y() == he)1687 p.setY (1);1688 1689 if (p != aGlobalPos)1690 {1691 m_lastMousePos = p;1692 QCursor::setPos(m_lastMousePos);1693 }1694 else1695 {1696 m_lastMousePos = aGlobalPos;1697 }1698 # endif1699 #endif /* !Q_WS_MAC */1700 return true; /* stop further event handling */1701 }1702 else /* !uisession()->isMouseCaptured() */1703 {1704 #if 0 // TODO: Move that to fullscreen event-hjadler:1705 if (vboxGlobal().vmRenderMode() != VBoxDefs::SDLMode)1706 {1707 /* try to automatically scroll the guest canvas if the1708 * mouse is on the screen border */1709 /// @todo (r=dmik) better use a timer for autoscroll1710 QRect scrGeo = QApplication::desktop()->screenGeometry (this);1711 int dx = 0, dy = 0;1712 if (scrGeo.width() < contentsWidth())1713 {1714 if (scrGeo.left() == aGlobalPos.x()) dx = -1;1715 if (scrGeo.right() == aGlobalPos.x()) dx = +1;1716 }1717 if (scrGeo.height() < contentsHeight())1718 {1719 if (scrGeo.top() == aGlobalPos.y()) dy = -1;1720 if (scrGeo.bottom() == aGlobalPos.y()) dy = +1;1721 }1722 if (dx || dy)1723 scrollBy(dx, dy);1724 }1725 #endif1726 1727 if (uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated())1728 {1729 int cw = contentsWidth(), ch = contentsHeight();1730 int vw = visibleWidth(), vh = visibleHeight();1731 1732 if (vboxGlobal().vmRenderMode() != VBoxDefs::SDLMode)1733 {1734 /* Try to automatically scroll the guest canvas if the1735 * mouse goes outside its visible part: */1736 int dx = 0;1737 if (aPos.x() > vw) dx = aPos.x() - vw;1738 else if (aPos.x() < 0) dx = aPos.x();1739 int dy = 0;1740 if (aPos.y() > vh) dy = aPos.y() - vh;1741 else if (aPos.y() < 0) dy = aPos.y();1742 if (dx != 0 || dy != 0) scrollBy (dx, dy);1743 }1744 1745 QPoint cpnt = viewportToContents(aPos);1746 if (cpnt.x() < 0) cpnt.setX(0);1747 else if (cpnt.x() > cw - 1) cpnt.setX(cw - 1);1748 if (cpnt.y() < 0) cpnt.setY(0);1749 else if (cpnt.y() > ch - 1) cpnt.setY(ch - 1);1750 1751 // TODO: Where to put that actually?1752 /* Get & Setup absolute-event shift: */1753 CFramebuffer framebuffer;1754 LONG xShift = 0, yShift = 0;1755 session().GetConsole().GetDisplay().GetFramebuffer(screenId(), framebuffer, xShift, yShift);1756 cpnt.setX(cpnt.x() + xShift);1757 cpnt.setY(cpnt.y() + yShift);1758 1759 CMouse mouse = session().GetConsole().GetMouse();1760 // AssertMsgFailed(("x=%d, y=%d", cpnt.x(), cpnt.y())); // this shows what absolute coordinates are correct!1761 mouse.PutMouseEventAbsolute(cpnt.x() + 1, cpnt.y() + 1, wheelVertical, wheelHorizontal, state);1762 return true;1763 }1764 else1765 {1766 if (hasFocus() && (aType == QEvent::MouseButtonRelease && aButtons == Qt::NoButton))1767 {1768 if (uisession()->isPaused())1769 {1770 vboxProblem().remindAboutPausedVMInput();1771 }1772 else if (uisession()->isRunning())1773 {1774 /* Temporarily disable auto capture that will take place after this dialog is dismissed because1775 * the capture state is to be defined by the dialog result itself: */1776 uisession()->setAutoCaptureDisabled(true);1777 bool autoConfirmed = false;1778 bool ok = vboxProblem().confirmInputCapture(&autoConfirmed);1779 if (autoConfirmed)1780 uisession()->setAutoCaptureDisabled(false);1781 /* Otherwise, the disable flag will be reset in the next console view's foucs in event (since1782 * may happen asynchronously on some platforms, after we return from this code): */1783 if (ok)1784 {1785 #ifdef Q_WS_X111786 /* Make sure that pending FocusOut events from the previous message box are handled,1787 * otherwise the mouse is immediately ungrabbed again: */1788 qApp->processEvents();1789 #endif1790 captureKbd(true);1791 captureMouse(true);1792 }1793 }1794 }1795 }1796 }1797 1798 return false;1799 1315 } 1800 1316 … … 2114 1630 { 2115 1631 if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0)) 2116 focusEvent (pEvent->type == XFocusIn); 1632 { 1633 focusEvent(pEvent->type == XFocusIn); 1634 if (pEvent->type == XFocusOut) 1635 machineLogic()->mouseHandler()->releaseMouse(); 1636 } 2117 1637 } 2118 1638 return false; … … 2423 1943 } 2424 1944 2425 void UIMachineView::emitMouseStateChanged()2426 {2427 emit mouseStateChanged(mouseState());2428 }2429 2430 1945 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */) 2431 1946 { … … 2496 2011 if (fEmitSignal) 2497 2012 emitKeyboardStateChanged(); 2498 }2499 2500 void UIMachineView::captureMouse(bool fCapture, bool fEmitSignal /* = true */)2501 {2502 /* Do not change anything if its already so: */2503 if (uisession()->isMouseCaptured() == fCapture)2504 return;2505 2506 /* Store new mouse 'captured' state value: */2507 uisession()->setMouseCaptured(fCapture);2508 2509 if (fCapture)2510 {2511 /* Memorize the host position where the cursor was captured: */2512 m_capturedMousePos = QCursor::pos();2513 #ifdef Q_WS_WIN322514 /* Remember what this window captured mouse: */2515 m_fItsMeWhoCapturedMouse = true;2516 /* Move the mouse to the center of the visible area: */2517 m_lastMousePos = mapToGlobal(visibleRegion().boundingRect().center());2518 QCursor::setPos(m_lastMousePos);2519 /* Update mouse clipping: */2520 updateMouseCursorClipping();2521 #elif defined (Q_WS_MAC)2522 /* Move the mouse to the center of the visible area: */2523 m_lastMousePos = mapToGlobal(visibleRegion().boundingRect().center());2524 QCursor::setPos(m_lastMousePos);2525 /* Grab all mouse events: */2526 viewport()->grabMouse();2527 #else2528 /* Grab all mouse events: */2529 viewport()->grabMouse();2530 m_lastMousePos = QCursor::pos();2531 #endif2532 }2533 else2534 {2535 /* Return the cursor to where it was when we captured it: */2536 QCursor::setPos(m_capturedMousePos);2537 }2538 2539 /* Updating guest mouse: */2540 CMouse mouse = session().GetConsole().GetMouse();2541 mouse.PutMouseEvent(0, 0, 0, 0, 0);2542 2543 /* Emit signal if required: */2544 if (fEmitSignal)2545 emitMouseStateChanged();2546 2013 } 2547 2014 … … 2710 2177 machineLogic()->updateDockIcon(); 2711 2178 } 2712 2713 void UIMachineView::setMouseCoalescingEnabled(bool fOn)2714 {2715 /* Enable mouse event compression if we leave the VM view. This2716 is necessary for having smooth resizing of the VM/other2717 windows.2718 Disable mouse event compression if we enter the VM view. So2719 all mouse events are registered in the VM. Only do this if2720 the keyboard/mouse is grabbed (this is when we have a valid2721 event handler). */2722 if (fOn || m_fKeyboardGrabbed)2723 ::darwinSetMouseCoalescingEnabled(fOn);2724 }2725 2179 #endif /* Q_WS_MAC */ 2726 2180 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
r30348 r30408 59 59 /* Public getters: */ 60 60 int keyboardState() const; 61 int mouseState() const;62 61 virtual QRegion lastVisibleRegion() const { return QRegion(); } 63 62 64 63 /* Public setters: */ 65 64 virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {} 66 virtual void setMouseIntegrationEnabled(bool fEnabled);67 65 68 66 /* Public members: */ … … 71 69 signals: 72 70 73 /* Mouse/Keyboard state-change signals: */71 /* Keyboard state-change signals: */ 74 72 void keyboardStateChanged(int iState); 75 void mouseStateChanged(int iState);76 73 77 74 /* Utility signals: */ … … 109 106 QSize desktopGeometry() const; 110 107 QSize guestSizeHint(); 108 #ifdef Q_WS_MAC 109 /* These getters are temporary here while UIKeyboardHandler is not implemented: */ 110 bool isHostKeyAlone() const { return m_bIsHostkeyAlone; } 111 bool isKeyboardGrabbed() const { return m_fKeyboardGrabbed; } 112 #endif /* Q_WS_MAC */ 111 113 112 114 /* Protected setters: */ … … 117 119 118 120 /* Protected helpers: */ 119 void updateMouseCursorShape();120 #ifdef Q_WS_WIN32121 void updateMouseCursorClipping();122 #endif123 121 virtual QRect workingArea() = 0; 124 122 virtual void calculateDesktopGeometry() = 0; … … 128 126 #ifdef Q_WS_MAC 129 127 void updateDockIcon(); 130 void setMouseCoalescingEnabled(bool fOn);131 128 CGImageRef vmContentImage(); 132 129 CGImageRef frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer); … … 158 155 /* Console callback handlers: */ 159 156 virtual void sltMachineStateChanged(); 160 virtual void sltMousePointerShapeChanged();161 virtual void sltMouseCapabilityChanged();162 157 virtual void sltPerformGuestResize(const QSize & /* toSize */) {}; 163 164 /* Session callback handlers: */165 virtual void sltMouseCapturedStatusChanged();166 158 167 159 /* Various helper slots: */ … … 173 165 void focusEvent(bool aHasFocus, bool aReleaseHostKey = true); 174 166 bool keyEvent(int aKey, uint8_t aScan, int aFlags, wchar_t *aUniKey = NULL); 175 bool mouseEvent(int aType, const QPoint &aPos, const QPoint &aGlobalPos,176 Qt::MouseButtons aButtons, Qt::KeyboardModifiers aModifiers,177 int aWheelDelta, Qt::Orientation aWheelDir);178 167 void resizeEvent(QResizeEvent *pEvent); 179 168 void moveEvent(QMoveEvent *pEvent); … … 203 192 #endif 204 193 void emitKeyboardStateChanged(); 205 void emitMouseStateChanged();206 194 void captureKbd(bool fCapture, bool fEmitSignal = true); 207 void captureMouse(bool fCapture, bool fEmitSignal = true);208 195 void saveKeyStates(); 209 196 void releaseAllPressedKeys(bool aReleaseHostKey = true); … … 222 209 QSize m_storedConsoleSize; 223 210 224 QPoint m_lastMousePos;225 QPoint m_capturedMousePos;226 int m_iLastMouseWheelDelta;227 228 211 uint8_t m_pressedKeys[128]; 229 212 uint8_t m_pressedKeysCopy[128]; … … 239 222 #endif 240 223 241 #ifdef Q_WS_WIN242 bool m_fItsMeWhoCapturedMouse;243 #endif /* Q_WS_WIN */244 224 #ifdef Q_WS_MAC 245 225 /** The current modifier key mask. Used to figure out which modifier … … 252 232 253 233 /* Friend classes: */ 234 friend class UIMouseHandler; 254 235 friend class UIMachineLogic; 255 236 friend class UIFrameBuffer; -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp
r30291 r30408 3 3 * 4 4 * VBox frontends: Qt GUI ("VirtualBox"): 5 * UIM achineViewclass implementation5 * UIMouseHandler class implementation 6 6 */ 7 7 … … 20 20 /* Global includes */ 21 21 #include <QDesktopWidget> 22 #include <QTimer> 23 #include <QPainter> 24 #include <QScrollBar> 25 #include <VBox/VBoxVideo.h> 22 #include <QMouseEvent> 26 23 27 24 /* Local includes */ 28 25 #include "VBoxGlobal.h" 29 26 #include "VBoxProblemReporter.h" 30 #include "UIFrameBuffer.h" 31 #include "UIFrameBufferQGL.h" 32 #include "UIFrameBufferQImage.h" 33 #include "UIFrameBufferQuartz2D.h" 34 #include "UIFrameBufferSDL.h" 35 #include "VBoxFBOverlay.h" 27 #include "UIMouseHandler.h" 36 28 #include "UISession.h" 37 #include "UIActionsPool.h"38 29 #include "UIMachineLogic.h" 39 #include "UIMachineWindow.h"40 30 #include "UIMachineView.h" 41 #include "UIMachineWindowNormal.h" 42 #include "UIMachineWindowFullscreen.h" 43 #include "UIMachineWindowSeamless.h" 44 #include "UIMachineViewNormal.h" 45 #include "UIMachineViewFullscreen.h" 46 #include "UIMachineViewSeamless.h" 47 48 #ifdef Q_WS_PM 49 # include "QIHotKeyEdit.h" 50 #endif /* defined (Q_WS_PM) */ 51 52 #ifdef Q_WS_WIN 53 #undef LOWORD 54 #undef HIWORD 55 #undef LOBYTE 56 #undef HIBYTE 57 #include <windows.h> 58 static UIMachineView *gView = 0; 59 static HHOOK gKbdHook = 0; 60 #endif /* defined (Q_WS_WIN) */ 61 62 #ifdef Q_WS_X11 63 # include <QX11Info> 64 # define XK_XKB_KEYS 65 # define XK_MISCELLANY 66 # include <X11/XKBlib.h> 67 # include <X11/keysym.h> 68 # ifdef KeyPress 69 const int XFocusOut = FocusOut; 70 const int XFocusIn = FocusIn; 71 const int XKeyPress = KeyPress; 72 const int XKeyRelease = KeyRelease; 73 # undef KeyRelease 74 # undef KeyPress 75 # undef FocusOut 76 # undef FocusIn 77 # endif 78 # include "XKeyboard.h" 79 #endif /* defined (Q_WS_X11) */ 80 81 #ifdef Q_WS_MAC 82 # include "DockIconPreview.h" 83 # include "DarwinKeyboard.h" 84 # include "UICocoaApplication.h" 85 # include <VBox/err.h> 86 # include <Carbon/Carbon.h> 87 #endif /* Q_WS_MAC */ 88 89 class VBoxViewport: public QWidget 90 { 91 public: 92 93 VBoxViewport(QWidget *pParent) : QWidget(pParent) 94 { 95 /* No need for background drawing: */ 96 setAttribute(Qt::WA_OpaquePaintEvent); 97 } 98 99 QPaintEngine *paintEngine() const 100 { 101 if (testAttribute(Qt::WA_PaintOnScreen)) 102 return NULL; 103 else 104 return QWidget::paintEngine(); 105 } 106 }; 107 108 enum { KeyExtended = 0x01, KeyPressed = 0x02, KeyPause = 0x04, KeyPrint = 0x08 }; 109 enum { IsKeyPressed = 0x01, IsExtKeyPressed = 0x02, IsKbdCaptured = 0x80 }; 110 111 UIMachineView* UIMachineView::create( UIMachineWindow *pMachineWindow 112 , VBoxDefs::RenderMode renderMode 113 #ifdef VBOX_WITH_VIDEOHWACCEL 114 , bool bAccelerate2DVideo 115 #endif 116 , UIVisualStateType visualStateType 117 , ulong uScreenId) 118 { 119 UIMachineView *view = 0; 31 32 /* Factory function to create mouse-handler: */ 33 UIMouseHandler* UIMouseHandler::create(UIMachineLogic *pMachineLogic, 34 UIVisualStateType visualStateType) 35 { 36 /* Prepare mouse-handler: */ 37 UIMouseHandler *pMouseHandler = 0; 38 /* Depending on visual-state type: */ 120 39 switch (visualStateType) 121 40 { 41 /* For now all the states using common mouse-handler: */ 122 42 case UIVisualStateType_Normal: 123 view = new UIMachineViewNormal( pMachineWindow124 , renderMode125 #ifdef VBOX_WITH_VIDEOHWACCEL126 , bAccelerate2DVideo127 #endif128 , uScreenId);129 break;130 43 case UIVisualStateType_Fullscreen: 131 view = new UIMachineViewFullscreen( pMachineWindow132 , renderMode133 #ifdef VBOX_WITH_VIDEOHWACCEL134 , bAccelerate2DVideo135 #endif136 , uScreenId);137 break;138 44 case UIVisualStateType_Seamless: 139 view = new UIMachineViewSeamless( pMachineWindow 140 , renderMode 141 #ifdef VBOX_WITH_VIDEOHWACCEL 142 , bAccelerate2DVideo 143 #endif 144 , uScreenId); 45 pMouseHandler = new UIMouseHandler(pMachineLogic); 145 46 break; 146 47 default: 147 48 break; 148 49 } 149 return view; 150 } 151 152 void UIMachineView::destroy(UIMachineView *pWhichView) 153 { 154 delete pWhichView; 155 } 156 157 int UIMachineView::keyboardState() const 158 { 159 return (m_bIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) | 160 (m_bIsHostkeyPressed ? UIViewStateType_HostKeyPressed : 0); 161 } 162 163 int UIMachineView::mouseState() const 50 /* Return prepared mouse-handler: */ 51 return pMouseHandler; 52 } 53 54 /* Factory function to destroy mouse-handler: */ 55 void UIMouseHandler::destroy(UIMouseHandler *pMouseHandler) 56 { 57 /* Delete mouse-handler: */ 58 delete pMouseHandler; 59 } 60 61 /* Registers new machine-view: */ 62 void UIMouseHandler::addMachineView(ulong uViewIndex, UIMachineView *pMachineView) 63 { 64 /* If that view is NOT registered yet: */ 65 if (!m_views.contains(uViewIndex)) 66 { 67 /* Register machine-view: */ 68 m_views.insert(uViewIndex, pMachineView); 69 /* Install event-filter for machine-view: */ 70 m_views[uViewIndex]->installEventFilter(this); 71 /* Make machine-view notify mouse-handler about resizeHintDone(): */ 72 connect(m_views[uViewIndex], SIGNAL(resizeHintDone()), this, SLOT(sltMousePointerShapeChanged())); 73 } 74 75 /* If that viewport is NOT registered yet: */ 76 if (!m_viewports.contains(uViewIndex)) 77 { 78 /* Register machine-view-viewport: */ 79 m_viewports.insert(uViewIndex, pMachineView->viewport()); 80 /* Install event-filter for machine-view-viewport: */ 81 m_viewports[uViewIndex]->installEventFilter(this); 82 } 83 } 84 85 /* Remove registered machine-view: */ 86 void UIMouseHandler::delMachineView(ulong uViewIndex) 87 { 88 /* If that view is registered yet: */ 89 if (m_views.contains(uViewIndex)) 90 { 91 /* Unregister machine-view: */ 92 m_views.remove(uViewIndex); 93 } 94 95 /* If that viewport is registered yet: */ 96 if (m_viewports.contains(uViewIndex)) 97 { 98 /* Unregister machine-view-viewport: */ 99 m_viewports.remove(uViewIndex); 100 } 101 } 102 103 void UIMouseHandler::captureMouse(ulong uScreenId) 104 { 105 /* Do not try to capture mouse if its captured already: */ 106 if (uisession()->isMouseCaptured()) 107 return; 108 109 /* If such viewport exists: */ 110 if (m_viewports.contains(uScreenId)) 111 { 112 /* Store mouse-capturing state value: */ 113 uisession()->setMouseCaptured(true); 114 115 /* Memorize the index of machine-view-viewport captured mouse: */ 116 m_iMouseCaptureViewIndex = uScreenId; 117 118 /* Memorize the host position where the cursor was captured: */ 119 m_capturedMousePos = QCursor::pos(); 120 #ifdef Q_WS_WIN 121 /* Move the mouse to the center of the visible area: */ 122 m_lastMousePos = m_views[m_iMouseCaptureViewIndex]->mapToGlobal(m_views[m_iMouseCaptureViewIndex]->visibleRegion().boundingRect().center()); 123 QCursor::setPos(m_lastMousePos); 124 /* Update mouse clipping: */ 125 updateMouseCursorClipping(); 126 #elif defined (Q_WS_MAC) 127 /* Move the mouse to the center of the visible area: */ 128 m_lastMousePos = m_views[m_iMouseCaptureViewIndex]->mapToGlobal(m_views[m_iMouseCaptureViewIndex]->visibleRegion().boundingRect().center()); 129 QCursor::setPos(m_lastMousePos); 130 /* Grab all mouse events: */ 131 m_viewports[m_iMouseCaptureViewIndex]->grabMouse(); 132 #else /* Q_WS_MAC */ 133 /* Remember current mouse position: */ 134 m_lastMousePos = QCursor::pos(); 135 /* Grab all mouse events: */ 136 m_viewports[m_iMouseCaptureViewIndex]->grabMouse(); 137 #endif /* !Q_WS_MAC */ 138 139 /* Switch guest mouse to the relative mode: */ 140 CMouse mouse = session().GetConsole().GetMouse(); 141 mouse.PutMouseEvent(0, 0, 0, 0, 0); 142 143 /* Emit signal if required: */ 144 emit mouseStateChanged(mouseState()); 145 } 146 } 147 148 void UIMouseHandler::releaseMouse() 149 { 150 /* Do not try to release mouse if its released already: */ 151 if (!uisession()->isMouseCaptured()) 152 return; 153 154 /* If such viewport exists: */ 155 if (m_viewports.contains(m_iMouseCaptureViewIndex)) 156 { 157 /* Store mouse-capturing state value: */ 158 uisession()->setMouseCaptured(false); 159 160 /* Return the cursor to where it was when we captured it: */ 161 QCursor::setPos(m_capturedMousePos); 162 #ifdef Q_WS_WIN 163 /* Update mouse clipping: */ 164 updateMouseCursorClipping(); 165 #else /* Q_WS_WIN */ 166 /* Releasing grabbed mouse from that view: */ 167 m_viewports[m_iMouseCaptureViewIndex]->releaseMouse(); 168 #endif /* !Q_WS_WIN */ 169 /* Reset mouse-capture index: */ 170 m_iMouseCaptureViewIndex = -1; 171 172 /* Emit signal if required: */ 173 emit mouseStateChanged(mouseState()); 174 } 175 } 176 177 /* Setter for mouse-integration feature: */ 178 void UIMouseHandler::setMouseIntegrationEnabled(bool fEnabled) 179 { 180 /* Do not do anything if its already done: */ 181 if (uisession()->isMouseIntegrated() == fEnabled) 182 return; 183 184 /* Store mouse-integration state value: */ 185 uisession()->setMouseIntegrated(fEnabled); 186 187 /* Reuse sltMouseCapabilityChanged() to update mouse state: */ 188 sltMouseCapabilityChanged(); 189 } 190 191 /* Current mouse state: */ 192 int UIMouseHandler::mouseState() const 164 193 { 165 194 return (uisession()->isMouseCaptured() ? UIMouseStateType_MouseCaptured : 0) | … … 168 197 } 169 198 170 void UIMachineView::setMouseIntegrationEnabled(bool fEnabled) 171 { 172 /* Do not change anything if its already so: */ 173 if (uisession()->isMouseIntegrated() == fEnabled) 174 return; 175 176 /* Store new mouse 'integrated' state value: */ 177 uisession()->setMouseIntegrated(fEnabled); 178 179 /* We should capture/release mouse depending on mouse 'integrated' state value: */ 180 captureMouse(!uisession()->isMouseIntegrated(), false /* emit signal? */); 181 182 /* Update mouse cursor shape: */ 183 updateMouseCursorShape(); 184 185 /* If mouse is integrated and supports absolute pointing 186 * we should switch guest mouse to the absolute mode: */ 187 if (uisession()->isMouseIntegrated() && uisession()->isMouseSupportsAbsolute()) 188 { 199 /* Machine state-change handler: */ 200 void UIMouseHandler::sltMachineStateChanged() 201 { 202 /* Get machine state: */ 203 KMachineState state = uisession()->machineState(); 204 /* Handle particular machine states: */ 205 switch (state) 206 { 207 case KMachineState_Paused: 208 case KMachineState_TeleportingPausedVM: 209 case KMachineState_Stuck: 210 { 211 /* Release the mouse: */ 212 releaseMouse(); 213 break; 214 } 215 default: 216 break; 217 } 218 } 219 220 /* Mouse capability-change handler: */ 221 void UIMouseHandler::sltMouseCapabilityChanged() 222 { 223 /* If mouse supports absolute pointing and mouse-integration activated: */ 224 if (uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()) 225 { 226 /* Release the mouse: */ 227 releaseMouse(); 228 /* Also we should switch guest mouse to the absolute mode: */ 189 229 CMouse mouse = session().GetConsole().GetMouse(); 190 230 mouse.PutMouseEventAbsolute(-1, -1, 0, 0, 0); 191 231 } 232 /* If mouse-integration deactivated or mouse doesn't supports absolute pointing: */ 233 else 234 { 235 /* Search for the machine-view focused now: */ 236 int iFocusedView = -1; 237 QList<ulong> screenIds = m_views.keys(); 238 for (int i = 0; i < screenIds.size(); ++i) 239 { 240 if (m_views[screenIds[i]]->hasFocus()) 241 { 242 iFocusedView = screenIds[i]; 243 break; 244 } 245 } 246 /* If there is no focused view but views are present we will use the first one: */ 247 if (iFocusedView == -1 && !screenIds.isEmpty()) 248 iFocusedView = screenIds[0]; 249 /* Capture mouse using that view: */ 250 if (iFocusedView != -1) 251 captureMouse(iFocusedView); 252 } 253 254 /* Notify user about mouse supports or not absolute pointing if that method was called by signal: */ 255 if (sender()) 256 vboxProblem().remindAboutMouseIntegration(uisession()->isMouseSupportsAbsolute()); 192 257 193 258 /* Notify all listeners: */ 194 emitMouseStateChanged(); 195 } 196 197 UIMachineView::UIMachineView( UIMachineWindow *pMachineWindow 198 , VBoxDefs::RenderMode renderMode 199 #ifdef VBOX_WITH_VIDEOHWACCEL 200 , bool bAccelerate2DVideo 201 #endif 202 , ulong uScreenId) 203 // TODO_NEW_CORE: really think of if this is right 204 // : QAbstractScrollArea(((QMainWindow*)pMachineWindow->machineWindow())->centralWidget()) 205 : QAbstractScrollArea(pMachineWindow->machineWindow()) 206 , m_pMachineWindow(pMachineWindow) 207 , m_mode(renderMode) 208 , m_uScreenId(uScreenId) 209 , m_globalSettings(vboxGlobal().settings()) 210 , m_pFrameBuffer(0) 211 , m_previousState(KMachineState_Null) 212 , m_desktopGeometryType(DesktopGeo_Invalid) 213 , m_iLastMouseWheelDelta(0) 214 , m_bIsAutoCaptureDisabled(false) 215 , m_bIsKeyboardCaptured(false) 216 , m_bIsHostkeyPressed(false) 217 , m_bIsHostkeyAlone (false) 218 , m_bIsHostkeyInCapture(false) 219 , m_bIsMachineWindowResizeIgnored(false) 220 , m_fPassCAD(false) 221 #ifdef VBOX_WITH_VIDEOHWACCEL 222 , m_fAccelerate2DVideo(bAccelerate2DVideo) 223 #endif /* VBOX_WITH_VIDEOHWACCEL */ 224 #ifdef Q_WS_WIN 225 , m_fItsMeWhoCapturedMouse(false) 226 #endif 227 #ifdef Q_WS_MAC 228 , m_darwinKeyModifiers(0) 229 , m_fKeyboardGrabbed (false) 230 #endif /* Q_WS_MAC */ 231 { 232 } 233 234 UIMachineView::~UIMachineView() 235 { 236 } 237 238 UISession* UIMachineView::uisession() const 239 { 240 return machineWindowWrapper()->machineLogic()->uisession(); 241 } 242 243 CSession& UIMachineView::session() 244 { 245 return uisession()->session(); 246 } 247 248 QSize UIMachineView::sizeHint() const 249 { 250 #ifdef VBOX_WITH_DEBUGGER 251 // TODO: Fix all DEBUGGER stuff! 252 /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */ 253 QSize fb(m_pFrameBuffer->width(), m_pFrameBuffer->height()); 254 if ((fb.width() < 16 || fb.height() < 16) && (vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled())) 255 fb = QSize(640, 480); 256 return QSize(fb.width() + frameWidth() * 2, fb.height() + frameWidth() * 2); 257 #else 258 return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2); 259 #endif 260 } 261 262 int UIMachineView::contentsX() const 263 { 264 return horizontalScrollBar()->value(); 265 } 266 267 int UIMachineView::contentsY() const 268 { 269 return verticalScrollBar()->value(); 270 } 271 272 int UIMachineView::contentsWidth() const 273 { 274 return m_pFrameBuffer->width(); 275 } 276 277 int UIMachineView::contentsHeight() const 278 { 279 return m_pFrameBuffer->height(); 280 } 281 282 int UIMachineView::visibleWidth() const 283 { 284 return horizontalScrollBar()->pageStep(); 285 } 286 287 int UIMachineView::visibleHeight() const 288 { 289 return verticalScrollBar()->pageStep(); 290 } 291 292 UIMachineLogic* UIMachineView::machineLogic() const 293 { 294 return machineWindowWrapper()->machineLogic(); 295 } 296 297 QSize UIMachineView::desktopGeometry() const 298 { 299 QSize geometry; 300 switch (m_desktopGeometryType) 301 { 302 case DesktopGeo_Fixed: 303 case DesktopGeo_Automatic: 304 geometry = QSize(qMax(m_desktopGeometry.width(), m_storedConsoleSize.width()), 305 qMax(m_desktopGeometry.height(), m_storedConsoleSize.height())); 306 break; 307 case DesktopGeo_Any: 308 geometry = QSize(0, 0); 309 break; 310 default: 311 AssertMsgFailed(("Bad geometry type %d!\n", m_desktopGeometryType)); 312 } 313 return geometry; 314 } 315 316 QSize UIMachineView::guestSizeHint() 317 { 318 /* Result: */ 319 QSize sizeHint; 320 321 /* Get current machine: */ 322 CMachine machine = session().GetMachine(); 323 324 /* Load machine view hint: */ 325 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) : 326 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId); 327 QString strValue = machine.GetExtraData(strKey); 328 329 bool ok = true; 330 int width = 0, height = 0; 331 if (ok) 332 width = strValue.section(',', 0, 0).toInt(&ok); 333 if (ok) 334 height = strValue.section(',', 1, 1).toInt(&ok); 335 336 if (ok /* If previous parameters were read correctly! */) 337 { 338 /* Compose guest size hint from loaded values: */ 339 sizeHint = QSize(width, height); 340 } 341 else 342 { 343 /* Compose guest size hint from default attributes: */ 344 sizeHint = QSize(800, 600); 345 } 346 347 /* Return result: */ 348 return sizeHint; 349 } 350 351 void UIMachineView::setDesktopGeometry(DesktopGeo geometry, int aWidth, int aHeight) 352 { 353 switch (geometry) 354 { 355 case DesktopGeo_Fixed: 356 m_desktopGeometryType = DesktopGeo_Fixed; 357 if (aWidth != 0 && aHeight != 0) 358 m_desktopGeometry = QSize(aWidth, aHeight); 359 else 360 m_desktopGeometry = QSize(0, 0); 361 storeConsoleSize(0, 0); 362 break; 363 case DesktopGeo_Automatic: 364 m_desktopGeometryType = DesktopGeo_Automatic; 365 m_desktopGeometry = QSize(0, 0); 366 storeConsoleSize(0, 0); 367 break; 368 case DesktopGeo_Any: 369 m_desktopGeometryType = DesktopGeo_Any; 370 m_desktopGeometry = QSize(0, 0); 371 break; 372 default: 373 AssertMsgFailed(("Invalid desktop geometry type %d\n", geometry)); 374 m_desktopGeometryType = DesktopGeo_Invalid; 375 } 376 } 377 378 void UIMachineView::storeConsoleSize(int iWidth, int iHeight) 379 { 380 m_storedConsoleSize = QSize(iWidth, iHeight); 381 } 382 383 void UIMachineView::storeGuestSizeHint(const QSize &sizeHint) 384 { 385 /* Get current machine: */ 386 CMachine machine = session().GetMachine(); 387 388 /* Save machine view hint: */ 389 QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) : 390 QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId); 391 QString strValue = QString("%1,%2").arg(sizeHint.width()).arg(sizeHint.height()); 392 machine.SetExtraData(strKey, strValue); 393 } 394 395 void UIMachineView::updateMouseCursorShape() 259 emit mouseStateChanged(mouseState()); 260 } 261 262 /* Mouse pointer-shape-change handler: */ 263 void UIMouseHandler::sltMousePointerShapeChanged() 396 264 { 397 265 /* First of all, we should check if the host pointer should be visible. … … 404 272 uisession()->isHidingHostPointer())) 405 273 { 406 viewport()->setCursor(Qt::BlankCursor); 274 QList<ulong> screenIds = m_viewports.keys(); 275 for (int i = 0; i < screenIds.size(); ++i) 276 m_viewports[screenIds[i]]->setCursor(Qt::BlankCursor); 407 277 } 408 278 … … 415 285 uisession()->isValidPointerShapePresent()) 416 286 { 417 viewport()->setCursor(uisession()->cursor()); 287 QList<ulong> screenIds = m_viewports.keys(); 288 for (int i = 0; i < screenIds.size(); ++i) 289 m_viewports[screenIds[i]]->setCursor(uisession()->cursor()); 418 290 } 419 291 … … 424 296 * 2. mouse is 'not captured', 'not integrated', 'absolute'. 425 297 * We have nothing to do with that except just unset the cursor. */ 426 viewport()->unsetCursor(); 427 } 428 429 #ifdef Q_WS_WIN 430 /* This method is actually required only because under win-host 431 * we do not really grab the mouse in case of capturing it. 432 * I have to check if its really need, may be just grabMouse() will be enought: */ 433 void UIMachineView::updateMouseCursorClipping() 434 { 435 if (m_fItsMeWhoCapturedMouse) 436 { 437 QRect r = viewport()->rect(); 438 r.moveTopLeft(viewport()->mapToGlobal(QPoint(0, 0))); 439 RECT rect = { r.left(), r.top(), r.right() + 1, r.bottom() + 1 }; 440 ::ClipCursor(&rect); 441 } 442 } 443 #endif 444 445 void UIMachineView::updateSliders() 446 { 447 QSize p = viewport()->size(); 448 QSize m = maximumViewportSize(); 449 450 QSize v = QSize(frameBuffer()->width(), frameBuffer()->height()); 451 /* No scroll bars needed: */ 452 if (m.expandedTo(v) == m) 453 p = m; 454 455 horizontalScrollBar()->setRange(0, v.width() - p.width()); 456 verticalScrollBar()->setRange(0, v.height() - p.height()); 457 horizontalScrollBar()->setPageStep(p.width()); 458 verticalScrollBar()->setPageStep(p.height()); 459 } 460 461 void UIMachineView::prepareFrameBuffer() 462 { 463 /* Prepare viewport: */ 464 #ifdef VBOX_GUI_USE_QGLFB 465 QWidget *pViewport; 466 switch (mode()) 467 { 468 case VBoxDefs::QGLMode: 469 pViewport = new VBoxGLWidget(session().GetConsole(), this, NULL); 470 break; 471 default: 472 pViewport = new VBoxViewport(this); 473 } 474 #else 475 VBoxViewport *pViewport = new VBoxViewport(this); 476 #endif 477 setViewport(pViewport); 478 479 CDisplay display = session().GetConsole().GetDisplay(); 480 Assert(!display.isNull()); 481 m_pFrameBuffer = NULL; 482 483 switch (mode()) 484 { 485 #ifdef VBOX_GUI_USE_QIMAGE 486 case VBoxDefs::QImageMode: 487 # ifdef VBOX_WITH_VIDEOHWACCEL 488 if (m_fAccelerate2DVideo) 489 { 490 UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId()); 491 if (pFramebuffer) 492 pFramebuffer->setView(this); 493 else 494 { 495 /* these two additional template args is a workaround to this [VBox|UI] duplication 496 * @todo: they are to be removed once VBox stuff is gone */ 497 pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQImage, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId()); 498 uisession()->setFrameBuffer(screenId(), pFramebuffer); 499 } 500 m_pFrameBuffer = pFramebuffer; 501 } 502 else 503 m_pFrameBuffer = new UIFrameBufferQImage(this); 504 # else 505 m_pFrameBuffer = new UIFrameBufferQImage(this); 506 # endif 507 break; 508 #endif /* VBOX_GUI_USE_QIMAGE */ 509 #ifdef VBOX_GUI_USE_QGLFB 510 case VBoxDefs::QGLMode: 511 m_pFrameBuffer = new UIFrameBufferQGL(this); 512 break; 513 // case VBoxDefs::QGLOverlayMode: 514 // m_pFrameBuffer = new UIQGLOverlayFrameBuffer(this); 515 // break; 516 #endif /* VBOX_GUI_USE_QGLFB */ 517 #ifdef VBOX_GUI_USE_SDL 518 case VBoxDefs::SDLMode: 519 /* Indicate that we are doing all drawing stuff ourself: */ 520 // TODO_NEW_CORE 521 viewport()->setAttribute(Qt::WA_PaintOnScreen); 522 # ifdef Q_WS_X11 523 /* This is somehow necessary to prevent strange X11 warnings on i386 and segfaults on x86_64: */ 524 XFlush(QX11Info::display()); 525 # endif 526 # if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */ 527 if (m_fAccelerate2DVideo) 528 { 529 class UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId()); 530 if (pFramebuffer) 531 pFramebuffer->setView(this); 532 else 533 { 534 /* these two additional template args is a workaround to this [VBox|UI] duplication 535 * @todo: they are to be removed once VBox stuff is gone */ 536 pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferSDL, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId()); 537 uisession()->setFrameBuffer(screenId(), pFramebuffer); 538 } 539 m_pFrameBuffer = pFramebuffer; 540 } 541 else 542 m_pFrameBuffer = new UIFrameBufferSDL(this); 543 # else 544 m_pFrameBuffer = new UIFrameBufferSDL(this); 545 # endif 546 /* Disable scrollbars because we cannot correctly draw in a scrolled window using SDL: */ 547 horizontalScrollBar()->setEnabled(false); 548 verticalScrollBar()->setEnabled(false); 549 break; 550 #endif /* VBOX_GUI_USE_SDL */ 551 #if 0 // TODO: Enable DDraw frame buffer! 552 #ifdef VBOX_GUI_USE_DDRAW 553 case VBoxDefs::DDRAWMode: 554 m_pFrameBuffer = new UIDDRAWFrameBuffer(this); 555 if (!m_pFrameBuffer || m_pFrameBuffer->address() == NULL) 556 { 557 if (m_pFrameBuffer) 558 delete m_pFrameBuffer; 559 m_mode = VBoxDefs::QImageMode; 560 m_pFrameBuffer = new UIFrameBufferQImage(this); 561 } 562 break; 563 #endif /* VBOX_GUI_USE_DDRAW */ 564 #endif 565 #ifdef VBOX_GUI_USE_QUARTZ2D 566 case VBoxDefs::Quartz2DMode: 567 /* Indicate that we are doing all drawing stuff ourself: */ 568 viewport()->setAttribute(Qt::WA_PaintOnScreen); 569 # ifdef VBOX_WITH_VIDEOHWACCEL 570 if (m_fAccelerate2DVideo) 571 { 572 UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId()); 573 if (pFramebuffer) 574 pFramebuffer->setView(this); 575 else 576 { 577 /* these two additional template args is a workaround to this [VBox|UI] duplication 578 * @todo: they are to be removed once VBox stuff is gone */ 579 pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQuartz2D, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId()); 580 uisession()->setFrameBuffer(screenId(), pFramebuffer); 581 } 582 m_pFrameBuffer = pFramebuffer; 583 } 584 else 585 m_pFrameBuffer = new UIFrameBufferQuartz2D(this); 586 # else 587 m_pFrameBuffer = new UIFrameBufferQuartz2D(this); 588 # endif 589 break; 590 #endif /* VBOX_GUI_USE_QUARTZ2D */ 591 default: 592 AssertReleaseMsgFailed(("Render mode must be valid: %d\n", mode())); 593 LogRel(("Invalid render mode: %d\n", mode())); 594 qApp->exit(1); 595 break; 596 } 597 if (m_pFrameBuffer) 598 { 599 #ifdef VBOX_WITH_VIDEOHWACCEL 600 CFramebuffer fb(NULL); 601 if (m_fAccelerate2DVideo) 602 { 603 LONG XOrigin, YOrigin; 604 /* check if the framebuffer is already assigned 605 * in this case we do not need to re-assign it 606 * neither do we need to AddRef */ 607 display.GetFramebuffer(m_uScreenId, fb, XOrigin, YOrigin); 608 } 609 if (fb.raw() != m_pFrameBuffer) /* <-this will evaluate to true iff m_fAccelerate2DVideo is disabled or iff no framebuffer is yet assigned */ 610 #endif 611 { 612 m_pFrameBuffer->AddRef(); 613 } 614 615 /* always perform SetFramebuffer to ensure 3D gets notified */ 616 display.SetFramebuffer(m_uScreenId, CFramebuffer(m_pFrameBuffer)); 617 } 618 619 #ifdef Q_WS_X11 620 /* Processing pseudo resize-event to synchronize frame-buffer 621 * with stored framebuffer size in case of machine state was 'saved': */ 622 if (session().GetMachine().GetState() == KMachineState_Saved) 623 { 624 QSize size = guestSizeHint(); 625 UIResizeEvent event(FramebufferPixelFormat_Opaque, NULL, 0, 0, size.width(), size.height()); 626 frameBuffer()->resizeEvent(&event); 627 } 628 #endif /* Q_WS_X11 */ 629 } 630 631 void UIMachineView::prepareCommon() 632 { 633 /* Prepare view frame: */ 634 setFrameStyle(QFrame::NoFrame); 635 636 /* Pressed keys: */ 637 ::memset(m_pressedKeys, 0, sizeof(m_pressedKeys)); 638 639 /* Setup palette: */ 640 QPalette palette(viewport()->palette()); 641 palette.setColor(viewport()->backgroundRole(), Qt::black); 642 viewport()->setPalette(palette); 643 644 /* Setup focus policy: */ 645 setFocusPolicy(Qt::WheelFocus); 646 647 #if defined Q_WS_PM 648 bool ok = VBoxHlpInstallKbdHook(0, winId(), UM_PREACCEL_CHAR); 649 Assert(ok); 650 NOREF(ok); 651 #endif 652 } 653 654 void UIMachineView::prepareFilters() 655 { 656 /* Enable MouseMove events: */ 657 viewport()->setMouseTracking(true); 658 659 /* QScrollView does the below on its own, but let's 660 * do it anyway for the case it will not do it in the future: */ 661 viewport()->installEventFilter(this); 662 663 /* We want to be notified on some parent's events: */ 664 machineWindowWrapper()->machineWindow()->installEventFilter(this); 665 } 666 667 void UIMachineView::prepareConsoleConnections() 298 { 299 QList<ulong> screenIds = m_viewports.keys(); 300 for (int i = 0; i < screenIds.size(); ++i) 301 m_viewports[screenIds[i]]->unsetCursor(); 302 } 303 } 304 305 /* Mouse-handler constructor: */ 306 UIMouseHandler::UIMouseHandler(UIMachineLogic *pMachineLogic) 307 : QObject(pMachineLogic) 308 , m_pMachineLogic(pMachineLogic) 309 , m_iLastMouseWheelDelta(0) 310 , m_iMouseCaptureViewIndex(-1) 668 311 { 669 312 /* Machine state-change updater: */ 670 313 connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged())); 671 314 672 /* Mouse pointer shape state-change updater: */673 connect(uisession(), SIGNAL(sigMousePointerShapeChange()), this, SLOT(sltMousePointerShapeChanged()));674 675 315 /* Mouse capability state-change updater: */ 676 316 connect(uisession(), SIGNAL(sigMouseCapabilityChange()), this, SLOT(sltMouseCapabilityChanged())); 677 317 678 /* Mouse captivity status-change updater: */ 679 connect(uisession(), SIGNAL(sigMouseCapturedStatusChanged()), this, SLOT(sltMouseCapturedStatusChanged())); 680 } 681 682 void UIMachineView::loadMachineViewSettings() 683 { 684 /* Global settings: */ 685 { 686 #ifdef Q_WS_X11 687 /* Initialize the X keyboard subsystem: */ 688 initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes")); 689 #endif 690 691 /* Remember the desktop geometry and register for geometry 692 * change events for telling the guest about video modes we like: */ 693 QString desktopGeometry = vboxGlobal().settings().publicProperty("GUI/MaxGuestResolution"); 694 if ((desktopGeometry == QString::null) || (desktopGeometry == "auto")) 695 setDesktopGeometry(DesktopGeo_Automatic, 0, 0); 696 else if (desktopGeometry == "any") 697 setDesktopGeometry(DesktopGeo_Any, 0, 0); 698 else 699 { 700 int width = desktopGeometry.section(',', 0, 0).toInt(); 701 int height = desktopGeometry.section(',', 1, 1).toInt(); 702 setDesktopGeometry(DesktopGeo_Fixed, width, height); 703 } 704 } 705 706 /* Exatra data settings: */ 707 { 708 /* CAD settings: */ 709 QString passCAD = session().GetConsole().GetMachine().GetExtraData(VBoxDefs::GUI_PassCAD); 710 if (!passCAD.isEmpty() && ((passCAD != "false") || (passCAD != "no"))) 711 m_fPassCAD = true; 712 } 713 } 714 715 void UIMachineView::cleanupCommon() 716 { 717 #ifdef Q_WS_PM 718 bool ok = VBoxHlpUninstallKbdHook(0, winId(), UM_PREACCEL_CHAR); 719 Assert(ok); 720 NOREF(ok); 721 #endif /* Q_WS_PM */ 722 723 #ifdef Q_WS_WIN 724 if (gKbdHook) 725 UnhookWindowsHookEx(gKbdHook); 726 gView = 0; 727 #endif /* Q_WS_WIN */ 728 729 #ifdef Q_WS_MAC 730 /* We have to make sure the callback for the keyboard events is released 731 * when closing this view. */ 732 if (m_fKeyboardGrabbed) 733 darwinGrabKeyboardEvents (false); 734 #endif /* Q_WS_MAC */ 735 } 736 737 void UIMachineView::cleanupFrameBuffer() 738 { 739 if (m_pFrameBuffer) 740 { 741 /* Process pending frame-buffer resize events: */ 742 QApplication::sendPostedEvents(this, VBoxDefs::ResizeEventType); 743 #ifdef VBOX_WITH_VIDEOHWACCEL 744 if (m_fAccelerate2DVideo) 745 { 746 /* When 2D is enabled we do not re-create Framebuffers. This is done to 747 * 1. avoid 2D command loss during the time slot when no framebuffer is assigned to the display 748 * 2. make it easier to preserve the current 2D state */ 749 Assert(m_pFrameBuffer == uisession()->frameBuffer(screenId())); 750 m_pFrameBuffer->setView(NULL); 751 } 752 else 753 #endif 754 { 755 /* Warn framebuffer about its no more necessary: */ 756 m_pFrameBuffer->setDeleted(true); 757 /* Detach framebuffer from Display: */ 758 CDisplay display = session().GetConsole().GetDisplay(); 759 display.SetFramebuffer(m_uScreenId, CFramebuffer(NULL)); 760 /* Release the reference: */ 761 m_pFrameBuffer->Release(); 762 // delete m_pFrameBuffer; // TODO_NEW_CORE: possibly necessary to really cleanup 763 m_pFrameBuffer = NULL; 764 } 765 } 766 } 767 768 bool UIMachineView::event(QEvent *pEvent) 769 { 770 switch (pEvent->type()) 771 { 772 case QEvent::FocusIn: 773 { 774 if (uisession()->isRunning()) 775 focusEvent(true); 776 break; 777 } 778 case QEvent::FocusOut: 779 { 780 if (uisession()->isRunning()) 781 focusEvent(false); 782 else 318 /* Mouse pointer shape state-change updaters: */ 319 connect(uisession(), SIGNAL(sigMousePointerShapeChange()), this, SLOT(sltMousePointerShapeChanged())); 320 connect(this, SIGNAL(mouseStateChanged(int)), this, SLOT(sltMousePointerShapeChanged())); 321 322 /* Initialize: */ 323 sltMachineStateChanged(); 324 sltMousePointerShapeChanged(); 325 sltMouseCapabilityChanged(); 326 } 327 328 /* Mouse-handler destructor: */ 329 UIMouseHandler::~UIMouseHandler() 330 { 331 } 332 333 /* Machine-logic getter: */ 334 UIMachineLogic* UIMouseHandler::machineLogic() const 335 { 336 return m_pMachineLogic; 337 } 338 339 /* UI Session getter: */ 340 UISession* UIMouseHandler::uisession() const 341 { 342 return machineLogic()->uisession(); 343 } 344 345 /* Main Session getter: */ 346 CSession& UIMouseHandler::session() const 347 { 348 return uisession()->session(); 349 } 350 351 /* Event handler for registered machine-view(s): */ 352 bool UIMouseHandler::eventFilter(QObject *pWatched, QEvent *pEvent) 353 { 354 /* If that object is of QWidget type: */ 355 if (QWidget *pWatchedWidget = qobject_cast<QWidget*>(pWatched)) 356 { 357 /* If thats machine-view-viewport: */ 358 if (m_viewports.values().contains(pWatchedWidget)) 359 { 360 /* Get current watched widget screen id: */ 361 ulong uScreenId = m_viewports.key(pWatchedWidget); 362 /* Handle viewport events: */ 363 switch (pEvent->type()) 783 364 { 784 /* Release the host key and all other pressed keys too even when paused 785 * (otherwise, we will get stuck keys in the guest when doing sendChangedKeyStates() on resume 786 * because key presses were already recorded in m_pressedKeys but key releases will most likely 787 * not reach us but the new focus window instead): */ 788 releaseAllPressedKeys(true /* including host key? */); 789 } 790 break; 791 } 792 793 case VBoxDefs::RepaintEventType: 794 { 795 UIRepaintEvent *pPaintEvent = static_cast<UIRepaintEvent*>(pEvent); 796 viewport()->repaint(pPaintEvent->x() - contentsX(), pPaintEvent->y() - contentsY(), 797 pPaintEvent->width(), pPaintEvent->height()); 798 799 return true; 800 } 801 802 #ifdef VBOX_WITH_VIDEOHWACCEL 803 case VBoxDefs::VHWACommandProcessType: 804 { 805 m_pFrameBuffer->doProcessVHWACommand(pEvent); 806 return true; 807 } 808 #endif 809 810 case QEvent::KeyPress: 811 case QEvent::KeyRelease: 812 { 813 QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent); 814 815 #ifdef Q_WS_PM 816 // TODO: that a temporary solution to send Alt+Tab and friends to the guest. 817 // The proper solution is to write a keyboard driver that will steal these combos from the host 818 // (it's impossible to do so using hooks on OS/2): 819 820 if (m_bIsHostkeyPressed) 821 { 822 bool pressed = pEvent->type() == QEvent::KeyPress; 823 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 824 825 /* Whether the host key is Shift so that it will modify the hot key values? 826 * Note that we don't distinguish between left and right shift here (too much hassle): */ 827 const bool kShift = (m_globalSettings.hostKey() == VK_SHIFT || 828 m_globalSettings.hostKey() == VK_LSHIFT) && 829 (pKeyEvent->state() & Qt::ShiftModifier); 830 /* define hot keys according to the Shift state */ 831 const int kAltTab = kShift ? Qt::Key_Exclam : Qt::Key_1; 832 const int kAltShiftTab = kShift ? Qt::Key_At : Qt::Key_2; 833 const int kCtrlEsc = kShift ? Qt::Key_AsciiTilde : Qt::Key_QuoteLeft; 834 835 /* Simulate Alt+Tab on Host+1 and Alt+Shift+Tab on Host+2 */ 836 if (pKeyEvent->key() == kAltTab || pKeyEvent->key() == kAltShiftTab) 837 { 838 if (pressed) 365 case QEvent::MouseMove: 366 case QEvent::MouseButtonRelease: 367 { 368 /* Check if we should propagate this event to another window: */ 369 QWidget *pHoveredWidget = QApplication::widgetAt(QCursor::pos()); 370 if (pHoveredWidget && pHoveredWidget != pWatchedWidget && m_viewports.values().contains(pHoveredWidget)) 839 371 { 840 /* Send the Alt press to the guest */ 841 if (!(m_pressedKeysCopy[0x38] & IsKeyPressed)) 842 { 843 /* Store the press in *Copy to have it automatically 844 * released when the Host key is released: */ 845 m_pressedKeysCopy[0x38] |= IsKeyPressed; 846 keyboard.PutScancode(0x38); 847 } 848 849 /* Make sure Shift is pressed if it's Key_2 and released if it's Key_1: */ 850 if (pKeyEvent->key() == kAltTab && 851 (m_pressedKeysCopy[0x2A] & IsKeyPressed)) 852 { 853 m_pressedKeysCopy[0x2A] &= ~IsKeyPressed; 854 keyboard.PutScancode(0xAA); 855 } 856 else 857 if (pKeyEvent->key() == kAltShiftTab && 858 !(m_pressedKeysCopy[0x2A] & IsKeyPressed)) 859 { 860 m_pressedKeysCopy[0x2A] |= IsKeyPressed; 861 keyboard.PutScancode(0x2A); 862 } 863 } 864 865 keyboard.PutScancode(pressed ? 0x0F : 0x8F); 866 867 pKeyEvent->accept(); 868 return true; 869 } 870 871 /* Simulate Ctrl+Esc on Host+Tilde */ 872 if (pKeyEvent->key() == kCtrlEsc) 873 { 874 /* Send the Ctrl press to the guest */ 875 if (pressed && !(m_pressedKeysCopy[0x1d] & IsKeyPressed)) 876 { 877 /* store the press in *Copy to have it automatically 878 * released when the Host key is released */ 879 m_pressedKeysCopy[0x1d] |= IsKeyPressed; 880 keyboard.PutScancode(0x1d); 881 } 882 883 keyboard.PutScancode(pressed ? 0x01 : 0x81); 884 885 pKeyEvent->accept(); 886 return true; 887 } 888 } 889 #endif /* Q_WS_PM */ 890 891 if (m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyPress) 892 { 893 /* Passing F1-F12 keys to the guest: */ 894 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F12) 895 { 896 QVector <LONG> combo(6); 897 combo[0] = 0x1d; /* Ctrl down */ 898 combo[1] = 0x38; /* Alt down */ 899 combo[4] = 0xb8; /* Alt up */ 900 combo[5] = 0x9d; /* Ctrl up */ 901 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F10) 902 { 903 combo[2] = 0x3b + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 down */ 904 combo[3] = 0xbb + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 up */ 905 } 906 /* some scan slice */ 907 else if (pKeyEvent->key() >= Qt::Key_F11 && pKeyEvent->key() <= Qt::Key_F12) 908 { 909 combo[2] = 0x57 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 down */ 910 combo[3] = 0xd7 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 up */ 911 } 912 else 913 Assert(0); 914 915 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 916 keyboard.PutScancodes(combo); 917 } 918 919 /* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */ 920 machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(pKeyEvent->key())); 921 } 922 else if (!m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyRelease) 923 { 924 /* Show a possible warning on key release which seems to be more expected by the end user: */ 925 if (uisession()->isPaused()) 926 { 927 /* Iif the reminder is disabled we pass the event to Qt to enable normal 928 * keyboard functionality (for example, menu access with Alt+Letter): */ 929 if (!vboxProblem().remindAboutPausedVMInput()) 930 break; 931 } 932 } 933 934 pKeyEvent->accept(); 935 return true; 936 } 937 938 #ifdef Q_WS_MAC 939 /* posted OnShowWindow */ 940 case VBoxDefs::ShowWindowEventType: 941 { 942 /* Dunno what Qt3 thinks a window that has minimized to the dock should be - it is not hidden, 943 * neither is it minimized. OTOH it is marked shown and visible, but not activated. 944 * This latter isn't of much help though, since at this point nothing is marked activated. 945 * I might have overlooked something, but I'm buggered what if I know what. So, I'll just always 946 * show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */ 947 window()->show(); 948 window()->activateWindow(); 949 return true; 950 } 951 #endif 952 953 default: 954 break; 955 } 956 957 return QAbstractScrollArea::event(pEvent); 958 } 959 960 bool UIMachineView::eventFilter(QObject *pWatched, QEvent *pEvent) 961 { 962 if (pWatched == viewport()) 963 { 964 switch (pEvent->type()) 965 { 966 case QEvent::MouseMove: 967 case QEvent::MouseButtonRelease: 968 { 969 /* Check if we should propagate this event to another window: */ 970 QWidget *pWidgetAt = QApplication::widgetAt(QCursor::pos()); 971 if (pWidgetAt && pWidgetAt->window() && pWidgetAt->window()->inherits("UIMachineWindow") && 972 pWidgetAt->window() != machineWindowWrapper()->machineWindow()) 973 { 974 /* Get current mouse-move event: */ 975 QMouseEvent *pOldMouseEvent = static_cast<QMouseEvent*>(pEvent); 976 977 /* Get real destination window of that event: */ 978 UIMachineWindow *pMachineWindow = 979 pWidgetAt->window()->inherits("UIMachineWindowNormal") ? 980 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowNormal*>(pWidgetAt->window())) : 981 pWidgetAt->window()->inherits("UIMachineWindowFullscreen") ? 982 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowFullscreen*>(pWidgetAt->window())) : 983 pWidgetAt->window()->inherits("UIMachineWindowSeamless") ? 984 static_cast<UIMachineWindow*>(qobject_cast<UIMachineWindowSeamless*>(pWidgetAt->window())) : 0; 985 if (pMachineWindow) 986 { 987 /* Get viewport: */ 988 QWidget *pOtherViewport = pMachineWindow->machineView()->viewport(); 372 /* Get current mouse-move event: */ 373 QMouseEvent *pOldMouseEvent = static_cast<QMouseEvent*>(pEvent); 989 374 990 375 /* Prepare redirected mouse-move event: */ 991 376 QMouseEvent *pNewMouseEvent = new QMouseEvent(pOldMouseEvent->type(), 992 p OtherViewport->mapFromGlobal(pOldMouseEvent->globalPos()),377 pHoveredWidget->mapFromGlobal(pOldMouseEvent->globalPos()), 993 378 pOldMouseEvent->globalPos(), 994 379 pOldMouseEvent->button(), … … 997 382 998 383 /* Send that event to real destination: */ 999 QApplication::postEvent(p OtherViewport, pNewMouseEvent);384 QApplication::postEvent(pHoveredWidget, pNewMouseEvent); 1000 385 1001 386 /* Filter out that event: */ 1002 387 return true; 1003 388 } 1004 } 1005 1006 /* Check if we should activate window under cursor: */1007 if (QApplication::activeWindow() &&1008 QApplication::activeWindow()->inherits("UIMachineWindow") &&1009 QApplication::activeWindow() != machineWindowWrapper()->machineWindow())1010 {1011 /* Activating hovered machine window: */1012 machineWindowWrapper()->machineWindow()->activateWindow();389 390 /* Check if we should activate window under cursor: */ 391 if (!uisession()->isMouseCaptured() && 392 QApplication::activeWindow() && 393 QApplication::activeWindow()->inherits("UIMachineWindow") && 394 QApplication::activeWindow() != pWatchedWidget->window()) 395 { 396 /* Activating hovered machine window: */ 397 pWatchedWidget->window()->activateWindow(); 1013 398 #ifdef Q_WS_X11 1014 /* On X11 its not enough to just activate window if you1015 * want to raise it also, so we will make it separately: */1016 machineWindowWrapper()->machineWindow()->raise();399 /* On X11 its not enough to just activate window if you 400 * want to raise it also, so we will make it separately: */ 401 pWatchedWidget->window()->raise(); 1017 402 #endif /* Q_WS_X11 */ 1018 } 1019 1020 /* This event should be also processed using next 'case': */ 403 } 404 405 /* This event should be also processed using next 'case': */ 406 } 407 case QEvent::MouseButtonPress: 408 case QEvent::MouseButtonDblClick: 409 { 410 QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent); 411 m_iLastMouseWheelDelta = 0; 412 if (mouseEvent(pMouseEvent->type(), uScreenId, 413 pMouseEvent->pos(), pMouseEvent->globalPos(), 414 pMouseEvent->buttons(), 0, Qt::Horizontal)) 415 return true; 416 break; 417 } 418 case QEvent::Wheel: 419 { 420 QWheelEvent *pWheelEvent = static_cast<QWheelEvent*>(pEvent); 421 /* There are pointing devices which send smaller values for the delta than 120. 422 * Here we sum them up until we are greater than 120. This allows to have finer control 423 * over the speed acceleration & enables such devices to send a valid wheel event to our 424 * guest mouse device at all: */ 425 int iDelta = 0; 426 m_iLastMouseWheelDelta += pWheelEvent->delta(); 427 if (qAbs(m_iLastMouseWheelDelta) >= 120) 428 { 429 iDelta = m_iLastMouseWheelDelta; 430 m_iLastMouseWheelDelta = m_iLastMouseWheelDelta % 120; 431 } 432 if (mouseEvent(pWheelEvent->type(), uScreenId, 433 pWheelEvent->pos(), pWheelEvent->globalPos(), 434 #ifdef QT_MAC_USE_COCOA 435 /* Qt Cocoa is buggy. It always reports a left button pressed when the 436 * mouse wheel event occurs. A workaround is to ask the application which 437 * buttons are pressed currently: */ 438 QApplication::mouseButtons(), 439 #else /* QT_MAC_USE_COCOA */ 440 pWheelEvent->buttons(), 441 #endif /* !QT_MAC_USE_COCOA */ 442 iDelta, pWheelEvent->orientation())) 443 return true; 444 break; 445 } 446 #ifdef Q_WS_MAC 447 case QEvent::Leave: 448 { 449 /* Enable mouse event compression if we leave the VM view. 450 * This is necessary for having smooth resizing of the VM/other windows: */ 451 ::darwinSetMouseCoalescingEnabled(true); 452 break; 453 } 454 case QEvent::Enter: 455 { 456 /* Disable mouse event compression if we enter the VM view. 457 * So all mouse events are registered in the VM. 458 * Only do this if the keyboard/mouse is grabbed 459 * (this is when we have a valid event handler): */ 460 if (m_views[uScreenId]->isKeyboardGrabbed()) 461 ::darwinSetMouseCoalescingEnabled(false); 462 break; 463 } 464 #endif /* Q_WS_MAC */ 465 #ifdef Q_WS_WIN 466 case QEvent::Resize: 467 { 468 /* Update mouse clipping: */ 469 updateMouseCursorClipping(); 470 break; 471 } 472 #endif /* Q_WS_WIN */ 473 default: 474 break; 1021 475 } 1022 case QEvent::MouseButtonPress: 1023 case QEvent::MouseButtonDblClick: 476 } 477 /* If no => check if that widget is of UIMachineView type: */ 478 else if (UIMachineView *pWatchedMachineView = qobject_cast<UIMachineView*>(pWatchedWidget)) 479 { 480 /* If thats machine-view itself => handle machine-view events: */ 481 if (m_views.values().contains(pWatchedMachineView)) 1024 482 { 1025 QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent); 1026 m_iLastMouseWheelDelta = 0; 1027 if (mouseEvent(pMouseEvent->type(), pMouseEvent->pos(), pMouseEvent->globalPos(), 1028 pMouseEvent->buttons(), pMouseEvent->modifiers(), 0, Qt::Horizontal)) 1029 return true; 1030 break; 483 switch (pEvent->type()) 484 { 485 case QEvent::FocusOut: 486 /* Just release the mouse: */ 487 releaseMouse(); 488 break; 489 default: 490 break; 491 } 1031 492 } 1032 case QEvent::Wheel: 1033 { 1034 QWheelEvent *pWheelEvent = static_cast<QWheelEvent*>(pEvent); 1035 /* There are pointing devices which send smaller values for the delta than 120. 1036 * Here we sum them up until we are greater than 120. This allows to have finer control 1037 * over the speed acceleration & enables such devices to send a valid wheel event to our 1038 * guest mouse device at all: */ 1039 int iDelta = 0; 1040 m_iLastMouseWheelDelta += pWheelEvent->delta(); 1041 if (qAbs(m_iLastMouseWheelDelta) >= 120) 1042 { 1043 iDelta = m_iLastMouseWheelDelta; 1044 m_iLastMouseWheelDelta = m_iLastMouseWheelDelta % 120; 1045 } 1046 if (mouseEvent(pWheelEvent->type(), pWheelEvent->pos(), pWheelEvent->globalPos(), 1047 #ifdef QT_MAC_USE_COCOA 1048 /* Qt Cocoa is buggy. It always reports a left button pressed when the 1049 * mouse wheel event occurs. A workaround is to ask the application which 1050 * buttons are pressed currently: */ 1051 QApplication::mouseButtons(), 1052 #else /* QT_MAC_USE_COCOA */ 1053 pWheelEvent->buttons(), 1054 #endif /* !QT_MAC_USE_COCOA */ 1055 pWheelEvent->modifiers(), 1056 iDelta, pWheelEvent->orientation())) 1057 return true; 1058 break; 1059 } 493 } 494 } 495 return QObject::eventFilter(pWatched, pEvent); 496 } 497 498 /* Separate function to handle most of existing mouse-events: */ 499 bool UIMouseHandler::mouseEvent(int iEventType, ulong uScreenId, 500 const QPoint &relativePos, const QPoint &globalPos, 501 Qt::MouseButtons mouseButtons, 502 int wheelDelta, Qt::Orientation wheelDirection) 503 { 504 /* Check if such view & viewport are registered: */ 505 if (!m_views.contains(uScreenId) || !m_viewports.contains(uScreenId)) 506 return true; 507 508 int iMouseButtonsState = 0; 509 if (mouseButtons & Qt::LeftButton) 510 iMouseButtonsState |= KMouseButtonState_LeftButton; 511 if (mouseButtons & Qt::RightButton) 512 iMouseButtonsState |= KMouseButtonState_RightButton; 513 if (mouseButtons & Qt::MidButton) 514 iMouseButtonsState |= KMouseButtonState_MiddleButton; 515 if (mouseButtons & Qt::XButton1) 516 iMouseButtonsState |= KMouseButtonState_XButton1; 517 if (mouseButtons & Qt::XButton2) 518 iMouseButtonsState |= KMouseButtonState_XButton2; 519 1060 520 #ifdef Q_WS_MAC 1061 case QEvent::Leave: 1062 { 1063 /* Enable mouse event compression if we leave the VM view. This is necessary for 1064 * having smooth resizing of the VM/other windows: */ 1065 setMouseCoalescingEnabled(true); 1066 break; 1067 } 1068 case QEvent::Enter: 1069 { 1070 /* Disable mouse event compression if we enter the VM view. So all mouse events are 1071 * registered in the VM. Only do this if the keyboard/mouse is grabbed (this is when 1072 * we have a valid event handler): */ 1073 setMouseCoalescingEnabled(false); 1074 break; 1075 } 521 /* Simulate the right click on host-key + left-mouse-button: */ 522 if (m_views[uScreenId]->isHostKeyPressed() && 523 m_views[uScreenId]->isHostKeyAlone() && 524 iMouseButtonsState == KMouseButtonState_LeftButton) 525 iMouseButtonsState = KMouseButtonState_RightButton; 1076 526 #endif /* Q_WS_MAC */ 1077 case QEvent::Resize: 1078 { 1079 #ifdef Q_WS_WIN32 1080 updateMouseCursorClipping(); 1081 #endif 1082 #ifdef VBOX_WITH_VIDEOHWACCEL 1083 if (m_pFrameBuffer) 1084 { 1085 m_pFrameBuffer->viewportResized(static_cast<QResizeEvent*>(pEvent)); 1086 } 1087 #endif 1088 break; 1089 } 1090 default: 1091 break; 1092 } 1093 } 1094 else if (pWatched == machineWindowWrapper()->machineWindow()) 1095 { 1096 switch (pEvent->type()) 1097 { 1098 case QEvent::WindowStateChange: 1099 { 1100 /* During minimizing and state restoring machineWindowWrapper() gets 1101 * the focus which belongs to console view window, so returning it properly. */ 1102 QWindowStateChangeEvent *pWindowEvent = static_cast<QWindowStateChangeEvent*>(pEvent); 1103 if (pWindowEvent->oldState() & Qt::WindowMinimized) 1104 { 1105 if (QApplication::focusWidget()) 1106 { 1107 QApplication::focusWidget()->clearFocus(); 1108 qApp->processEvents(); 1109 } 1110 QTimer::singleShot(0, this, SLOT(setFocus())); 1111 } 1112 break; 1113 } 1114 #if defined (Q_WS_WIN32) 1115 /* Install/uninstall low-level kbd hook on every activation/deactivation to: 1116 * a) avoid excess hook calls when we're not active and 1117 * b) be always in front of any other possible hooks */ 1118 case QEvent::WindowActivate: 1119 { 1120 gView = this; 1121 gKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0); 1122 AssertMsg(gKbdHook, ("SetWindowsHookEx(): err=%d", GetLastError())); 1123 break; 1124 } 1125 case QEvent::WindowDeactivate: 1126 { 1127 if (gKbdHook) 1128 { 1129 UnhookWindowsHookEx(gKbdHook); 1130 gKbdHook = NULL; 1131 if (gView == this) 1132 gView = 0; 1133 } 1134 break; 1135 } 1136 #endif /* defined (Q_WS_WIN32) */ 1137 #ifdef Q_WS_MAC 1138 /* Install/remove the keyboard event handler: */ 1139 case QEvent::WindowActivate: 1140 darwinGrabKeyboardEvents(true); 1141 break; 1142 case QEvent::WindowDeactivate: 1143 darwinGrabKeyboardEvents(false); 1144 break; 1145 #endif /* Q_WS_MAC */ 1146 default: 1147 break; 1148 } 1149 } 1150 1151 return QAbstractScrollArea::eventFilter (pWatched, pEvent); 1152 } 1153 1154 void UIMachineView::sltMachineStateChanged() 1155 { 1156 /* Get machine state: */ 1157 KMachineState state = uisession()->machineState(); 1158 switch (state) 1159 { 1160 case KMachineState_Paused: 1161 case KMachineState_TeleportingPausedVM: 1162 { 1163 if (mode() != VBoxDefs::TimerMode && m_pFrameBuffer && 1164 (state != KMachineState_TeleportingPausedVM || m_previousState != KMachineState_Teleporting)) 1165 { 1166 /* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */ 1167 QImage shot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32); 1168 /* If TakeScreenShot fails or returns no image, just show a black image. */ 1169 shot.fill(0); 1170 CDisplay dsp = session().GetConsole().GetDisplay(); 1171 dsp.TakeScreenShot(screenId(), shot.bits(), shot.width(), shot.height()); 1172 /* TakeScreenShot() may fail if, e.g. the Paused notification was delivered 1173 * after the machine execution was resumed. It's not fatal: */ 1174 if (dsp.isOk()) 1175 { 1176 dimImage(shot); 1177 } 1178 m_pauseShot = QPixmap::fromImage(shot); 1179 /* Fully repaint to pick up m_pauseShot: */ 1180 viewport()->repaint(); 1181 } 1182 /* reuse the focus event handler to uncapture everything */ 1183 if (hasFocus()) 1184 focusEvent (false /* aHasFocus*/, false /* aReleaseHostKey */); 1185 break; 1186 } 1187 case KMachineState_Stuck: 1188 { 1189 /* Reuse the focus event handler to uncapture everything: */ 1190 if (hasFocus()) 1191 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */); 1192 break; 1193 } 1194 case KMachineState_Running: 1195 { 1196 if ( m_previousState == KMachineState_Paused 1197 || m_previousState == KMachineState_TeleportingPausedVM 1198 || m_previousState == KMachineState_Restoring) 1199 { 1200 if (mode() != VBoxDefs::TimerMode && m_pFrameBuffer) 1201 { 1202 /* Reset the pixmap to free memory: */ 1203 m_pauseShot = QPixmap(); 1204 /* Ask for full guest display update (it will also update 1205 * the viewport through IFramebuffer::NotifyUpdate): */ 1206 CDisplay dsp = session().GetConsole().GetDisplay(); 1207 dsp.InvalidateAndUpdate(); 1208 } 1209 } 1210 /* Reuse the focus event handler to capture input: */ 1211 if (hasFocus()) 1212 focusEvent(true /* aHasFocus */); 1213 break; 1214 } 1215 default: 1216 break; 1217 } 1218 1219 m_previousState = state; 1220 } 1221 1222 void UIMachineView::sltMousePointerShapeChanged() 1223 { 1224 /* Update mouse cursor: */ 1225 updateMouseCursorShape(); 1226 } 1227 1228 void UIMachineView::sltMouseCapabilityChanged() 1229 { 1230 /* We should release mouse if guest notified us about it supports 'absolute' mouse 1231 * and mouse is in 'integrated' mode, which could be chosen from main machine menu: */ 1232 if (uisession()->isMouseIntegrated() && uisession()->isMouseSupportsAbsolute()) 1233 { 1234 CMouse mouse = session().GetConsole().GetMouse(); 1235 mouse.PutMouseEventAbsolute(-1, -1, 0, 0, 0); 1236 captureMouse(false, false); 1237 } 1238 1239 /* Update mouse cursor shape: */ 1240 updateMouseCursorShape(); 1241 1242 /* Notify user about mouse 'absolute' state if method was called by signal: */ 1243 if (sender()) vboxProblem().remindAboutMouseIntegration(uisession()->isMouseSupportsAbsolute()); 1244 1245 /* Notify all listeners: */ 1246 emitMouseStateChanged(); 1247 } 1248 1249 void UIMachineView::sltMouseCapturedStatusChanged() 1250 { 1251 /* If mouse 'captured' state value changed to 'false': */ 1252 if (!uisession()->isMouseCaptured()) 1253 { 1254 /* Releasing grabbed mouse from that window: */ 1255 #ifdef Q_WS_WIN 1256 m_fItsMeWhoCapturedMouse = false; 1257 ::ClipCursor(NULL); 1258 #else 1259 viewport()->releaseMouse(); 1260 #endif /* Q_WS_WIN */ 1261 } 1262 1263 /* Update mouse cursor shape: */ 1264 updateMouseCursorShape(); 1265 } 1266 1267 void UIMachineView::focusEvent(bool fHasFocus, bool fReleaseHostKey /* = true */) 1268 { 1269 if (fHasFocus) 1270 { 1271 #ifdef Q_WS_WIN32 1272 if (!m_bIsAutoCaptureDisabled && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow()) 1273 #else 1274 if (!m_bIsAutoCaptureDisabled && m_globalSettings.autoCapture()) 1275 #endif 1276 { 1277 captureKbd(true); 1278 } 1279 1280 /* Reset the single-time disable capture flag: */ 1281 if (m_bIsAutoCaptureDisabled) 1282 m_bIsAutoCaptureDisabled = false; 1283 } 1284 else 1285 { 1286 captureMouse(false); 1287 captureKbd(false, false); 1288 releaseAllPressedKeys(fReleaseHostKey); 1289 } 1290 } 1291 1292 bool UIMachineView::keyEvent(int iKey, uint8_t uScan, int fFlags, wchar_t *pUniKey /* = NULL */) 1293 { 1294 const bool isHostKey = iKey == m_globalSettings.hostKey(); 1295 1296 LONG buf[16]; 1297 LONG *codes = buf; 1298 uint count = 0; 1299 uint8_t whatPressed = 0; 1300 1301 if (!isHostKey && !m_bIsHostkeyPressed) 1302 { 1303 if (fFlags & KeyPrint) 1304 { 1305 static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 }; 1306 static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA }; 1307 if (fFlags & KeyPressed) 1308 { 1309 codes = PrintMake; 1310 count = SIZEOF_ARRAY(PrintMake); 1311 } 1312 else 1313 { 1314 codes = PrintBreak; 1315 count = SIZEOF_ARRAY(PrintBreak); 1316 } 1317 } 1318 else if (fFlags & KeyPause) 1319 { 1320 if (fFlags & KeyPressed) 1321 { 1322 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 }; 1323 codes = Pause; 1324 count = SIZEOF_ARRAY(Pause); 1325 } 1326 else 1327 { 1328 /* Pause shall not produce a break code */ 1329 return true; 1330 } 1331 } 1332 else 1333 { 1334 if (fFlags & KeyPressed) 1335 { 1336 /* Check if the guest has the same view on the modifier keys (NumLock, 1337 * CapsLock, ScrollLock) as the X server. If not, send KeyPress events 1338 * to synchronize the state. */ 1339 fixModifierState(codes, &count); 1340 } 1341 1342 /* Check if it's C-A-D and GUI/PassCAD is not true */ 1343 if (!m_fPassCAD && 1344 uScan == 0x53 /* Del */ && 1345 ((m_pressedKeys[0x38] & IsKeyPressed) /* Alt */ || 1346 (m_pressedKeys[0x38] & IsExtKeyPressed)) && 1347 ((m_pressedKeys[0x1d] & IsKeyPressed) /* Ctrl */ || 1348 (m_pressedKeys[0x1d] & IsExtKeyPressed))) 1349 { 1350 /* Use the C-A-D combination as a last resort to get the 1351 * keyboard and mouse back to the host when the user forgets 1352 * the Host Key. Note that it's always possible to send C-A-D 1353 * to the guest using the Host+Del combination. BTW, it would 1354 * be preferrable to completely ignore C-A-D in guests, but 1355 * that's not possible because we cannot predict what other 1356 * keys will be pressed next when one of C, A, D is held. */ 1357 if (uisession()->isRunning() && m_bIsKeyboardCaptured) 1358 { 1359 captureKbd(false); 1360 if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated())) 1361 captureMouse(false); 1362 } 1363 1364 return true; 1365 } 1366 1367 /* Process the scancode and update the table of pressed keys: */ 1368 whatPressed = IsKeyPressed; 1369 1370 if (fFlags & KeyExtended) 1371 { 1372 codes[count++] = 0xE0; 1373 whatPressed = IsExtKeyPressed; 1374 } 1375 1376 if (fFlags & KeyPressed) 1377 { 1378 codes[count++] = uScan; 1379 m_pressedKeys[uScan] |= whatPressed; 1380 } 1381 else 1382 { 1383 /* If we haven't got this key's press message, we ignore its release: */ 1384 if (!(m_pressedKeys[uScan] & whatPressed)) 1385 return true; 1386 codes[count++] = uScan | 0x80; 1387 m_pressedKeys[uScan] &= ~whatPressed; 1388 } 1389 1390 if (m_bIsKeyboardCaptured) 1391 m_pressedKeys[uScan] |= IsKbdCaptured; 1392 else 1393 m_pressedKeys[uScan] &= ~IsKbdCaptured; 1394 } 1395 } 1396 else 1397 { 1398 /* Currently this is used in winLowKeyboardEvent() only: */ 1399 m_bIsHostkeyInCapture = m_bIsKeyboardCaptured; 1400 } 1401 1402 bool emitSignal = false; 1403 int hotkey = 0; 1404 1405 /* Process the host key: */ 1406 if (fFlags & KeyPressed) 1407 { 1408 if (isHostKey) 1409 { 1410 if (!m_bIsHostkeyPressed) 1411 { 1412 m_bIsHostkeyPressed = m_bIsHostkeyAlone = true; 1413 if (uisession()->isRunning()) 1414 saveKeyStates(); 1415 emitSignal = true; 1416 } 1417 } 1418 else 1419 { 1420 if (m_bIsHostkeyPressed) 1421 { 1422 if (m_bIsHostkeyAlone) 1423 { 1424 hotkey = iKey; 1425 m_bIsHostkeyAlone = false; 1426 } 1427 } 1428 } 1429 } 1430 else 1431 { 1432 if (isHostKey) 1433 { 1434 if (m_bIsHostkeyPressed) 1435 { 1436 m_bIsHostkeyPressed = false; 1437 1438 if (m_bIsHostkeyAlone) 1439 { 1440 if (uisession()->isPaused()) 1441 { 1442 vboxProblem().remindAboutPausedVMInput(); 1443 } 1444 else if (uisession()->isRunning()) 1445 { 1446 bool captured = m_bIsKeyboardCaptured; 1447 bool ok = true; 1448 if (!captured) 1449 { 1450 /* temporarily disable auto capture that will take 1451 * place after this dialog is dismissed because 1452 * the capture state is to be defined by the 1453 * dialog result itself */ 1454 m_bIsAutoCaptureDisabled = true; 1455 bool autoConfirmed = false; 1456 ok = vboxProblem().confirmInputCapture (&autoConfirmed); 1457 if (autoConfirmed) 1458 m_bIsAutoCaptureDisabled = false; 1459 /* otherwise, the disable flag will be reset in 1460 * the next console view's foucs in event (since 1461 * may happen asynchronously on some platforms, 1462 * after we return from this code) */ 1463 } 1464 1465 if (ok) 1466 { 1467 captureKbd (!captured, false); 1468 if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated())) 1469 { 1470 #ifdef Q_WS_X11 1471 /* make sure that pending FocusOut events from the 1472 * previous message box are handled, otherwise the 1473 * mouse is immediately ungrabbed. */ 1474 qApp->processEvents(); 1475 #endif 1476 captureMouse(m_bIsKeyboardCaptured); 1477 } 1478 } 1479 } 1480 } 1481 1482 if (uisession()->isRunning()) 1483 sendChangedKeyStates(); 1484 1485 emitSignal = true; 1486 } 1487 } 1488 else 1489 { 1490 if (m_bIsHostkeyPressed) 1491 m_bIsHostkeyAlone = false; 1492 } 1493 } 1494 1495 /* emit the keyboard state change signal */ 1496 if (emitSignal) 1497 emitKeyboardStateChanged(); 1498 1499 /* Process Host+<key> shortcuts. currently, <key> is limited to 1500 * alphanumeric chars. Other Host+<key> combinations are handled in 1501 * event(). */ 1502 if (hotkey) 1503 { 1504 bool processed = false; 1505 #if defined (Q_WS_WIN32) 1506 NOREF(pUniKey); 1507 int n = GetKeyboardLayoutList(0, NULL); 1508 Assert (n); 1509 HKL *list = new HKL[n]; 1510 GetKeyboardLayoutList(n, list); 1511 for (int i = 0; i < n && !processed; i++) 1512 { 1513 wchar_t ch; 1514 static BYTE keys[256] = {0}; 1515 if (!ToUnicodeEx(hotkey, 0, keys, &ch, 1, 0, list[i]) == 1) 1516 ch = 0; 1517 if (ch) 1518 processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence((Qt::UNICODE_ACCEL + QChar(ch).toUpper().unicode()))); 1519 } 1520 delete[] list; 1521 #elif defined (Q_WS_X11) 1522 NOREF(pUniKey); 1523 Display *display = QX11Info::display(); 1524 int keysyms_per_keycode = getKeysymsPerKeycode(); 1525 KeyCode kc = XKeysymToKeycode (display, iKey); 1526 for (int i = 0; i < keysyms_per_keycode && !processed; i += 2) 1527 { 1528 KeySym ks = XKeycodeToKeysym(display, kc, i); 1529 char ch = 0; 1530 if (!XkbTranslateKeySym(display, &ks, 0, &ch, 1, NULL) == 1) 1531 ch = 0; 1532 if (ch) 1533 QChar c = QString::fromLocal8Bit(&ch, 1)[0]; 1534 } 1535 #elif defined (Q_WS_MAC) 1536 if (pUniKey && pUniKey[0] && !pUniKey[1]) 1537 processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode())); 1538 1539 /* Don't consider the hot key as pressed since the guest never saw 1540 * it. (probably a generic thing) */ 1541 m_pressedKeys[uScan] &= ~whatPressed; 1542 #endif 1543 1544 /* Grab the key from Qt if processed, or pass it to Qt otherwise 1545 * in order to process non-alphanumeric keys in event(), after they are 1546 * converted to Qt virtual keys. */ 1547 return processed; 1548 } 1549 1550 /* No more to do, if the host key is in action or the VM is paused: */ 1551 if (m_bIsHostkeyPressed || isHostKey || uisession()->isPaused()) 1552 { 1553 /* Grab the key from Qt and from VM if it's a host key, 1554 * otherwise just pass it to Qt */ 1555 return isHostKey; 1556 } 1557 1558 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 1559 Assert(!keyboard.isNull()); 1560 1561 #if defined (Q_WS_WIN32) 1562 /* send pending WM_PAINT events */ 1563 ::UpdateWindow(viewport()->winId()); 1564 #endif 1565 1566 std::vector <LONG> scancodes(codes, &codes[count]); 1567 keyboard.PutScancodes(QVector<LONG>::fromStdVector(scancodes)); 1568 1569 /* Grab the key from Qt: */ 1570 return true; 1571 } 1572 1573 bool UIMachineView::mouseEvent(int aType, const QPoint &aPos, const QPoint &aGlobalPos, 1574 Qt::MouseButtons aButtons, Qt::KeyboardModifiers /* aModifiers */, 1575 int aWheelDelta, Qt::Orientation aWheelDir) 1576 { 1577 int state = 0; 1578 if (aButtons & Qt::LeftButton) 1579 state |= KMouseButtonState_LeftButton; 1580 if (aButtons & Qt::RightButton) 1581 state |= KMouseButtonState_RightButton; 1582 if (aButtons & Qt::MidButton) 1583 state |= KMouseButtonState_MiddleButton; 1584 if (aButtons & Qt::XButton1) 1585 state |= KMouseButtonState_XButton1; 1586 if (aButtons & Qt::XButton2) 1587 state |= KMouseButtonState_XButton2; 1588 1589 #ifdef Q_WS_MAC 1590 /* Simulate the right click on Host+Left Mouse: */ 1591 if (m_bIsHostkeyPressed && 1592 m_bIsHostkeyAlone && 1593 state == KMouseButtonState_LeftButton) 1594 state = KMouseButtonState_RightButton; 1595 #endif /* Q_WS_MAC */ 1596 1597 int wheelVertical = 0; 1598 int wheelHorizontal = 0; 1599 if (aWheelDir == Qt::Vertical) 527 528 int iWheelVertical = 0; 529 int iWheelHorizontal = 0; 530 if (wheelDirection == Qt::Vertical) 1600 531 { 1601 532 /* The absolute value of wheel delta is 120 units per every wheel move; 1602 533 * positive deltas correspond to counterclockwize rotations (usually up), 1603 534 * negative deltas correspond to clockwize (usually down). */ 1604 wheelVertical = - (aWheelDelta / 120);1605 } 1606 else if ( aWheelDir== Qt::Horizontal)1607 wheelHorizontal = aWheelDelta / 120;535 iWheelVertical = - (wheelDelta / 120); 536 } 537 else if (wheelDirection == Qt::Horizontal) 538 iWheelHorizontal = wheelDelta / 120; 1608 539 1609 540 if (uisession()->isMouseCaptured()) 1610 541 { 1611 #ifdef Q_WS_WIN 32542 #ifdef Q_WS_WIN 1612 543 /* Send pending WM_PAINT events: */ 1613 ::UpdateWindow( viewport()->winId());544 ::UpdateWindow(m_viewports[uScreenId]->winId()); 1614 545 #endif 1615 546 1616 547 CMouse mouse = session().GetConsole().GetMouse(); 1617 mouse.PutMouseEvent(aGlobalPos.x() - m_lastMousePos.x(), 1618 aGlobalPos.y() - m_lastMousePos.y(), 1619 wheelVertical, wheelHorizontal, state); 1620 1621 #if defined (Q_WS_MAC) 1622 /* 1623 * Keep the mouse from leaving the widget. 1624 * 548 mouse.PutMouseEvent(globalPos.x() - m_lastMousePos.x(), 549 globalPos.y() - m_lastMousePos.y(), 550 iWheelVertical, iWheelHorizontal, iMouseButtonsState); 551 552 #ifdef Q_WS_MAC 553 /* Keep the mouse from leaving the widget. 1625 554 * This is a bit tricky to get right because if it escapes we won't necessarily 1626 555 * get mouse events any longer and can warp it back. So, we keep safety zone 1627 556 * of up to 300 pixels around the borders of the widget to prevent this from 1628 557 * happening. Also, the mouse is warped back to the center of the widget. 1629 * 1630 * (Note, aPos seems to be unreliable, it caused endless recursion here at one points...) 1631 * (Note, synergy and other remote clients might not like this cursor warping.) 1632 */ 1633 QRect rect = viewport()->visibleRegion().boundingRect(); 1634 QPoint pw = viewport()->mapToGlobal(viewport()->pos()); 558 * (Note, relativePos seems to be unreliable, it caused endless recursion here at one points...) 559 * (Note, synergy and other remote clients might not like this cursor warping.) */ 560 QRect rect = m_viewports[uScreenId]->visibleRegion().boundingRect(); 561 QPoint pw = m_viewports[uScreenId]->mapToGlobal(m_viewports[uScreenId]->pos()); 1635 562 rect.translate(pw.x(), pw.y()); 1636 563 1637 QRect dpRect = QApplication::desktop()->screenGeometry( viewport());1638 if (rect.intersects 564 QRect dpRect = QApplication::desktop()->screenGeometry(m_viewports[uScreenId]); 565 if (rect.intersects(dpRect)) 1639 566 rect = rect.intersect(dpRect); 1640 567 1641 int wsafe = rect.width() / 6;1642 rect.setWidth(rect.width() - wsafe * 2);1643 rect.setLeft(rect.left() + wsafe);1644 1645 int hsafe = rect.height() / 6;1646 rect.setWidth(rect.height() - hsafe * 2);1647 rect.setTop(rect.top() + hsafe);1648 1649 if (rect.contains( aGlobalPos, true))1650 m_lastMousePos = aGlobalPos;568 int iWsafe = rect.width() / 6; 569 rect.setWidth(rect.width() - iWsafe * 2); 570 rect.setLeft(rect.left() + iWsafe); 571 572 int iHsafe = rect.height() / 6; 573 rect.setWidth(rect.height() - iHsafe * 2); 574 rect.setTop(rect.top() + iHsafe); 575 576 if (rect.contains(globalPos, true)) 577 m_lastMousePos = globalPos; 1651 578 else 1652 579 { … … 1654 581 QCursor::setPos(m_lastMousePos); 1655 582 } 1656 #else /* !Q_WS_MAC */ 1657 1658 /* "jerk" the mouse by bringing it to the opposite side 1659 * to simulate the endless moving */ 1660 1661 # ifdef Q_WS_WIN32 1662 int we = viewport()->width() - 1; 1663 int he = viewport()->height() - 1; 1664 QPoint p = aPos; 1665 if (aPos.x() == 0) 1666 p.setX(we - 1); 1667 else if (aPos.x() == we) 583 #else /* Q_WS_MAC */ 584 585 /* Bringing mouse to the opposite side to simulate the endless moving: */ 586 587 # ifdef Q_WS_WIN 588 int iWe = m_viewports[uScreenId]->width() - 1; 589 int iHe = m_viewports[uScreenId]->height() - 1; 590 QPoint p = relativePos; 591 if (relativePos.x() == 0) 592 p.setX(iWe - 1); 593 else if (relativePos.x() == iWe) 1668 594 p.setX(1); 1669 if ( aPos.y() == 0 )1670 p.setY( he - 1);1671 else if ( aPos.y() == he)595 if (relativePos.y() == 0 ) 596 p.setY(iHe - 1); 597 else if (relativePos.y() == iHe) 1672 598 p.setY(1); 1673 599 1674 if (p != aPos)1675 { 1676 m_lastMousePos = viewport()->mapToGlobal(p);600 if (p != relativePos) 601 { 602 m_lastMousePos = m_viewports[uScreenId]->mapToGlobal(p); 1677 603 QCursor::setPos(m_lastMousePos); 1678 604 } 1679 605 else 1680 606 { 1681 m_lastMousePos = aGlobalPos;1682 } 1683 # else 1684 int we = QApplication::desktop()->width() - 1;1685 int he = QApplication::desktop()->height() - 1;1686 QPoint p = aGlobalPos;1687 if ( aGlobalPos.x() == 0)1688 p.setX (we - 1);1689 else if ( aGlobalPos.x() == we)607 m_lastMousePos = globalPos; 608 } 609 # else /* Q_WS_WIN */ 610 int iWe = QApplication::desktop()->width() - 1; 611 int iHe = QApplication::desktop()->height() - 1; 612 QPoint p = globalPos; 613 if (globalPos.x() == 0) 614 p.setX(iWe - 1); 615 else if (globalPos.x() == iWe) 1690 616 p.setX( 1 ); 1691 if ( aGlobalPos.y() == 0)1692 p.setY (he - 1);1693 else if ( aGlobalPos.y() == he)1694 p.setY 1695 1696 if (p != aGlobalPos)617 if (globalPos.y() == 0) 618 p.setY(iHe - 1); 619 else if (globalPos.y() == iHe) 620 p.setY(1); 621 622 if (p != globalPos) 1697 623 { 1698 624 m_lastMousePos = p; … … 1701 627 else 1702 628 { 1703 m_lastMousePos = aGlobalPos;1704 } 1705 # endif 629 m_lastMousePos = globalPos; 630 } 631 # endif /* !Q_WS_WIN */ 1706 632 #endif /* !Q_WS_MAC */ 1707 633 return true; /* stop further event handling */ … … 1709 635 else /* !uisession()->isMouseCaptured() */ 1710 636 { 1711 #if 0 // TODO: Move that to fullscreen event-h jadler:1712 if ( mode() != VBoxDefs::SDLMode)637 #if 0 // TODO: Move that to fullscreen event-handler: 638 if (vboxGlobal().vmRenderMode() != VBoxDefs::SDLMode) 1713 639 { 1714 640 /* try to automatically scroll the guest canvas if the … … 1716 642 /// @todo (r=dmik) better use a timer for autoscroll 1717 643 QRect scrGeo = QApplication::desktop()->screenGeometry (this); 1718 int dx = 0, dy = 0;644 int iDx = 0, iDy = 0; 1719 645 if (scrGeo.width() < contentsWidth()) 1720 646 { 1721 if (scrGeo.left() == aGlobalPos.x()) dx = -1;1722 if (scrGeo.right() == aGlobalPos.x()) dx = +1;647 if (scrGeo.left() == globalPos.x()) iDx = -1; 648 if (scrGeo.right() == globalPos.x()) iDx = +1; 1723 649 } 1724 650 if (scrGeo.height() < contentsHeight()) 1725 651 { 1726 if (scrGeo.top() == aGlobalPos.y()) dy = -1;1727 if (scrGeo.bottom() == aGlobalPos.y()) dy = +1;652 if (scrGeo.top() == globalPos.y()) iDy = -1; 653 if (scrGeo.bottom() == globalPos.y()) iDy = +1; 1728 654 } 1729 if ( dx || dy)1730 scrollBy( dx, dy);655 if (iDx || iDy) 656 scrollBy(iDx, iDy); 1731 657 } 1732 658 #endif … … 1734 660 if (uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()) 1735 661 { 1736 int cw = contentsWidth(), ch =contentsHeight();1737 int vw = visibleWidth(), vh =visibleHeight();1738 1739 if ( mode() != VBoxDefs::SDLMode)662 int iCw = m_views[uScreenId]->contentsWidth(), iCh = m_views[uScreenId]->contentsHeight(); 663 int iVw = m_views[uScreenId]->visibleWidth(), iVh = m_views[uScreenId]->visibleHeight(); 664 665 if (vboxGlobal().vmRenderMode() != VBoxDefs::SDLMode) 1740 666 { 1741 667 /* Try to automatically scroll the guest canvas if the 1742 668 * mouse goes outside its visible part: */ 1743 int dx = 0;1744 if ( aPos.x() > vw) dx = aPos.x() - vw;1745 else if ( aPos.x() < 0) dx = aPos.x();1746 int dy = 0;1747 if ( aPos.y() > vh) dy = aPos.y() - vh;1748 else if ( aPos.y() < 0) dy = aPos.y();1749 if ( dx != 0 || dy != 0) scrollBy (dx, dy);669 int iDx = 0; 670 if (relativePos.x() > iVw) iDx = relativePos.x() - iVw; 671 else if (relativePos.x() < 0) iDx = relativePos.x(); 672 int iDy = 0; 673 if (relativePos.y() > iVh) iDy = relativePos.y() - iVh; 674 else if (relativePos.y() < 0) iDy = relativePos.y(); 675 if (iDx != 0 || iDy != 0) m_views[uScreenId]->scrollBy(iDx, iDy); 1750 676 } 1751 677 1752 QPoint cpnt = viewportToContents(aPos);678 QPoint cpnt = m_views[uScreenId]->viewportToContents(relativePos); 1753 679 if (cpnt.x() < 0) cpnt.setX(0); 1754 else if (cpnt.x() > cw - 1) cpnt.setX(cw - 1);680 else if (cpnt.x() > iCw - 1) cpnt.setX(iCw - 1); 1755 681 if (cpnt.y() < 0) cpnt.setY(0); 1756 else if (cpnt.y() > ch - 1) cpnt.setY(ch - 1); 1757 1758 // TODO: Where to put that actually? 682 else if (cpnt.y() > iCh - 1) cpnt.setY(iCh - 1); 683 1759 684 /* Get & Setup absolute-event shift: */ 1760 685 CFramebuffer framebuffer; 1761 686 LONG xShift = 0, yShift = 0; 1762 session().GetConsole().GetDisplay().GetFramebuffer( screenId(), framebuffer, xShift, yShift);687 session().GetConsole().GetDisplay().GetFramebuffer(uScreenId, framebuffer, xShift, yShift); 1763 688 cpnt.setX(cpnt.x() + xShift); 1764 689 cpnt.setY(cpnt.y() + yShift); 1765 690 1766 691 CMouse mouse = session().GetConsole().GetMouse(); 1767 // AssertMsgFailed(("x=%d, y=%d", cpnt.x(), cpnt.y())); // this shows what absolute coordinates are correct! 1768 mouse.PutMouseEventAbsolute(cpnt.x() + 1, cpnt.y() + 1, wheelVertical, wheelHorizontal, state); 692 mouse.PutMouseEventAbsolute(cpnt.x() + 1, cpnt.y() + 1, iWheelVertical, iWheelHorizontal, iMouseButtonsState); 1769 693 return true; 1770 694 } 1771 695 else 1772 696 { 1773 if ( hasFocus() && (aType == QEvent::MouseButtonRelease && aButtons == Qt::NoButton))697 if (m_views[uScreenId]->hasFocus() && (iEventType == QEvent::MouseButtonRelease && mouseButtons == Qt::NoButton)) 1774 698 { 1775 699 if (uisession()->isPaused()) … … 1781 705 /* Temporarily disable auto capture that will take place after this dialog is dismissed because 1782 706 * the capture state is to be defined by the dialog result itself: */ 1783 m_bIsAutoCaptureDisabled = true;707 uisession()->setAutoCaptureDisabled(true); 1784 708 bool autoConfirmed = false; 1785 709 bool ok = vboxProblem().confirmInputCapture(&autoConfirmed); 1786 710 if (autoConfirmed) 1787 m_bIsAutoCaptureDisabled = false;711 uisession()->setAutoCaptureDisabled(false); 1788 712 /* Otherwise, the disable flag will be reset in the next console view's foucs in event (since 1789 713 * may happen asynchronously on some platforms, after we return from this code): */ … … 1795 719 qApp->processEvents(); 1796 720 #endif 1797 captureKbd(true); 1798 captureMouse(true); 721 /* Actually that will be a call to keyboard-handler, not no machine-view, 722 * but now keyboard-handler is not implemented yet. */ 723 m_views[uScreenId]->captureKbd(true); 724 725 captureMouse(uScreenId); 1799 726 } 1800 727 } … … 1806 733 } 1807 734 1808 void UIMachineView::resizeEvent(QResizeEvent *pEvent) 1809 { 1810 updateSliders(); 1811 return QAbstractScrollArea::resizeEvent(pEvent); 1812 } 1813 1814 void UIMachineView::moveEvent(QMoveEvent *pEvent) 1815 { 1816 return QAbstractScrollArea::moveEvent(pEvent); 1817 } 1818 1819 void UIMachineView::paintEvent(QPaintEvent *pPaintEvent) 1820 { 1821 if (m_pauseShot.isNull()) 1822 { 1823 /* Delegate the paint function to the VBoxFrameBuffer interface: */ 1824 if (m_pFrameBuffer) 1825 m_pFrameBuffer->paintEvent(pPaintEvent); 1826 #ifdef Q_WS_MAC 1827 /* Update the dock icon if we are in the running state */ 1828 if (uisession()->isRunning()) 1829 updateDockIcon(); 1830 #endif /* Q_WS_MAC */ 735 #ifdef Q_WS_WIN 736 /* This method is actually required only because under win-host 737 * we do not really grab the mouse in case of capturing it: */ 738 void UIMouseHandler::updateMouseCursorClipping() 739 { 740 /* Check if such viewport is registered: */ 741 if (!m_viewports.contains(m_iMouseCaptureViewIndex)) 1831 742 return; 1832 } 1833 1834 #ifdef VBOX_GUI_USE_QUARTZ2D 1835 if (mode() == VBoxDefs::Quartz2DMode && m_pFrameBuffer) 1836 { 1837 m_pFrameBuffer->paintEvent(pPaintEvent); 1838 updateDockIcon(); 743 744 if (uisession()->isMouseCaptured()) 745 { 746 QWidget *pMachineViewViewport = m_viewports[m_iMouseCaptureViewIndex]; 747 QRect r = pMachineViewViewport->rect(); 748 r.moveTopLeft(pMachineViewViewport->mapToGlobal(QPoint(0, 0))); 749 RECT rect = { r.left(), r.top(), r.right() + 1, r.bottom() + 1 }; 750 ::ClipCursor(&rect); 1839 751 } 1840 752 else 1841 #endif /* VBOX_GUI_USE_QUARTZ2D */ 1842 { 1843 /* We have a snapshot for the paused state: */ 1844 QRect r = pPaintEvent->rect().intersect(viewport()->rect()); 1845 /* We have to disable paint on screen if we are using the regular painter: */ 1846 bool paintOnScreen = viewport()->testAttribute(Qt::WA_PaintOnScreen); 1847 viewport()->setAttribute(Qt::WA_PaintOnScreen, false); 1848 QPainter pnt(viewport()); 1849 pnt.drawPixmap(r.x(), r.y(), m_pauseShot, r.x() + contentsX(), r.y() + contentsY(), r.width(), r.height()); 1850 /* Restore the attribute to its previous state: */ 1851 viewport()->setAttribute(Qt::WA_PaintOnScreen, paintOnScreen); 1852 #ifdef Q_WS_MAC 1853 updateDockIcon(); 1854 #endif /* Q_WS_MAC */ 1855 } 1856 } 1857 1858 #if defined(Q_WS_WIN32) 1859 1860 LRESULT CALLBACK UIMachineView::lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) 1861 { 1862 if (gView && nCode == HC_ACTION && gView->winLowKeyboardEvent(wParam, *(KBDLLHOOKSTRUCT *)lParam)) 1863 return 1; 1864 1865 return CallNextHookEx(NULL, nCode, wParam, lParam); 1866 } 1867 1868 bool UIMachineView::winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event) 1869 { 1870 /* Sometimes it happens that Win inserts additional events on some key 1871 * press/release. For example, it prepends ALT_GR in German layout with 1872 * the VK_LCONTROL vkey with curious 0x21D scan code (seems to be necessary 1873 * to specially treat ALT_GR to enter additional chars to regular apps). 1874 * These events are definitely unwanted in VM, so filter them out. */ 1875 /* Note (michael): it also sometimes sends the VK_CAPITAL vkey with scan 1876 * code 0x23a. If this is not passed through then it is impossible to 1877 * cancel CapsLock on a French keyboard. I didn't find any other examples 1878 * of these strange events. Let's hope we are not missing anything else 1879 * of importance! */ 1880 if (hasFocus() && (event.scanCode & ~0xFF)) 1881 { 1882 if (event.vkCode == VK_CAPITAL) 1883 return false; 1884 else 1885 return true; 1886 } 1887 1888 if (!m_bIsKeyboardCaptured) 1889 return false; 1890 1891 /* it's possible that a key has been pressed while the keyboard was not 1892 * captured, but is being released under the capture. Detect this situation 1893 * and return false to let Windows process the message normally and update 1894 * its key state table (to avoid the stuck key effect). */ 1895 uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) ? IsExtKeyPressed : IsKeyPressed; 1896 if ((event.flags & 0x80) /* released */ && 1897 ((event.vkCode == m_globalSettings.hostKey() && !m_bIsHostkeyInCapture) || 1898 (m_pressedKeys[event.scanCode] & (IsKbdCaptured | what_pressed)) == what_pressed)) 1899 return false; 1900 1901 MSG message; 1902 message.hwnd = winId(); 1903 message.message = msg; 1904 message.wParam = event.vkCode; 1905 message.lParam = 1 | (event.scanCode & 0xFF) << 16 | (event.flags & 0xFF) << 24; 1906 1907 /* Windows sets here the extended bit when the Right Shift key is pressed, 1908 * which is totally wrong. Undo it. */ 1909 if (event.vkCode == VK_RSHIFT) 1910 message.lParam &= ~0x1000000; 1911 1912 /* we suppose here that this hook is always called on the main GUI thread */ 1913 long dummyResult; 1914 return winEvent(&message, &dummyResult); 1915 } 1916 1917 bool UIMachineView::winEvent(MSG *aMsg, long* /* aResult */) 1918 { 1919 if (!(aMsg->message == WM_KEYDOWN || aMsg->message == WM_SYSKEYDOWN || 1920 aMsg->message == WM_KEYUP || aMsg->message == WM_SYSKEYUP)) 1921 return false; 1922 1923 /* Check for the special flag possibly set at the end of this function */ 1924 if (aMsg->lParam & (0x1 << 25)) 1925 { 1926 aMsg->lParam &= ~(0x1 << 25); 1927 return false; 1928 } 1929 1930 int scan = (aMsg->lParam >> 16) & 0x7F; 1931 /* scancodes 0x80 and 0x00 are ignored */ 1932 if (!scan) 1933 return true; 1934 1935 int vkey = aMsg->wParam; 1936 1937 /* When one of the SHIFT keys is held and one of the cursor movement 1938 * keys is pressed, Windows duplicates SHIFT press/release messages, 1939 * but with the virtual key code set to 0xFF. These virtual keys are also 1940 * sent in some other situations (Pause, PrtScn, etc.). Ignore such 1941 * messages. */ 1942 if (vkey == 0xFF) 1943 return true; 1944 1945 int flags = 0; 1946 if (aMsg->lParam & 0x1000000) 1947 flags |= KeyExtended; 1948 if (!(aMsg->lParam & 0x80000000)) 1949 flags |= KeyPressed; 1950 1951 switch (vkey) 1952 { 1953 case VK_SHIFT: 1954 case VK_CONTROL: 1955 case VK_MENU: 1956 { 1957 /* overcome stupid Win32 modifier key generalization */ 1958 int keyscan = scan; 1959 if (flags & KeyExtended) 1960 keyscan |= 0xE000; 1961 switch (keyscan) 1962 { 1963 case 0x002A: vkey = VK_LSHIFT; break; 1964 case 0x0036: vkey = VK_RSHIFT; break; 1965 case 0x001D: vkey = VK_LCONTROL; break; 1966 case 0xE01D: vkey = VK_RCONTROL; break; 1967 case 0x0038: vkey = VK_LMENU; break; 1968 case 0xE038: vkey = VK_RMENU; break; 1969 } 1970 break; 1971 } 1972 case VK_NUMLOCK: 1973 /* Win32 sets the extended bit for the NumLock key. Reset it. */ 1974 flags &= ~KeyExtended; 1975 break; 1976 case VK_SNAPSHOT: 1977 flags |= KeyPrint; 1978 break; 1979 case VK_PAUSE: 1980 flags |= KeyPause; 1981 break; 1982 } 1983 1984 bool result = keyEvent(vkey, scan, flags); 1985 if (!result && m_bIsKeyboardCaptured) 1986 { 1987 /* keyEvent() returned that it didn't process the message, but since the 1988 * keyboard is captured, we don't want to pass it to Windows. We just want 1989 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 1990 * shortcuts for example). So send it direcltly to the window with the 1991 * special flag in the reserved area of lParam (to avoid recursion). */ 1992 ::SendMessage(aMsg->hwnd, aMsg->message, 1993 aMsg->wParam, aMsg->lParam | (0x1 << 25)); 1994 return true; 1995 } 1996 1997 /* These special keys have to be handled by Windows as well to update the 1998 * internal modifier state and to enable/disable the keyboard LED */ 1999 if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT) 2000 return false; 2001 2002 return result; 2003 } 2004 2005 #elif defined(Q_WS_PM) 2006 2007 bool UIMachineView::pmEvent(QMSG *aMsg) 2008 { 2009 if (aMsg->msg == UM_PREACCEL_CHAR) 2010 { 2011 /* We are inside the input hook 2012 * let the message go through the normal system pipeline. */ 2013 if (!m_bIsKeyboardCaptured) 2014 return false; 2015 } 2016 2017 if (aMsg->msg != WM_CHAR && aMsg->msg != UM_PREACCEL_CHAR) 2018 return false; 2019 2020 /* check for the special flag possibly set at the end of this function */ 2021 if (SHORT2FROMMP(aMsg->mp2) & 0x8000) 2022 { 2023 aMsg->mp2 = MPFROM2SHORT(SHORT1FROMMP(aMsg->mp2), SHORT2FROMMP(aMsg->mp2) & ~0x8000); 2024 return false; 2025 } 2026 2027 USHORT ch = SHORT1FROMMP(aMsg->mp2); 2028 USHORT f = SHORT1FROMMP(aMsg->mp1); 2029 2030 int scan = (unsigned int)CHAR4FROMMP(aMsg->mp1); 2031 if (!scan || scan > 0x7F) 2032 return true; 2033 2034 int vkey = QIHotKeyEdit::virtualKey(aMsg); 2035 2036 int flags = 0; 2037 2038 if ((ch & 0xFF) == 0xE0) 2039 { 2040 flags |= KeyExtended; 2041 scan = ch >> 8; 2042 } 2043 else if (scan == 0x5C && (ch & 0xFF) == '/') 2044 { 2045 /* this is the '/' key on the keypad */ 2046 scan = 0x35; 2047 flags |= KeyExtended; 2048 } 2049 else 2050 { 2051 /* For some keys, the scan code passed in QMSG is a pseudo scan 2052 * code. We replace it with a real hardware scan code, according to 2053 * http://www.computer-engineering.org/ps2keyboard/scancodes1.html. 2054 * Also detect Pause and PrtScn and set flags. */ 2055 switch (vkey) 2056 { 2057 case VK_ENTER: scan = 0x1C; flags |= KeyExtended; break; 2058 case VK_CTRL: scan = 0x1D; flags |= KeyExtended; break; 2059 case VK_ALTGRAF: scan = 0x38; flags |= KeyExtended; break; 2060 case VK_LWIN: scan = 0x5B; flags |= KeyExtended; break; 2061 case VK_RWIN: scan = 0x5C; flags |= KeyExtended; break; 2062 case VK_WINMENU: scan = 0x5D; flags |= KeyExtended; break; 2063 case VK_FORWARD: scan = 0x69; flags |= KeyExtended; break; 2064 case VK_BACKWARD: scan = 0x6A; flags |= KeyExtended; break; 2065 #if 0 2066 /// @todo this would send 0xE0 0x46 0xE0 0xC6. It's not fully 2067 // clear what is more correct 2068 case VK_BREAK: scan = 0x46; flags |= KeyExtended; break; 2069 #else 2070 case VK_BREAK: scan = 0; flags |= KeyPause; break; 2071 #endif 2072 case VK_PAUSE: scan = 0; flags |= KeyPause; break; 2073 case VK_PRINTSCRN: scan = 0; flags |= KeyPrint; break; 2074 default:; 2075 } 2076 } 2077 2078 if (!(f & KC_KEYUP)) 2079 flags |= KeyPressed; 2080 2081 bool result = keyEvent (vkey, scan, flags); 2082 if (!result && m_bIsKeyboardCaptured) 2083 { 2084 /* keyEvent() returned that it didn't process the message, but since the 2085 * keyboard is captured, we don't want to pass it to PM. We just want 2086 * to let Qt process the message (to handle non-alphanumeric <HOST>+key 2087 * shortcuts for example). So send it direcltly to the window with the 2088 * special flag in the reserved area of lParam (to avoid recursion). */ 2089 ::WinSendMsg (aMsg->hwnd, WM_CHAR, aMsg->mp1, 2090 MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), SHORT2FROMMP (aMsg->mp2) | 0x8000)); 2091 return true; 2092 } 2093 return result; 2094 } 2095 2096 #elif defined(Q_WS_X11) 2097 2098 static Bool VBoxConsoleViewCompEvent(Display *, XEvent *pEvent, XPointer pvArg) 2099 { 2100 XEvent *pKeyEvent = (XEvent*)pvArg; 2101 if ((pEvent->type == XKeyPress) && (pEvent->xkey.keycode == pKeyEvent->xkey.keycode)) 2102 return True; 2103 else 2104 return False; 2105 } 2106 2107 bool UIMachineView::x11Event(XEvent *pEvent) 2108 { 2109 switch (pEvent->type) 2110 { 2111 /* We have to handle XFocusOut right here as this event is not passed 2112 * to UIMachineView::event(). Handling this event is important for 2113 * releasing the keyboard before the screen saver gets active. 2114 * 2115 * See public ticket #3894: Apparently this makes problems with newer 2116 * versions of Qt and this hack is probably not necessary anymore. 2117 * So disable it for Qt >= 4.5.0. */ 2118 case XFocusOut: 2119 case XFocusIn: 2120 if (uisession()->isRunning()) 2121 { 2122 if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0)) 2123 focusEvent (pEvent->type == XFocusIn); 2124 } 2125 return false; 2126 case XKeyPress: 2127 case XKeyRelease: 2128 break; 2129 default: 2130 return false; /* pass the event to Qt */ 2131 } 2132 2133 /* Translate the keycode to a PC scan code. */ 2134 unsigned scan = handleXKeyEvent(pEvent); 2135 2136 /* scancodes 0x00 (no valid translation) and 0x80 are ignored */ 2137 if (!scan & 0x7F) 2138 return true; 2139 2140 /* Fix for http://www.virtualbox.org/ticket/1296: 2141 * when X11 sends events for repeated keys, it always inserts an 2142 * XKeyRelease before the XKeyPress. */ 2143 XEvent returnEvent; 2144 if ((pEvent->type == XKeyRelease) && (XCheckIfEvent(pEvent->xkey.display, &returnEvent, 2145 VBoxConsoleViewCompEvent, (XPointer)pEvent) == True)) 2146 { 2147 XPutBackEvent(pEvent->xkey.display, &returnEvent); 2148 /* Discard it, don't pass it to Qt. */ 2149 return true; 2150 } 2151 2152 KeySym ks = ::XKeycodeToKeysym(pEvent->xkey.display, pEvent->xkey.keycode, 0); 2153 2154 int flags = 0; 2155 if (scan >> 8) 2156 flags |= KeyExtended; 2157 if (pEvent->type == XKeyPress) 2158 flags |= KeyPressed; 2159 2160 /* Remove the extended flag */ 2161 scan &= 0x7F; 2162 2163 switch (ks) 2164 { 2165 case XK_Print: 2166 flags |= KeyPrint; 2167 break; 2168 case XK_Pause: 2169 flags |= KeyPause; 2170 break; 2171 } 2172 2173 return keyEvent(ks, scan, flags); 2174 } 2175 2176 #elif defined(Q_WS_MAC) 2177 2178 bool UIMachineView::darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent) 2179 { 2180 bool ret = false; 2181 UInt32 EventKind = ::GetEventKind(inEvent); 2182 if (EventKind != kEventRawKeyModifiersChanged) 2183 { 2184 /* convert keycode to set 1 scan code. */ 2185 UInt32 keyCode = ~0U; 2186 ::GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode); 2187 unsigned scanCode = ::DarwinKeycodeToSet1Scancode(keyCode); 2188 if (scanCode) 2189 { 2190 /* calc flags. */ 2191 int flags = 0; 2192 if (EventKind != kEventRawKeyUp) 2193 flags |= KeyPressed; 2194 if (scanCode & VBOXKEY_EXTENDED) 2195 flags |= KeyExtended; 2196 /** @todo KeyPause, KeyPrint. */ 2197 scanCode &= VBOXKEY_SCANCODE_MASK; 2198 2199 /* get the unicode string (if present). */ 2200 AssertCompileSize(wchar_t, 2); 2201 AssertCompileSize(UniChar, 2); 2202 ByteCount cbWritten = 0; 2203 wchar_t ucs[8]; 2204 if (::GetEventParameter(inEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 2205 sizeof(ucs), &cbWritten, &ucs[0]) != 0) 2206 cbWritten = 0; 2207 ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */ 2208 2209 ret = keyEvent(keyCode, scanCode, flags, ucs[0] ? ucs : NULL); 2210 } 2211 } 2212 else 2213 { 2214 /* May contain multiple modifier changes, kind of annoying. */ 2215 UInt32 newMask = 0; 2216 ::GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32, NULL, 2217 sizeof(newMask), NULL, &newMask); 2218 newMask = ::DarwinAdjustModifierMask(newMask, pvCocoaEvent); 2219 UInt32 changed = newMask ^ m_darwinKeyModifiers; 2220 if (changed) 2221 { 2222 for (UInt32 bit = 0; bit < 32; bit++) 2223 { 2224 if (!(changed & (1 << bit))) 2225 continue; 2226 unsigned scanCode = ::DarwinModifierMaskToSet1Scancode(1 << bit); 2227 if (!scanCode) 2228 continue; 2229 unsigned keyCode = ::DarwinModifierMaskToDarwinKeycode(1 << bit); 2230 Assert(keyCode); 2231 2232 if (!(scanCode & VBOXKEY_LOCK)) 2233 { 2234 unsigned flags = (newMask & (1 << bit)) ? KeyPressed : 0; 2235 if (scanCode & VBOXKEY_EXTENDED) 2236 flags |= KeyExtended; 2237 scanCode &= VBOXKEY_SCANCODE_MASK; 2238 ret |= keyEvent(keyCode, scanCode & 0xff, flags); 2239 } 2240 else 2241 { 2242 unsigned flags = 0; 2243 if (scanCode & VBOXKEY_EXTENDED) 2244 flags |= KeyExtended; 2245 scanCode &= VBOXKEY_SCANCODE_MASK; 2246 keyEvent(keyCode, scanCode, flags | KeyPressed); 2247 keyEvent(keyCode, scanCode, flags); 2248 } 2249 } 2250 } 2251 2252 m_darwinKeyModifiers = newMask; 2253 2254 /* Always return true here because we'll otherwise getting a Qt event 2255 we don't want and that will only cause the Pause warning to pop up. */ 2256 ret = true; 2257 } 2258 2259 return ret; 2260 } 2261 2262 void UIMachineView::darwinGrabKeyboardEvents(bool fGrab) 2263 { 2264 m_fKeyboardGrabbed = fGrab; 2265 if (fGrab) 2266 { 2267 /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */ 2268 ::CGSetLocalEventsSuppressionInterval(0.0); 2269 setMouseCoalescingEnabled(false); 2270 2271 /* Register the event callback/hook and grab the keyboard. */ 2272 UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */, 2273 UIMachineView::darwinEventHandlerProc, this); 2274 2275 ::DarwinGrabKeyboard (false); 2276 } 2277 else 2278 { 2279 ::DarwinReleaseKeyboard(); 2280 UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */, 2281 UIMachineView::darwinEventHandlerProc, this); 2282 } 2283 } 2284 2285 bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser) 2286 { 2287 UIMachineView *view = (UIMachineView*)pvUser; 2288 EventRef inEvent = (EventRef)pvCarbonEvent; 2289 UInt32 eventClass = ::GetEventClass(inEvent); 2290 2291 /* Check if this is an application key combo. In that case we will not pass 2292 * the event to the guest, but let the host process it. */ 2293 if (::darwinIsApplicationCommand(pvCocoaEvent)) 2294 return false; 2295 2296 /* All keyboard class events needs to be handled. */ 2297 if (eventClass == kEventClassKeyboard) 2298 { 2299 if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent)) 2300 return true; 2301 } 2302 /* Pass the event along. */ 2303 return false; 2304 } 2305 2306 #endif 2307 2308 void UIMachineView::fixModifierState(LONG *piCodes, uint *puCount) 2309 { 2310 /* Synchronize the views of the host and the guest to the modifier keys. 2311 * This function will add up to 6 additional keycodes to codes. */ 2312 2313 #if defined(Q_WS_X11) 2314 2315 Window wDummy1, wDummy2; 2316 int iDummy3, iDummy4, iDummy5, iDummy6; 2317 unsigned uMask; 2318 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0; 2319 2320 uKeyMaskCaps = LockMask; 2321 XModifierKeymap* map = XGetModifierMapping(QX11Info::display()); 2322 KeyCode keyCodeNum = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock); 2323 KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock); 2324 2325 for (int i = 0; i < 8; ++ i) 2326 { 2327 if (keyCodeNum != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeNum) 2328 uKeyMaskNum = 1 << i; 2329 else if (keyCodeScroll != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeScroll) 2330 uKeyMaskScroll = 1 << i; 2331 } 2332 XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2, 2333 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask); 2334 XFreeModifiermap(map); 2335 2336 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(uMask & uKeyMaskNum))) 2337 { 2338 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1); 2339 piCodes[(*puCount)++] = 0x45; 2340 piCodes[(*puCount)++] = 0x45 | 0x80; 2341 } 2342 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(uMask & uKeyMaskCaps))) 2343 { 2344 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 2345 piCodes[(*puCount)++] = 0x3a; 2346 piCodes[(*puCount)++] = 0x3a | 0x80; 2347 /* Some keyboard layouts require shift to be pressed to break 2348 * capslock. For simplicity, only do this if shift is not 2349 * already held down. */ 2350 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 2351 { 2352 piCodes[(*puCount)++] = 0x2a; 2353 piCodes[(*puCount)++] = 0x2a | 0x80; 2354 } 2355 } 2356 2357 #elif defined(Q_WS_WIN32) 2358 2359 if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK)))) 2360 { 2361 uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1); 2362 piCodes[(*puCount)++] = 0x45; 2363 piCodes[(*puCount)++] = 0x45 | 0x80; 2364 } 2365 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL)))) 2366 { 2367 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 2368 piCodes[(*puCount)++] = 0x3a; 2369 piCodes[(*puCount)++] = 0x3a | 0x80; 2370 /* Some keyboard layouts require shift to be pressed to break 2371 * capslock. For simplicity, only do this if shift is not 2372 * already held down. */ 2373 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 2374 { 2375 piCodes[(*puCount)++] = 0x2a; 2376 piCodes[(*puCount)++] = 0x2a | 0x80; 2377 } 2378 } 2379 2380 #elif defined(Q_WS_MAC) 2381 2382 /* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */ 2383 if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock))) 2384 { 2385 uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1); 2386 piCodes[(*puCount)++] = 0x3a; 2387 piCodes[(*puCount)++] = 0x3a | 0x80; 2388 /* Some keyboard layouts require shift to be pressed to break 2389 * capslock. For simplicity, only do this if shift is not 2390 * already held down. */ 2391 if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed)) 2392 { 2393 piCodes[(*puCount)++] = 0x2a; 2394 piCodes[(*puCount)++] = 0x2a | 0x80; 2395 } 2396 } 2397 2398 #else 2399 2400 //#warning Adapt UIMachineView::fixModifierState 2401 2402 #endif 2403 } 2404 2405 QPoint UIMachineView::viewportToContents(const QPoint &vp) const 2406 { 2407 return QPoint(vp.x() + contentsX(), vp.y() + contentsY()); 2408 } 2409 2410 void UIMachineView::scrollBy(int dx, int dy) 2411 { 2412 horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx); 2413 verticalScrollBar()->setValue(verticalScrollBar()->value() + dy); 2414 } 2415 2416 #ifdef VBOX_WITH_VIDEOHWACCEL 2417 void UIMachineView::scrollContentsBy(int dx, int dy) 2418 { 2419 if (m_pFrameBuffer) 2420 { 2421 m_pFrameBuffer->viewportScrolled(dx, dy); 2422 } 2423 QAbstractScrollArea::scrollContentsBy(dx, dy); 2424 } 2425 #endif 2426 2427 void UIMachineView::emitKeyboardStateChanged() 2428 { 2429 emit keyboardStateChanged(keyboardState()); 2430 } 2431 2432 void UIMachineView::emitMouseStateChanged() 2433 { 2434 emit mouseStateChanged(mouseState()); 2435 } 2436 2437 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */) 2438 { 2439 if (m_bIsKeyboardCaptured == fCapture) 2440 return; 2441 2442 #if defined(Q_WS_WIN32) 2443 /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */ 2444 #elif defined(Q_WS_X11) 2445 /* On X11, we are using passive XGrabKey for normal (windowed) mode 2446 * instead of XGrabKeyboard (called by QWidget::grabKeyboard()) 2447 * because XGrabKeyboard causes a problem under metacity - a window cannot be moved 2448 * using the mouse if it is currently actively grabing the keyboard; 2449 * For static modes we are using usual (active) keyboard grabbing. */ 2450 switch (machineLogic()->visualStateType()) 2451 { 2452 /* If window is moveable we are making passive keyboard grab: */ 2453 case UIVisualStateType_Normal: 2454 { 2455 if (fCapture) 2456 XGrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync); 2457 else 2458 XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId()); 2459 break; 2460 } 2461 /* If window is NOT moveable we are making active keyboard grab: */ 2462 case UIVisualStateType_Fullscreen: 2463 case UIVisualStateType_Seamless: 2464 { 2465 if (fCapture) 2466 { 2467 /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager. 2468 * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times, 2469 * and after we will just ignore that issue: */ 2470 int cTriesLeft = 50; 2471 while (cTriesLeft && XGrabKeyboard(QX11Info::display(), machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; } 2472 } 2473 else 2474 XUngrabKeyboard(QX11Info::display(), CurrentTime); 2475 break; 2476 } 2477 /* Should we try to grab keyboard in default case? I think - NO. */ 2478 default: 2479 break; 2480 } 2481 #elif defined(Q_WS_MAC) 2482 /* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers 2483 * (for right/left separation). */ 2484 if (fCapture) 2485 { 2486 ::DarwinDisableGlobalHotKeys(true); 2487 grabKeyboard(); 2488 } 2489 else 2490 { 2491 ::DarwinDisableGlobalHotKeys(false); 2492 releaseKeyboard(); 2493 } 2494 #else 2495 if (fCapture) 2496 grabKeyboard(); 2497 else 2498 releaseKeyboard(); 2499 #endif 2500 2501 m_bIsKeyboardCaptured = fCapture; 2502 2503 if (fEmitSignal) 2504 emitKeyboardStateChanged(); 2505 } 2506 2507 void UIMachineView::captureMouse(bool fCapture, bool fEmitSignal /* = true */) 2508 { 2509 /* Do not change anything if its already so: */ 2510 if (uisession()->isMouseCaptured() == fCapture) 2511 return; 2512 2513 /* Store new mouse 'captured' state value: */ 2514 uisession()->setMouseCaptured(fCapture); 2515 2516 if (fCapture) 2517 { 2518 /* Memorize the host position where the cursor was captured: */ 2519 m_capturedMousePos = QCursor::pos(); 2520 #ifdef Q_WS_WIN32 2521 /* Remember what this window captured mouse: */ 2522 m_fItsMeWhoCapturedMouse = true; 2523 /* Move the mouse to the center of the visible area: */ 2524 m_lastMousePos = mapToGlobal(visibleRegion().boundingRect().center()); 2525 QCursor::setPos(m_lastMousePos); 2526 /* Update mouse clipping: */ 2527 updateMouseCursorClipping(); 2528 #elif defined (Q_WS_MAC) 2529 /* Move the mouse to the center of the visible area: */ 2530 m_lastMousePos = mapToGlobal(visibleRegion().boundingRect().center()); 2531 QCursor::setPos(m_lastMousePos); 2532 /* Grab all mouse events: */ 2533 viewport()->grabMouse(); 2534 #else 2535 /* Grab all mouse events: */ 2536 viewport()->grabMouse(); 2537 m_lastMousePos = QCursor::pos(); 2538 #endif 2539 } 2540 else 2541 { 2542 /* Return the cursor to where it was when we captured it: */ 2543 QCursor::setPos(m_capturedMousePos); 2544 } 2545 2546 /* Updating guest mouse: */ 2547 CMouse mouse = session().GetConsole().GetMouse(); 2548 mouse.PutMouseEvent(0, 0, 0, 0, 0); 2549 2550 /* Emit signal if required: */ 2551 if (fEmitSignal) 2552 emitMouseStateChanged(); 2553 } 2554 2555 void UIMachineView::saveKeyStates() 2556 { 2557 ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys)); 2558 } 2559 2560 void UIMachineView::releaseAllPressedKeys(bool aReleaseHostKey /* = true */) 2561 { 2562 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 2563 bool fSentRESEND = false; 2564 2565 /* Send a dummy scan code (RESEND) to prevent the guest OS from recognizing 2566 * a single key click (for ex., Alt) and performing an unwanted action 2567 * (for ex., activating the menu) when we release all pressed keys below. 2568 * Note, that it's just a guess that sending RESEND will give the desired 2569 * effect :), but at least it works with NT and W2k guests. */ 2570 for (uint i = 0; i < SIZEOF_ARRAY (m_pressedKeys); i++) 2571 { 2572 if (m_pressedKeys[i] & IsKeyPressed) 2573 { 2574 if (!fSentRESEND) 2575 { 2576 keyboard.PutScancode (0xFE); 2577 fSentRESEND = true; 2578 } 2579 keyboard.PutScancode(i | 0x80); 2580 } 2581 else if (m_pressedKeys[i] & IsExtKeyPressed) 2582 { 2583 if (!fSentRESEND) 2584 { 2585 keyboard.PutScancode(0xFE); 2586 fSentRESEND = true; 2587 } 2588 QVector <LONG> codes(2); 2589 codes[0] = 0xE0; 2590 codes[1] = i | 0x80; 2591 keyboard.PutScancodes(codes); 2592 } 2593 m_pressedKeys[i] = 0; 2594 } 2595 2596 if (aReleaseHostKey) 2597 m_bIsHostkeyPressed = false; 2598 2599 #ifdef Q_WS_MAC 2600 /* Clear most of the modifiers: */ 2601 m_darwinKeyModifiers &= 2602 alphaLock | kEventKeyModifierNumLockMask | 2603 (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (m_globalSettings.hostKey())); 2604 #endif 2605 2606 emitKeyboardStateChanged(); 2607 } 2608 2609 void UIMachineView::sendChangedKeyStates() 2610 { 2611 QVector <LONG> codes(2); 2612 CKeyboard keyboard = session().GetConsole().GetKeyboard(); 2613 for (uint i = 0; i < SIZEOF_ARRAY(m_pressedKeys); ++ i) 2614 { 2615 uint8_t os = m_pressedKeysCopy[i]; 2616 uint8_t ns = m_pressedKeys[i]; 2617 if ((os & IsKeyPressed) != (ns & IsKeyPressed)) 2618 { 2619 codes[0] = i; 2620 if (!(ns & IsKeyPressed)) 2621 codes[0] |= 0x80; 2622 keyboard.PutScancode(codes[0]); 2623 } 2624 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed)) 2625 { 2626 codes[0] = 0xE0; 2627 codes[1] = i; 2628 if (!(ns & IsExtKeyPressed)) 2629 codes[1] |= 0x80; 2630 keyboard.PutScancodes(codes); 2631 } 2632 } 2633 } 2634 2635 void UIMachineView::dimImage(QImage &img) 2636 { 2637 for (int y = 0; y < img.height(); ++ y) 2638 { 2639 if (y % 2) 2640 { 2641 if (img.depth() == 32) 2642 { 2643 for (int x = 0; x < img.width(); ++ x) 2644 { 2645 int gray = qGray(img.pixel (x, y)) / 2; 2646 img.setPixel(x, y, qRgb (gray, gray, gray)); 2647 } 2648 } 2649 else 2650 { 2651 ::memset(img.scanLine (y), 0, img.bytesPerLine()); 2652 } 2653 } 2654 else 2655 { 2656 if (img.depth() == 32) 2657 { 2658 for (int x = 0; x < img.width(); ++ x) 2659 { 2660 int gray = (2 * qGray (img.pixel (x, y))) / 3; 2661 img.setPixel(x, y, qRgb (gray, gray, gray)); 2662 } 2663 } 2664 } 2665 } 2666 } 2667 2668 #ifdef Q_WS_MAC 2669 CGImageRef UIMachineView::vmContentImage() 2670 { 2671 if (!m_pauseShot.isNull()) 2672 { 2673 CGImageRef pauseImg = ::darwinToCGImageRef(&m_pauseShot); 2674 /* Use the pause image as background */ 2675 return pauseImg; 2676 } 2677 else 2678 { 2679 # ifdef VBOX_GUI_USE_QUARTZ2D 2680 if (mode() == VBoxDefs::Quartz2DMode) 2681 { 2682 /* If the render mode is Quartz2D we could use the CGImageRef 2683 * of the framebuffer for the dock icon creation. This saves 2684 * some conversion time. */ 2685 CGImageRef image = static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef(); 2686 CGImageRetain(image); /* Retain it, cause the consumer will release it. */ 2687 return image; 2688 } 2689 else 2690 # endif /* VBOX_GUI_USE_QUARTZ2D */ 2691 /* In image mode we have to create the image ref out of the 2692 * framebuffer */ 2693 return frameBuffertoCGImageRef(m_pFrameBuffer); 2694 } 2695 return 0; 2696 } 2697 2698 CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer) 2699 { 2700 CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); 2701 Assert(cs); 2702 /* Create the image copy of the framebuffer */ 2703 CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL); 2704 Assert(dp); 2705 CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs, 2706 kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false, 2707 kCGRenderingIntentDefault); 2708 Assert(ir); 2709 CGDataProviderRelease(dp); 2710 CGColorSpaceRelease(cs); 2711 2712 return ir; 2713 } 2714 2715 void UIMachineView::updateDockIcon() 2716 { 2717 machineLogic()->updateDockIcon(); 2718 } 2719 2720 void UIMachineView::setMouseCoalescingEnabled(bool fOn) 2721 { 2722 /* Enable mouse event compression if we leave the VM view. This 2723 is necessary for having smooth resizing of the VM/other 2724 windows. 2725 Disable mouse event compression if we enter the VM view. So 2726 all mouse events are registered in the VM. Only do this if 2727 the keyboard/mouse is grabbed (this is when we have a valid 2728 event handler). */ 2729 if (fOn || m_fKeyboardGrabbed) 2730 ::darwinSetMouseCoalescingEnabled(fOn); 2731 } 2732 #endif /* Q_WS_MAC */ 2733 753 { 754 ::ClipCursor(NULL); 755 } 756 } 757 #endif /* Q_WS_WIN */ 758 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.h
r30291 r30408 2 2 * 3 3 * VBox frontends: Qt GUI ("VirtualBox"): 4 * UIM achineViewclass declaration4 * UIMouseHandler class declaration 5 5 */ 6 6 … … 17 17 */ 18 18 19 #ifndef ___UIM achineView_h___20 #define ___UIM achineView_h___19 #ifndef ___UIMouseHandler_h___ 20 #define ___UIMouseHandler_h___ 21 21 22 22 /* Global includes */ 23 #include <QAbstractScrollArea> 24 #include <QEventLoop> 23 #include <QObject> 24 #include <QPoint> 25 #include <QMap> 25 26 26 27 /* Local includes */ 27 #include "COMDefs.h"28 28 #include "UIMachineDefs.h" 29 29 30 #ifdef Q_WS_MAC 31 # include <CoreFoundation/CFBase.h> 32 #endif /* Q_WS_MAC */ 30 /* Global forwards */ 31 class QWidget; 33 32 34 33 /* Local forwards */ 34 class CSession; 35 35 class UISession; 36 class UIFrameBuffer;37 class UIMachineWindow;38 36 class UIMachineLogic; 39 class VBoxGlobalSettings;37 class UIMachineView; 40 38 41 class UIMachineView : public QAbstractScrollArea 39 /* Delegate to control VM mouse functionality: */ 40 class UIMouseHandler : public QObject 42 41 { 43 42 Q_OBJECT; … … 45 44 public: 46 45 47 /* Desktop geometry types: */ 48 enum DesktopGeo { DesktopGeo_Invalid = 0, DesktopGeo_Fixed, DesktopGeo_Automatic, DesktopGeo_Any }; 46 /* Factory functions to create/destroy mouse-handler: */ 47 static UIMouseHandler* create(UIMachineLogic *pMachineLogic, UIVisualStateType visualStateType); 48 static void destroy(UIMouseHandler *pMouseHandler); 49 49 50 /* Factory function to create required view sub-child: */ 51 static UIMachineView* create( UIMachineWindow *pMachineWindow 52 , VBoxDefs::RenderMode renderMode 53 #ifdef VBOX_WITH_VIDEOHWACCEL 54 , bool bAccelerate2DVideo 55 #endif 56 , UIVisualStateType visualStateType 57 , ulong uScreenId); 58 static void destroy(UIMachineView *pWhichView); 50 /* Registers/Remove new machine-view: */ 51 void addMachineView(ulong uViewIndex, UIMachineView *pMachineView); 52 void delMachineView(ulong uViewIndex); 59 53 60 /* Public getters: */ 61 int keyboardState() const; 54 /* Commands to capture/release mouse: */ 55 void captureMouse(ulong uScreenId); 56 void releaseMouse(); 57 58 /* Setter for mouse-integration feature: */ 59 void setMouseIntegrationEnabled(bool fEnabled); 60 61 /* Current mouse state: */ 62 62 int mouseState() const; 63 virtual QRegion lastVisibleRegion() const { return QRegion(); }64 65 /* Public setters: */66 virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {}67 virtual void setMouseIntegrationEnabled(bool fEnabled);68 69 /* Public members: */70 virtual void normalizeGeometry(bool /* bAdjustPosition = false */) = 0;71 63 72 64 signals: 73 65 74 /* Mouse/Keyboard state-change signals: */ 75 void keyboardStateChanged(int iState); 76 void mouseStateChanged(int iState); 66 /* Notifies listeners about mouse state-change: */ 67 void mouseStateChanged(int iNewState); 77 68 78 /* Utility signals: */ 79 void resizeHintDone(); 69 protected slots: 70 71 /* Machine state-change handler: */ 72 virtual void sltMachineStateChanged(); 73 74 /* Mouse capability-change handler: */ 75 virtual void sltMouseCapabilityChanged(); 76 77 /* Mouse pointer-shape-change handler: */ 78 virtual void sltMousePointerShapeChanged(); 80 79 81 80 protected: 82 81 83 /* Machine view constructor/destructor: */ 84 UIMachineView( UIMachineWindow *pMachineWindow 85 , VBoxDefs::RenderMode renderMode 86 #ifdef VBOX_WITH_VIDEOHWACCEL 87 , bool bAccelerate2DVideo 88 #endif 89 , ulong uScreenId); 90 virtual ~UIMachineView(); 82 /* Mouse-handler constructor/destructor: */ 83 UIMouseHandler(UIMachineLogic *pMachineLogic); 84 virtual ~UIMouseHandler(); 91 85 92 /* Protected getters: */ 86 /* Getters: */ 87 UIMachineLogic* machineLogic() const; 93 88 UISession* uisession() const; 94 CSession& session(); 95 QSize sizeHint() const; 96 int contentsX() const; 97 int contentsY() const; 98 int contentsWidth() const; 99 int contentsHeight() const; 100 int visibleWidth() const; 101 int visibleHeight() const; 102 VBoxDefs::RenderMode mode() const { return m_mode; } 103 ulong screenId() const { return m_uScreenId; } 104 UIFrameBuffer* frameBuffer() const { return m_pFrameBuffer; } 105 UIMachineWindow* machineWindowWrapper() const { return m_pMachineWindow; } 106 UIMachineLogic* machineLogic() const; 107 bool isHostKeyPressed() const { return m_bIsHostkeyPressed; } 108 bool isMachineWindowResizeIgnored() const { return m_bIsMachineWindowResizeIgnored; } 109 const QPixmap& pauseShot() const { return m_pauseShot; } 110 QSize storedConsoleSize() const { return m_storedConsoleSize; } 111 DesktopGeo desktopGeometryType() const { return m_desktopGeometryType; } 112 QSize desktopGeometry() const; 113 QSize guestSizeHint(); 89 CSession& session() const; 114 90 115 /* Protected setters: */ 116 void setDesktopGeometry(DesktopGeo geometry, int iWidth, int iHeight); 117 void storeConsoleSize(int iWidth, int iHeight); 118 void setMachineWindowResizeIgnored(bool fIgnore = true) { m_bIsMachineWindowResizeIgnored = fIgnore; } 119 void storeGuestSizeHint(const QSize &sizeHint); 120 121 /* Protected helpers: */ 122 void updateMouseCursorShape(); 123 #ifdef Q_WS_WIN32 124 void updateMouseCursorClipping(); 125 #endif 126 virtual QRect workingArea() = 0; 127 virtual void calculateDesktopGeometry() = 0; 128 virtual void maybeRestrictMinimumSize() = 0; 129 virtual void updateSliders(); 130 131 #ifdef Q_WS_MAC 132 void updateDockIcon(); 133 void setMouseCoalescingEnabled(bool fOn); 134 CGImageRef vmContentImage(); 135 CGImageRef frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer); 136 #endif /* Q_WS_MAC */ 137 138 /* Prepare routines: */ 139 virtual void prepareFrameBuffer(); 140 virtual void prepareCommon(); 141 virtual void prepareFilters(); 142 virtual void prepareConsoleConnections(); 143 virtual void loadMachineViewSettings(); 144 145 /* Cleanup routines: */ 146 //virtual void saveMachineViewSettings() {} 147 //virtual void cleanupConsoleConnections() {} 148 //virtual void cleanupFilters() {} 149 virtual void cleanupCommon(); 150 virtual void cleanupFrameBuffer(); 151 152 /* Cross-platforms event processors: */ 153 bool event(QEvent *pEvent); 91 /* Event handler for registered machine-view(s): */ 154 92 bool eventFilter(QObject *pWatched, QEvent *pEvent); 155 93 156 /* Protected variables: */ 157 QSize m_desktopGeometry; 94 /* Separate function to handle most of existing mouse-events: */ 95 bool mouseEvent(int iEventType, ulong uScreenId, 96 const QPoint &relativePos, const QPoint &globalPos, 97 Qt::MouseButtons mouseButtons, 98 int wheelDelta, Qt::Orientation wheelDirection); 158 99 159 protected slots: 100 #ifdef Q_WS_WIN 101 /* This method is actually required only because under win-host 102 * we do not really grab the mouse in case of capturing it: */ 103 void updateMouseCursorClipping(); 104 #endif /* Q_WS_WIN */ 160 105 161 /* Console callback handlers: */ 162 virtual void sltMachineStateChanged(); 163 virtual void sltMousePointerShapeChanged(); 164 virtual void sltMouseCapabilityChanged(); 165 virtual void sltPerformGuestResize(const QSize & /* toSize */) {}; 106 /* Machine logic parent: */ 107 UIMachineLogic *m_pMachineLogic; 166 108 167 /* Session callback handlers: */ 168 virtual void sltMouseCapturedStatusChanged(); 109 /* Registered machine-view(s): */ 110 QMap<ulong, UIMachineView*> m_views; 111 /* Registered machine-view-viewport(s): */ 112 QMap<ulong, QWidget*> m_viewports; 169 113 170 /* Various helper slots: */ 171 virtual void sltNormalizeGeometry() { normalizeGeometry(true); } 172 173 private: 174 175 /* Cross-platforms event processors: */ 176 void focusEvent(bool aHasFocus, bool aReleaseHostKey = true); 177 bool keyEvent(int aKey, uint8_t aScan, int aFlags, wchar_t *aUniKey = NULL); 178 bool mouseEvent(int aType, const QPoint &aPos, const QPoint &aGlobalPos, 179 Qt::MouseButtons aButtons, Qt::KeyboardModifiers aModifiers, 180 int aWheelDelta, Qt::Orientation aWheelDir); 181 void resizeEvent(QResizeEvent *pEvent); 182 void moveEvent(QMoveEvent *pEvent); 183 void paintEvent(QPaintEvent *pEvent); 184 185 /* Platform specific event processors: */ 186 #if defined(Q_WS_WIN32) 187 static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam); 188 bool winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event); 189 bool winEvent(MSG *aMsg, long *aResult); 190 #elif defined(Q_WS_PM) 191 bool pmEvent(QMSG *aMsg); 192 #elif defined(Q_WS_X11) 193 bool x11Event(XEvent *event); 194 #elif defined(Q_WS_MAC) 195 bool darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent); 196 void darwinGrabKeyboardEvents(bool fGrab); 197 static bool darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser); 198 #endif 199 200 /* Private helpers: */ 201 void fixModifierState(LONG *piCodes, uint *puCount); 202 QPoint viewportToContents(const QPoint &vp) const; 203 void scrollBy(int dx, int dy); 204 #ifdef VBOX_WITH_VIDEOHWACCEL 205 void scrollContentsBy(int dx, int dy); 206 #endif 207 void emitKeyboardStateChanged(); 208 void emitMouseStateChanged(); 209 void captureKbd(bool fCapture, bool fEmitSignal = true); 210 void captureMouse(bool fCapture, bool fEmitSignal = true); 211 void saveKeyStates(); 212 void releaseAllPressedKeys(bool aReleaseHostKey = true); 213 void sendChangedKeyStates(); 214 215 static void dimImage(QImage &img); 216 217 /* Private members: */ 218 UIMachineWindow *m_pMachineWindow; 219 VBoxDefs::RenderMode m_mode; 220 ulong m_uScreenId; 221 const VBoxGlobalSettings &m_globalSettings; 222 UIFrameBuffer *m_pFrameBuffer; 223 KMachineState m_previousState; 224 225 DesktopGeo m_desktopGeometryType; 226 QSize m_storedConsoleSize; 227 114 /* Other mouse variables: */ 228 115 QPoint m_lastMousePos; 229 116 QPoint m_capturedMousePos; 230 117 int m_iLastMouseWheelDelta; 231 232 uint8_t m_pressedKeys[128]; 233 uint8_t m_pressedKeysCopy[128]; 234 235 bool m_bIsAutoCaptureDisabled : 1; 236 bool m_bIsKeyboardCaptured : 1; 237 bool m_bIsHostkeyPressed : 1; 238 bool m_bIsHostkeyAlone : 1; 239 bool m_bIsHostkeyInCapture : 1; 240 bool m_bIsMachineWindowResizeIgnored : 1; 241 bool m_fPassCAD : 1; 242 #ifdef VBOX_WITH_VIDEOHWACCEL 243 bool m_fAccelerate2DVideo; 244 #endif 245 246 #ifdef Q_WS_WIN 247 bool m_fItsMeWhoCapturedMouse; 248 #endif /* Q_WS_WIN */ 249 #ifdef Q_WS_MAC 250 /** The current modifier key mask. Used to figure out which modifier 251 * key was pressed when we get a kEventRawKeyModifiersChanged event. */ 252 UInt32 m_darwinKeyModifiers; 253 bool m_fKeyboardGrabbed; 254 #endif /* Q_WS_MAC */ 255 256 QPixmap m_pauseShot; 257 258 /* Friend classes: */ 259 friend class UIMachineLogic; 260 friend class UIFrameBuffer; 261 friend class UIFrameBufferQImage; 262 friend class UIFrameBufferQuartz2D; 263 friend class UIFrameBufferQGL; 264 template<class, class, class> friend class VBoxOverlayFrameBuffer; 118 int m_iMouseCaptureViewIndex; 265 119 }; 266 120 267 /* This maintenance class is a part of future roll-back mechanism. 268 * It allows to block main GUI thread until specific event received. 269 * Later it will become more abstract but now its just used to help 270 * fullscreen & seamless modes to restore normal guest size hint. */ 271 class UIMachineViewBlocker : public QEventLoop 272 { 273 Q_OBJECT; 121 #endif // !___UIMouseHandler_h___ 274 122 275 public:276 277 UIMachineViewBlocker()278 : QEventLoop(0)279 , m_iTimerId(0)280 {281 /* Also start timer to unlock pool in case of282 * required condition doesn't happens by some reason: */283 m_iTimerId = startTimer(3000);284 }285 286 virtual ~UIMachineViewBlocker()287 {288 /* Kill the timer: */289 killTimer(m_iTimerId);290 }291 292 protected:293 294 void timerEvent(QTimerEvent *pEvent)295 {296 /* If that timer event occurs => it seems297 * guest resize event doesn't comes in time,298 * shame on it, but we just unlocking 'this': */299 QEventLoop::timerEvent(pEvent);300 exit();301 }302 303 int m_iTimerId;304 };305 306 #endif // !___UIMachineView_h___307 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UISession.h
r30348 r30408 138 138 139 139 /* Mouse setters: */ 140 void setMouseCaptured(bool fIsMouseCaptured) { m_fIsMouseCaptured = fIsMouseCaptured; emit sigMouseCapturedStatusChanged();}140 void setMouseCaptured(bool fIsMouseCaptured) { m_fIsMouseCaptured = fIsMouseCaptured; } 141 141 void setMouseIntegrated(bool fIsMouseIntegrated) { m_fIsMouseIntegrated = fIsMouseIntegrated; } 142 142 … … 176 176 /* Session signals: */ 177 177 void sigMachineStarted(); 178 void sigMouseCapturedStatusChanged();179 178 180 179 public slots: -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineLogicFullscreen.cpp
r30407 r30408 27 27 28 28 #include "UIActionsPool.h" 29 #include "UIMouseHandler.h" 29 30 #include "UIMachineLogicFullscreen.h" 30 31 #include "UIMachineWindow.h" … … 194 195 m_pScreenLayout->update(); 195 196 197 /* Create mouse-handler: */ 198 UIMouseHandler *pMouseHandler = UIMouseHandler::create(this, visualStateType()); 199 setMouseHandler(pMouseHandler); 200 196 201 /* Create machine window(s): */ 197 202 for (int cScreenId = 0; cScreenId < m_pScreenLayout->guestScreenCount(); ++cScreenId) … … 225 230 foreach (UIMachineWindow *pMachineWindow, machineWindows()) 226 231 UIMachineWindow::destroy(pMachineWindow); 232 233 /* Cleanup mouse-handler: */ 234 UIMouseHandler::destroy(mouseHandler()); 227 235 228 236 #ifdef Q_WS_MAC -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
r30347 r30408 74 74 /* Initialization: */ 75 75 sltMachineStateChanged(); 76 sltMousePointerShapeChanged();77 sltMouseCapabilityChanged();78 76 } 79 77 … … 188 186 #endif /* Q_WS_MAC */ 189 187 190 /* Update mouse cursor shape: */191 updateMouseCursorShape();192 193 188 /* May be we have to restrict minimum size? */ 194 189 maybeRestrictMinimumSize(); -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineLogicNormal.cpp
r30407 r30408 27 27 28 28 #include "UIActionsPool.h" 29 #include "UIMouseHandler.h" 29 30 #include "UIDownloaderAdditions.h" 30 31 #include "UIMachineLogicNormal.h" … … 142 143 #endif /* Q_WS_MAC */ 143 144 145 /* Create mouse-handler: */ 146 UIMouseHandler *pMouseHandler = UIMouseHandler::create(this, visualStateType()); 147 setMouseHandler(pMouseHandler); 148 144 149 /* Get monitors count: */ 145 150 ulong uMonitorCount = session().GetMachine().GetMonitorCount(); … … 164 169 foreach (UIMachineWindow *pMachineWindow, machineWindows()) 165 170 UIMachineWindow::destroy(pMachineWindow); 171 172 /* Cleanup mouse-handler: */ 173 UIMouseHandler::destroy(mouseHandler()); 166 174 } 167 175 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
r30347 r30408 69 69 sltMachineStateChanged(); 70 70 sltAdditionsStateChanged(); 71 sltMousePointerShapeChanged();72 sltMouseCapabilityChanged();73 71 } 74 72 … … 176 174 machineLogic()->updateDockIconSize(screenId(), pResizeEvent->width(), pResizeEvent->height()); 177 175 #endif /* Q_WS_MAC */ 178 179 /* Update mouse cursor shape: */180 updateMouseCursorShape();181 176 182 177 /* May be we have to restrict minimum size? */ -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp
r30347 r30408 30 30 31 31 #include "UIActionsPool.h" 32 #include "UIMouseHandler.h" 32 33 #include "UIDownloaderAdditions.h" 33 34 #include "UIDownloaderUserManual.h" … … 489 490 490 491 /* Mouse state-change updater: */ 491 connect(machine View(), SIGNAL(mouseStateChanged(int)), indicatorsPool()->indicator(UIIndicatorIndex_Mouse), SLOT(setState(int)));492 connect(machineLogic()->mouseHandler(), SIGNAL(mouseStateChanged(int)), indicatorsPool()->indicator(UIIndicatorIndex_Mouse), SLOT(setState(int))); 492 493 493 494 /* Early initialize required connections: */ 494 495 indicatorsPool()->indicator(UIIndicatorIndex_Hostkey)->setState(machineView()->keyboardState()); 495 indicatorsPool()->indicator(UIIndicatorIndex_Mouse)->setState(machine View()->mouseState());496 indicatorsPool()->indicator(UIIndicatorIndex_Mouse)->setState(machineLogic()->mouseHandler()->mouseState()); 496 497 } 497 498 } -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineLogicSeamless.cpp
r30407 r30408 27 27 28 28 #include "UIActionsPool.h" 29 #include "UIMouseHandler.h" 29 30 #include "UIMachineLogicSeamless.h" 30 31 #include "UIMachineWindow.h" … … 184 185 m_pScreenLayout->update(); 185 186 187 /* Create machine mouse-handler: */ 188 UIMouseHandler *pMouseHandler = UIMouseHandler::create(this, visualStateType()); 189 setMouseHandler(pMouseHandler); 190 186 191 /* Create machine window(s): */ 187 192 for (int cScreenId = 0; cScreenId < m_pScreenLayout->guestScreenCount(); ++cScreenId) … … 206 211 foreach (UIMachineWindow *pMachineWindow, machineWindows()) 207 212 UIMachineWindow::destroy(pMachineWindow); 213 214 /* Cleanup mouse-handler: */ 215 UIMouseHandler::destroy(mouseHandler()); 208 216 } 209 217 -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
r30347 r30408 76 76 sltMachineStateChanged(); 77 77 sltAdditionsStateChanged(); 78 sltMousePointerShapeChanged();79 sltMouseCapabilityChanged();80 78 } 81 79 … … 199 197 #endif /* Q_WS_MAC */ 200 198 201 /* Update mouse cursor shape: */202 updateMouseCursorShape();203 204 199 /* Update machine-view sliders: */ 205 200 updateSliders();
Note:
See TracChangeset
for help on using the changeset viewer.