VirtualBox

Changeset 30637 in vbox


Ignore:
Timestamp:
Jul 5, 2010 10:36:29 PM (15 years ago)
Author:
vboxsync
Message:

FE/Qt: 5079: Separate UI Keyboard-Handler for running VM - initial implementation commit.

Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
12 edited
8 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk

    r30408 r30637  
    327327        src/runtime/UIActionsPool.h \
    328328        src/runtime/UIIndicatorsPool.h \
     329        src/runtime/UIKeyboardHandler.h \
    329330        src/runtime/UIMouseHandler.h \
    330331        src/runtime/UIMachineLogic.h \
    331332        src/runtime/UIMachineView.h \
    332333        src/runtime/UIMultiScreenLayout.h \
     334        src/runtime/normal/UIKeyboardHandlerNormal.h \
    333335        src/runtime/normal/UIMachineLogicNormal.h \
    334336        src/runtime/normal/UIMachineWindowNormal.h \
    335337        src/runtime/normal/UIMachineViewNormal.h \
     338        src/runtime/fullscreen/UIKeyboardHandlerFullscreen.h \
    336339        src/runtime/fullscreen/UIMachineLogicFullscreen.h \
    337340        src/runtime/fullscreen/UIMachineWindowFullscreen.h \
    338341        src/runtime/fullscreen/UIMachineViewFullscreen.h \
     342        src/runtime/seamless/UIKeyboardHandlerSeamless.h \
    339343        src/runtime/seamless/UIMachineLogicSeamless.h \
    340344        src/runtime/seamless/UIMachineWindowSeamless.h \
     
    461465        src/runtime/UIActionsPool.cpp \
    462466        src/runtime/UIIndicatorsPool.cpp \
     467        src/runtime/UIKeyboardHandler.cpp \
    463468        src/runtime/UIMouseHandler.cpp \
    464469        src/runtime/UIFrameBuffer.cpp \
     
    471476        src/runtime/UIMachineMenuBar.cpp \
    472477        src/runtime/UIMultiScreenLayout.cpp \
     478        src/runtime/normal/UIKeyboardHandlerNormal.cpp \
    473479        src/runtime/normal/UIMachineLogicNormal.cpp \
    474480        src/runtime/normal/UIMachineWindowNormal.cpp \
    475481        src/runtime/normal/UIMachineViewNormal.cpp \
     482        src/runtime/fullscreen/UIKeyboardHandlerFullscreen.cpp \
    476483        src/runtime/fullscreen/UIMachineLogicFullscreen.cpp \
    477484        src/runtime/fullscreen/UIMachineWindowFullscreen.cpp \
    478485        src/runtime/fullscreen/UIMachineViewFullscreen.cpp \
     486        src/runtime/seamless/UIKeyboardHandlerSeamless.cpp \
    479487        src/runtime/seamless/UIMachineLogicSeamless.cpp \
    480488        src/runtime/seamless/UIMachineWindowSeamless.cpp \
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp

    r30458 r30637  
    33 *
    44 * VBox frontends: Qt GUI ("VirtualBox"):
    5  * UIMachineView class implementation
     5 * UIKeyboardHandler class implementation
    66 */
    77
     
    1919
    2020/* Global includes */
    21 #include <QDesktopWidget>
    22 #include <QTimer>
    23 #include <QPainter>
    24 #include <QScrollBar>
    25 #include <VBox/VBoxVideo.h>
     21#include <QKeyEvent>
    2622
    2723/* Local includes */
    2824#include "VBoxGlobal.h"
    2925#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"
     26#include "UIActionsPool.h"
     27#include "UIKeyboardHandlerNormal.h"
     28#include "UIKeyboardHandlerFullscreen.h"
     29#include "UIKeyboardHandlerSeamless.h"
     30#include "UIMouseHandler.h"
    3631#include "UISession.h"
    37 #include "UIActionsPool.h"
    38 #include "UIMouseHandler.h"
    3932#include "UIMachineLogic.h"
    40 #include "UIMachineWindow.h"
    41 #include "UIMachineView.h"
    4233#include "UIMachineWindowNormal.h"
    4334#include "UIMachineWindowFullscreen.h"
    4435#include "UIMachineWindowSeamless.h"
    45 #include "UIMachineViewNormal.h"
    46 #include "UIMachineViewFullscreen.h"
    47 #include "UIMachineViewSeamless.h"
    48 
    49 #ifdef Q_WS_PM
    50 # include "QIHotKeyEdit.h"
    51 #endif /* defined (Q_WS_PM) */
    52 
    53 #ifdef Q_WS_WIN
    54 #undef LOWORD
    55 #undef HIWORD
    56 #undef LOBYTE
    57 #undef HIBYTE
    58 #include <windows.h>
    59 static UIMachineView *gView = 0;
    60 static HHOOK gKbdHook = 0;
    61 #endif /* defined (Q_WS_WIN) */
     36#include "UIMachineView.h"
    6237
    6338#ifdef Q_WS_X11
    6439# include <QX11Info>
    65 # define XK_XKB_KEYS
    66 # define XK_MISCELLANY
    6740# include <X11/XKBlib.h>
    6841# include <X11/keysym.h>
     
    7649#  undef FocusOut
    7750#  undef FocusIn
    78 # endif
     51# endif /* KeyPress */
    7952# include "XKeyboard.h"
    80 #endif /* defined (Q_WS_X11) */
    81 
    82 #ifdef Q_WS_MAC
    83 # include "DockIconPreview.h"
    84 # include "DarwinKeyboard.h"
    85 # include "UICocoaApplication.h"
    86 # include <VBox/err.h>
    87 # include <Carbon/Carbon.h>
    88 #endif /* Q_WS_MAC */
    89 
    90 class VBoxViewport: public QWidget
    91 {
    92 public:
    93 
    94     VBoxViewport(QWidget *pParent) : QWidget(pParent)
    95     {
    96         /* No need for background drawing: */
    97         setAttribute(Qt::WA_OpaquePaintEvent);
    98     }
    99 
    100     QPaintEngine *paintEngine() const
    101     {
    102         if (testAttribute(Qt::WA_PaintOnScreen))
    103             return NULL;
    104         else
    105             return QWidget::paintEngine();
    106     }
    107 };
    108 
     53#endif /* Q_WS_X11 */
     54
     55/* Enums representing different keyboard-states: */
    10956enum { KeyExtended = 0x01, KeyPressed = 0x02, KeyPause = 0x04, KeyPrint = 0x08 };
    11057enum { IsKeyPressed = 0x01, IsExtKeyPressed = 0x02, IsKbdCaptured = 0x80 };
    11158
    112 UIMachineView* UIMachineView::create(  UIMachineWindow *pMachineWindow
    113 #ifdef VBOX_WITH_VIDEOHWACCEL
    114                                      , bool bAccelerate2DVideo
    115 #endif
    116                                      , UIVisualStateType visualStateType
    117                                      , ulong uScreenId)
    118 {
    119     UIMachineView *view = 0;
     59#ifdef Q_WS_WIN
     60UIKeyboardHandler* UIKeyboardHandler::m_pKeyboardHandler = 0;
     61#endif /* Q_WS_WIN */
     62
     63/* Factory function to create keyboard-handler: */
     64UIKeyboardHandler* UIKeyboardHandler::create(UIMachineLogic *pMachineLogic,
     65                                             UIVisualStateType visualStateType)
     66{
     67    /* Prepare keyboard-handler: */
     68    UIKeyboardHandler *pKeyboardHandler = 0;
     69    /* Depending on visual-state type: */
    12070    switch (visualStateType)
    12171    {
    12272        case UIVisualStateType_Normal:
    123             view = new UIMachineViewNormal(  pMachineWindow
    124 #ifdef VBOX_WITH_VIDEOHWACCEL
    125                                            , bAccelerate2DVideo
    126 #endif
    127                                            , uScreenId);
     73            pKeyboardHandler = new UIKeyboardHandlerNormal(pMachineLogic);
    12874            break;
    12975        case UIVisualStateType_Fullscreen:
    130             view = new UIMachineViewFullscreen(  pMachineWindow
    131 #ifdef VBOX_WITH_VIDEOHWACCEL
    132                                                , bAccelerate2DVideo
    133 #endif
    134                                                , uScreenId);
     76            pKeyboardHandler = new UIKeyboardHandlerFullscreen(pMachineLogic);
    13577            break;
    13678        case UIVisualStateType_Seamless:
    137             view = new UIMachineViewSeamless(  pMachineWindow
    138 #ifdef VBOX_WITH_VIDEOHWACCEL
    139                                              , bAccelerate2DVideo
    140 #endif
    141                                              , uScreenId);
     79            pKeyboardHandler = new UIKeyboardHandlerSeamless(pMachineLogic);
    14280            break;
    14381        default:
    14482            break;
    14583    }
    146     return view;
    147 }
    148 
    149 void UIMachineView::destroy(UIMachineView *pWhichView)
    150 {
    151     delete pWhichView;
    152 }
    153 
    154 int UIMachineView::keyboardState() const
    155 {
    156     return (m_bIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) |
     84#ifdef Q_WS_WIN
     85    /* Its required to have static pointer to created handler
     86     * because windows keyboard-hook works only with static members: */
     87    m_pKeyboardHandler = pKeyboardHandler;
     88#endif /* Q_WS_WIN */
     89    /* Return prepared keyboard-handler: */
     90    return pKeyboardHandler;
     91}
     92
     93/* Factory function to destroy keyboard-handler: */
     94void UIKeyboardHandler::destroy(UIKeyboardHandler *pKeyboardHandler)
     95{
     96    /* Delete keyboard-handler: */
     97#ifdef Q_WS_WIN
     98    m_pKeyboardHandler = 0;
     99#endif /* Q_WS_WIN */
     100    delete pKeyboardHandler;
     101}
     102
     103/* Prepare listened objects: */
     104void UIKeyboardHandler::prepareListener(ulong uIndex, UIMachineWindow *pMachineWindow)
     105{
     106    /* If that window is NOT registered yet: */
     107    if (!m_windows.contains(uIndex))
     108    {
     109        /* Add window: */
     110        m_windows.insert(uIndex, pMachineWindow);
     111        /* Install event-filter for window: */
     112        switch (machineLogic()->visualStateType())
     113        {
     114            case UIVisualStateType_Normal:
     115                static_cast<UIMachineWindowNormal*>(m_windows[uIndex])->installEventFilter(this);
     116                break;
     117            case UIVisualStateType_Fullscreen:
     118                static_cast<UIMachineWindowFullscreen*>(m_windows[uIndex])->installEventFilter(this);
     119                break;
     120            case UIVisualStateType_Seamless:
     121                static_cast<UIMachineWindowSeamless*>(m_windows[uIndex])->installEventFilter(this);
     122                break;
     123            default:
     124                break;
     125        }
     126    }
     127
     128    /* If that view is NOT registered yet: */
     129    if (!m_views.contains(uIndex))
     130    {
     131        /* Add view: */
     132        m_views.insert(uIndex, pMachineWindow->machineView());
     133        /* Install event-filter for view: */
     134        m_views[uIndex]->installEventFilter(this);
     135    }
     136}
     137
     138/* Cleanup listened objects: */
     139void UIKeyboardHandler::cleanupListener(ulong uIndex)
     140{
     141    /* If window still registered: */
     142    if (m_windows.contains(uIndex))
     143    {
     144        /* Remove window: */
     145        m_windows.remove(uIndex);
     146    }
     147
     148    /* If view still registered: */
     149    if (m_views.contains(uIndex))
     150    {
     151        /* Remove view: */
     152        m_views.remove(uIndex);
     153    }
     154}
     155
     156void UIKeyboardHandler::captureKeyboard(ulong uScreenId)
     157{
     158    /* Do NOT capture keyboard if its captured already: */
     159    if (m_fIsKeyboardCaptured)
     160        return;
     161
     162    /* If such view exists: */
     163    if (m_views.contains(uScreenId))
     164    {
     165        /* Store new keyboard-captured state value: */
     166        m_fIsKeyboardCaptured = true;
     167
     168        /* Remember which screen had captured keyboard: */
     169        m_iKeyboardCaptureViewIndex = uScreenId;
     170
     171#if defined(Q_WS_WIN)
     172        /* On Win, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */
     173#elif defined(Q_WS_X11)
     174        /* On X11, we are using passive XGrabKey for normal (windowed) mode
     175         * instead of XGrabKeyboard (called by QWidget::grabKeyboard())
     176         * because XGrabKeyboard causes a problem under metacity - a window cannot be moved
     177         * using the mouse if it is currently actively grabing the keyboard;
     178         * For static modes we are using usual (active) keyboard grabbing. */
     179        switch (machineLogic()->visualStateType())
     180        {
     181            /* If window is moveable we are making passive keyboard grab: */
     182            case UIVisualStateType_Normal:
     183            {
     184                XGrabKey(QX11Info::display(), AnyKey, AnyModifier, m_windows[m_iKeyboardCaptureViewIndex]->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync);
     185                break;
     186            }
     187            /* If window is NOT moveable we are making active keyboard grab: */
     188            case UIVisualStateType_Fullscreen:
     189            case UIVisualStateType_Seamless:
     190            {
     191                /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager.
     192                 * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times,
     193                 * and after we will just ignore that issue: */
     194                int cTriesLeft = 50;
     195                while (cTriesLeft && XGrabKeyboard(QX11Info::display(), m_windows[m_iKeyboardCaptureViewIndex]->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; }
     196                break;
     197            }
     198            /* Should we try to grab keyboard in default case? I think - NO. */
     199            default:
     200                break;
     201        }
     202#elif defined(Q_WS_MAC)
     203        /* On Mac, we use the Qt methods + disabling global hot keys + watching modifiers (for right/left separation). */
     204        ::DarwinDisableGlobalHotKeys(true);
     205        m_views[m_iKeyboardCaptureViewIndex]->grabKeyboard();
     206#else
     207        /* On other platforms we are just praying Qt method will work. */
     208        m_views[m_iKeyboardCaptureViewIndex]->grabKeyboard();
     209#endif
     210
     211        /* Notify all the listeners: */
     212        emit keyboardStateChanged(keyboardState());
     213    }
     214}
     215
     216void UIKeyboardHandler::releaseKeyboard()
     217{
     218    /* Do NOT capture keyboard if its captured already: */
     219    if (!m_fIsKeyboardCaptured)
     220        return;
     221
     222    /* If such view exists: */
     223    if (m_views.contains(m_iKeyboardCaptureViewIndex))
     224    {
     225        /* Store new keyboard-captured state value: */
     226        m_fIsKeyboardCaptured = false;
     227
     228#if defined(Q_WS_WIN)
     229        /* On Win, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */
     230#elif defined(Q_WS_X11)
     231        /* On X11, we are using passive XGrabKey for normal (windowed) mode
     232         * instead of XGrabKeyboard (called by QWidget::grabKeyboard())
     233         * because XGrabKeyboard causes a problem under metacity - a window cannot be moved
     234         * using the mouse if it is currently actively grabing the keyboard;
     235         * For static modes we are using usual (active) keyboard grabbing. */
     236        switch (machineLogic()->visualStateType())
     237        {
     238            /* If window is moveable we are making passive keyboard ungrab: */
     239            case UIVisualStateType_Normal:
     240            {
     241                XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, m_windows[m_iKeyboardCaptureViewIndex]->machineWindow()->winId());
     242                break;
     243            }
     244            /* If window is NOT moveable we are making active keyboard ungrab: */
     245            case UIVisualStateType_Fullscreen:
     246            case UIVisualStateType_Seamless:
     247            {
     248                XUngrabKeyboard(QX11Info::display(), CurrentTime);
     249                break;
     250            }
     251            /* Should we try to release keyboard in default case? I think - NO. */
     252            default:
     253                break;
     254        }
     255#elif defined(Q_WS_MAC)
     256        ::DarwinDisableGlobalHotKeys(false);
     257        m_views[m_iKeyboardCaptureViewIndex]->releaseKeyboard();
     258#else
     259        m_views[m_iKeyboardCaptureViewIndex]->releaseKeyboard();
     260#endif
     261
     262        /* Reset keyboard-capture index: */
     263        m_iKeyboardCaptureViewIndex = -1;
     264
     265        /* Notify all the listeners: */
     266        emit keyboardStateChanged(keyboardState());
     267    }
     268}
     269
     270/* Current keyboard state: */
     271int UIKeyboardHandler::keyboardState() const
     272{
     273    return (m_fIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) |
    157274           (m_bIsHostkeyPressed ? UIViewStateType_HostKeyPressed : 0);
    158275}
    159276
    160 UIMachineView::UIMachineView(  UIMachineWindow *pMachineWindow
    161 #ifdef VBOX_WITH_VIDEOHWACCEL
    162                              , bool bAccelerate2DVideo
     277#if defined(Q_WS_WIN)
     278
     279bool UIKeyboardHandler::winEventFilter(MSG *pMsg, ulong uScreenId)
     280{
     281    /* Check if some system event should be filtered-out.
     282     * Returning 'true' means filtering-out,
     283     * Returning 'false' means passing event to Qt. */
     284    bool fResult = false; /* Pass to Qt by default: */
     285    switch (pMsg->message)
     286    {
     287        case WM_KEYDOWN:
     288        case WM_KEYUP:
     289        case WM_SYSKEYDOWN:
     290        case WM_SYSKEYUP:
     291        {
     292            /* Check for the special flag possibly set at the end of this function: */
     293            if (pMsg->lParam & (0x1 << 25))
     294            {
     295                pMsg->lParam &= ~(0x1 << 25);
     296                fResult = false;
     297                break;
     298            }
     299
     300            /* Scancodes 0x80 and 0x00 are ignored: */
     301            uint8_t scan = (pMsg->lParam >> 16) & 0x7F;
     302            if (!scan)
     303            {
     304                fResult = true;
     305                break;
     306            }
     307
     308            int vkey = pMsg->wParam;
     309
     310            /* When one of the SHIFT keys is held and one of the cursor movement
     311             * keys is pressed, Windows duplicates SHIFT press/release messages,
     312             * but with the virtual key code set to 0xFF. These virtual keys are also
     313             * sent in some other situations (Pause, PrtScn, etc.). Ignore suc messages. */
     314            if (vkey == 0xFF)
     315            {
     316                fResult = true;
     317                break;
     318            }
     319
     320            int flags = 0;
     321            if (pMsg->lParam & 0x1000000)
     322                flags |= KeyExtended;
     323            if (!(pMsg->lParam & 0x80000000))
     324                flags |= KeyPressed;
     325
     326            switch (vkey)
     327            {
     328                case VK_SHIFT:
     329                case VK_CONTROL:
     330                case VK_MENU:
     331                {
     332                    /* Overcome stupid Win32 modifier key generalization: */
     333                    int keyscan = scan;
     334                    if (flags & KeyExtended)
     335                        keyscan |= 0xE000;
     336                    switch (keyscan)
     337                    {
     338                        case 0x002A: vkey = VK_LSHIFT; break;
     339                        case 0x0036: vkey = VK_RSHIFT; break;
     340                        case 0x001D: vkey = VK_LCONTROL; break;
     341                        case 0xE01D: vkey = VK_RCONTROL; break;
     342                        case 0x0038: vkey = VK_LMENU; break;
     343                        case 0xE038: vkey = VK_RMENU; break;
     344                    }
     345                    break;
     346                }
     347                case VK_NUMLOCK:
     348                    /* Win32 sets the extended bit for the NumLock key. Reset it: */
     349                    flags &= ~KeyExtended;
     350                    break;
     351                case VK_SNAPSHOT:
     352                    flags |= KeyPrint;
     353                    break;
     354                case VK_PAUSE:
     355                    flags |= KeyPause;
     356                    break;
     357            }
     358
     359            bool result = keyEvent(vkey, scan, flags, uScreenId);
     360            if (!result && m_fIsKeyboardCaptured)
     361            {
     362                /* keyEvent() returned that it didn't process the message, but since the
     363                 * keyboard is captured, we don't want to pass it to Windows. We just want
     364                 * to let Qt process the message (to handle non-alphanumeric <HOST>+key
     365                 * shortcuts for example). So send it direcltly to the window with the
     366                 * special flag in the reserved area of lParam (to avoid recursion). */
     367                ::SendMessage(pMsg->hwnd, pMsg->message,
     368                              pMsg->wParam, pMsg->lParam | (0x1 << 25));
     369                fResult = true;
     370                break;
     371            }
     372
     373            /* These special keys have to be handled by Windows as well to update the
     374             * internal modifier state and to enable/disable the keyboard LED */
     375            if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT)
     376            {
     377                fResult = false;
     378                break;
     379            }
     380
     381            fResult = result;
     382            break;
     383        }
     384        default:
     385            break;
     386    }
     387    /* Return result: */
     388    return fResult;
     389}
     390
     391#elif defined(Q_WS_X11)
     392
     393static Bool UIKeyboardHandlerCompEvent(Display*, XEvent *pEvent, XPointer pvArg)
     394{
     395    XEvent *pKeyEvent = (XEvent*)pvArg;
     396    if ((pEvent->type == XKeyPress) && (pEvent->xkey.keycode == pKeyEvent->xkey.keycode))
     397        return True;
     398    else
     399        return False;
     400}
     401
     402bool UIKeyboardHandler::x11EventFilter(XEvent *pEvent, ulong uScreenId)
     403{
     404    /* Check if some system event should be filtered-out.
     405     * Returning 'true' means filtering-out,
     406     * Returning 'false' means passing event to Qt. */
     407    bool fResult = false; /* Pass to Qt by default: */
     408    switch (pEvent->type)
     409    {
     410        /* We have to handle XFocusOut right here as this event is not passed to UIMachineView::event().
     411         * Handling this event is important for releasing the keyboard before the screen saver gets active.
     412         * See public ticket #3894: Apparently this makes problems with newer versions of Qt
     413         * and this hack is probably not necessary anymore. So disable it for Qt >= 4.5.0. */
     414        case XFocusOut:
     415        case XFocusIn:
     416        {
     417            if (uisession()->isRunning())
     418            {
     419                if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0))
     420                {
     421                    if (pEvent->type == XFocusIn)
     422                    {
     423                        /* Capture keyboard by chosen view number: */
     424                        captureKeyboard(uScreenId);
     425                        /* Reset the single-time disable capture flag: */
     426                        if (uisession()->isAutoCaptureDisabled())
     427                            uisession()->setAutoCaptureDisabled(false);
     428                    }
     429                    else
     430                    {
     431                        /* Release keyboard: */
     432                        releaseKeyboard();
     433                        /* And all pressed keys including host-one: */
     434                        releaseAllPressedKeys(true);
     435                    }
     436                }
     437            }
     438            fResult = false;
     439        }
     440        case XKeyPress:
     441        case XKeyRelease:
     442        {
     443            /* Translate the keycode to a PC scan code. */
     444            uint8_t scan = handleXKeyEvent(pEvent);
     445
     446            /* Scancodes 0x00 (no valid translation) and 0x80 are ignored: */
     447            if (!scan & 0x7F)
     448            {
     449                fResult = true;
     450                break;
     451            }
     452
     453            /* Fix for http://www.virtualbox.org/ticket/1296:
     454             * when X11 sends events for repeated keys, it always inserts an XKeyRelease before the XKeyPress. */
     455            XEvent returnEvent;
     456            if ((pEvent->type == XKeyRelease) && (XCheckIfEvent(pEvent->xkey.display, &returnEvent,
     457                UIKeyboardHandlerCompEvent, (XPointer)pEvent) == True))
     458            {
     459                XPutBackEvent(pEvent->xkey.display, &returnEvent);
     460                fResult = true;
     461                break;
     462            }
     463
     464            KeySym ks = ::XKeycodeToKeysym(pEvent->xkey.display, pEvent->xkey.keycode, 0);
     465
     466            int flags = 0;
     467            if (scan >> 8)
     468                flags |= KeyExtended;
     469            if (pEvent->type == XKeyPress)
     470                flags |= KeyPressed;
     471
     472            /* Remove the extended flag: */
     473            scan &= 0x7F;
     474
     475            switch (ks)
     476            {
     477                case XK_Print:
     478                    flags |= KeyPrint;
     479                    break;
     480                case XK_Pause:
     481                    flags |= KeyPause;
     482                    break;
     483            }
     484
     485            fResult = keyEvent(ks, scan, flags, uScreenId);
     486        }
     487        default:
     488            break;
     489    }
     490    /* Return result: */
     491    return fResult;
     492}
     493
    163494#endif
    164                              , ulong uScreenId)
    165 // TODO_NEW_CORE: really think of if this is right
    166 //    : QAbstractScrollArea(((QMainWindow*)pMachineWindow->machineWindow())->centralWidget())
    167     : QAbstractScrollArea(pMachineWindow->machineWindow())
    168     , m_pMachineWindow(pMachineWindow)
    169     , m_uScreenId(uScreenId)
     495
     496/* Machine state-change handler: */
     497void UIKeyboardHandler::sltMachineStateChanged()
     498{
     499    /* Get machine state: */
     500    KMachineState state = uisession()->machineState();
     501    /* Handle particular machine states: */
     502    switch (state)
     503    {
     504        case KMachineState_Paused:
     505        case KMachineState_TeleportingPausedVM:
     506        case KMachineState_Stuck:
     507        {
     508            /* Release the keyboard: */
     509            releaseKeyboard();
     510            /* And all pressed keys except the host-one : */
     511            releaseAllPressedKeys(false /* release host-key? */);
     512            break;
     513        }
     514        case KMachineState_Running:
     515        {
     516            /* Capture the keyboard by the first focused view: */
     517            QList<ulong> theListOfViewIds = m_views.keys();
     518            for (int i = 0; i < theListOfViewIds.size(); ++i)
     519            {
     520                if (m_views[theListOfViewIds[i]]->hasFocus())
     521                {
     522                    captureKeyboard(theListOfViewIds[i]);
     523                    break;
     524                }
     525            }
     526            break;
     527        }
     528        default:
     529            break;
     530    }
     531}
     532
     533/* Keyboard-handler constructor: */
     534UIKeyboardHandler::UIKeyboardHandler(UIMachineLogic *pMachineLogic)
     535    : QObject(pMachineLogic)
     536    , m_pMachineLogic(pMachineLogic)
     537    , m_iKeyboardCaptureViewIndex(-1)
    170538    , m_globalSettings(vboxGlobal().settings())
    171     , m_pFrameBuffer(0)
    172     , m_previousState(KMachineState_Null)
    173     , m_desktopGeometryType(DesktopGeo_Invalid)
    174     , m_bIsKeyboardCaptured(false)
     539    , m_fIsKeyboardCaptured(false)
    175540    , m_bIsHostkeyPressed(false)
    176541    , m_bIsHostkeyAlone (false)
    177542    , m_bIsHostkeyInCapture(false)
    178     , m_bIsMachineWindowResizeIgnored(false)
    179543    , m_fPassCAD(false)
    180 #ifdef VBOX_WITH_VIDEOHWACCEL
    181     , m_fAccelerate2DVideo(bAccelerate2DVideo)
    182 #endif /* VBOX_WITH_VIDEOHWACCEL */
    183 #ifdef Q_WS_MAC
     544#if defined(Q_WS_WIN)
     545    , m_iKeyboardHookViewIndex(-1)
     546#elif defined(Q_WS_MAC)
    184547    , m_darwinKeyModifiers(0)
    185     , m_fKeyboardGrabbed (false)
    186 #endif /* Q_WS_MAC */
    187 {
    188 }
    189 
    190 UIMachineView::~UIMachineView()
    191 {
    192 }
    193 
    194 UISession* UIMachineView::uisession() const
    195 {
    196     return machineLogic()->uisession();
    197 }
    198 
    199 CSession& UIMachineView::session()
    200 {
    201     return uisession()->session();
    202 }
    203 
    204 QSize UIMachineView::sizeHint() const
    205 {
    206 #ifdef VBOX_WITH_DEBUGGER
    207     // TODO: Fix all DEBUGGER stuff!
    208     /* HACK ALERT! Really ugly workaround for the resizing to 9x1 done by DevVGA if provoked before power on. */
    209     QSize fb(m_pFrameBuffer->width(), m_pFrameBuffer->height());
    210     if ((fb.width() < 16 || fb.height() < 16) && (vboxGlobal().isStartPausedEnabled() || vboxGlobal().isDebuggerAutoShowEnabled()))
    211         fb = QSize(640, 480);
    212     return QSize(fb.width() + frameWidth() * 2, fb.height() + frameWidth() * 2);
    213 #else
    214     return QSize(m_pFrameBuffer->width() + frameWidth() * 2, m_pFrameBuffer->height() + frameWidth() * 2);
     548    , m_fKeyboardGrabbed(false)
    215549#endif
    216 }
    217 
    218 int UIMachineView::contentsX() const
    219 {
    220     return horizontalScrollBar()->value();
    221 }
    222 
    223 int UIMachineView::contentsY() const
    224 {
    225     return verticalScrollBar()->value();
    226 }
    227 
    228 int UIMachineView::contentsWidth() const
    229 {
    230     return m_pFrameBuffer->width();
    231 }
    232 
    233 int UIMachineView::contentsHeight() const
    234 {
    235     return m_pFrameBuffer->height();
    236 }
    237 
    238 int UIMachineView::visibleWidth() const
    239 {
    240     return horizontalScrollBar()->pageStep();
    241 }
    242 
    243 int UIMachineView::visibleHeight() const
    244 {
    245     return verticalScrollBar()->pageStep();
    246 }
    247 
    248 UIMachineLogic* UIMachineView::machineLogic() const
    249 {
    250     return machineWindowWrapper()->machineLogic();
    251 }
    252 
    253 QSize UIMachineView::desktopGeometry() const
    254 {
    255     QSize geometry;
    256     switch (m_desktopGeometryType)
    257     {
    258         case DesktopGeo_Fixed:
    259         case DesktopGeo_Automatic:
    260             geometry = QSize(qMax(m_desktopGeometry.width(), m_storedConsoleSize.width()),
    261                              qMax(m_desktopGeometry.height(), m_storedConsoleSize.height()));
    262             break;
    263         case DesktopGeo_Any:
    264             geometry = QSize(0, 0);
    265             break;
    266         default:
    267             AssertMsgFailed(("Bad geometry type %d!\n", m_desktopGeometryType));
    268     }
    269     return geometry;
    270 }
    271 
    272 QSize UIMachineView::guestSizeHint()
    273 {
    274     /* Result: */
    275     QSize sizeHint;
    276 
    277     /* Get current machine: */
    278     CMachine machine = session().GetMachine();
    279 
    280     /* Load machine view hint: */
    281     QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :
    282                      QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);
    283     QString strValue = machine.GetExtraData(strKey);
    284 
    285     bool ok = true;
    286     int width = 0, height = 0;
    287     if (ok)
    288         width = strValue.section(',', 0, 0).toInt(&ok);
    289     if (ok)
    290         height = strValue.section(',', 1, 1).toInt(&ok);
    291 
    292     if (ok /* If previous parameters were read correctly! */)
    293     {
    294         /* Compose guest size hint from loaded values: */
    295         sizeHint = QSize(width, height);
    296     }
    297     else
    298     {
    299         /* Compose guest size hint from default attributes: */
    300         sizeHint = QSize(800, 600);
    301     }
    302 
    303     /* Return result: */
    304     return sizeHint;
    305 }
    306 
    307 void UIMachineView::setDesktopGeometry(DesktopGeo geometry, int aWidth, int aHeight)
    308 {
    309     switch (geometry)
    310     {
    311         case DesktopGeo_Fixed:
    312             m_desktopGeometryType = DesktopGeo_Fixed;
    313             if (aWidth != 0 && aHeight != 0)
    314                 m_desktopGeometry = QSize(aWidth, aHeight);
    315             else
    316                 m_desktopGeometry = QSize(0, 0);
    317             storeConsoleSize(0, 0);
    318             break;
    319         case DesktopGeo_Automatic:
    320             m_desktopGeometryType = DesktopGeo_Automatic;
    321             m_desktopGeometry = QSize(0, 0);
    322             storeConsoleSize(0, 0);
    323             break;
    324         case DesktopGeo_Any:
    325             m_desktopGeometryType = DesktopGeo_Any;
    326             m_desktopGeometry = QSize(0, 0);
    327             break;
    328         default:
    329             AssertMsgFailed(("Invalid desktop geometry type %d\n", geometry));
    330             m_desktopGeometryType = DesktopGeo_Invalid;
    331     }
    332 }
    333 
    334 void UIMachineView::storeConsoleSize(int iWidth, int iHeight)
    335 {
    336     m_storedConsoleSize = QSize(iWidth, iHeight);
    337 }
    338 
    339 void UIMachineView::storeGuestSizeHint(const QSize &sizeHint)
    340 {
    341     /* Get current machine: */
    342     CMachine machine = session().GetMachine();
    343 
    344     /* Save machine view hint: */
    345     QString strKey = m_uScreenId == 0 ? QString("%1").arg(VBoxDefs::GUI_LastGuestSizeHint) :
    346                      QString("%1%2").arg(VBoxDefs::GUI_LastGuestSizeHint).arg(m_uScreenId);
    347     QString strValue = QString("%1,%2").arg(sizeHint.width()).arg(sizeHint.height());
    348     machine.SetExtraData(strKey, strValue);
    349 }
    350 
    351 void UIMachineView::updateSliders()
    352 {
    353     QSize p = viewport()->size();
    354     QSize m = maximumViewportSize();
    355 
    356     QSize v = QSize(frameBuffer()->width(), frameBuffer()->height());
    357     /* No scroll bars needed: */
    358     if (m.expandedTo(v) == m)
    359         p = m;
    360 
    361     horizontalScrollBar()->setRange(0, v.width() - p.width());
    362     verticalScrollBar()->setRange(0, v.height() - p.height());
    363     horizontalScrollBar()->setPageStep(p.width());
    364     verticalScrollBar()->setPageStep(p.height());
    365 }
    366 
    367 void UIMachineView::prepareFrameBuffer()
    368 {
    369     /* Prepare viewport: */
    370 #ifdef VBOX_GUI_USE_QGLFB
    371     QWidget *pViewport;
    372     switch (vboxGlobal().vmRenderMode())
    373     {
    374         case VBoxDefs::QGLMode:
    375             pViewport = new VBoxGLWidget(session().GetConsole(), this, NULL);
    376             break;
    377         default:
    378             pViewport = new VBoxViewport(this);
    379     }
    380 #else
    381     VBoxViewport *pViewport = new VBoxViewport(this);
    382 #endif
    383     setViewport(pViewport);
    384 
    385     CDisplay display = session().GetConsole().GetDisplay();
    386     Assert(!display.isNull());
    387     m_pFrameBuffer = NULL;
    388 
    389     switch (vboxGlobal().vmRenderMode())
    390     {
    391 #ifdef VBOX_GUI_USE_QIMAGE
    392         case VBoxDefs::QImageMode:
    393 # ifdef VBOX_WITH_VIDEOHWACCEL
    394             if (m_fAccelerate2DVideo)
    395             {
    396                 UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
    397                 if (pFramebuffer)
    398                     pFramebuffer->setView(this);
    399                 else
    400                 {
    401                     /* these two additional template args is a workaround to this [VBox|UI] duplication
    402                      * @todo: they are to be removed once VBox stuff is gone */
    403                     pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQImage, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
    404                     uisession()->setFrameBuffer(screenId(), pFramebuffer);
    405                 }
    406                 m_pFrameBuffer = pFramebuffer;
    407             }
    408             else
    409                 m_pFrameBuffer = new UIFrameBufferQImage(this);
    410 # else
    411             m_pFrameBuffer = new UIFrameBufferQImage(this);
    412 # endif
    413             break;
    414 #endif /* VBOX_GUI_USE_QIMAGE */
    415 #ifdef VBOX_GUI_USE_QGLFB
    416         case VBoxDefs::QGLMode:
    417             m_pFrameBuffer = new UIFrameBufferQGL(this);
    418             break;
    419 //        case VBoxDefs::QGLOverlayMode:
    420 //            m_pFrameBuffer = new UIQGLOverlayFrameBuffer(this);
    421 //            break;
    422 #endif /* VBOX_GUI_USE_QGLFB */
    423 #ifdef VBOX_GUI_USE_SDL
    424         case VBoxDefs::SDLMode:
    425             /* Indicate that we are doing all drawing stuff ourself: */
    426             // TODO_NEW_CORE
    427             viewport()->setAttribute(Qt::WA_PaintOnScreen);
    428 # ifdef Q_WS_X11
    429             /* This is somehow necessary to prevent strange X11 warnings on i386 and segfaults on x86_64: */
    430             XFlush(QX11Info::display());
    431 # endif
    432 # if defined(VBOX_WITH_VIDEOHWACCEL) && defined(DEBUG_misha) /* not tested yet */
    433             if (m_fAccelerate2DVideo)
    434             {
    435                 class UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
    436                 if (pFramebuffer)
    437                     pFramebuffer->setView(this);
    438                 else
    439                 {
    440                     /* these two additional template args is a workaround to this [VBox|UI] duplication
    441                      * @todo: they are to be removed once VBox stuff is gone */
    442                     pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferSDL, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
    443                     uisession()->setFrameBuffer(screenId(), pFramebuffer);
    444                 }
    445                 m_pFrameBuffer = pFramebuffer;
    446             }
    447             else
    448                 m_pFrameBuffer = new UIFrameBufferSDL(this);
    449 # else
    450             m_pFrameBuffer = new UIFrameBufferSDL(this);
    451 # endif
    452             /* Disable scrollbars because we cannot correctly draw in a scrolled window using SDL: */
    453             horizontalScrollBar()->setEnabled(false);
    454             verticalScrollBar()->setEnabled(false);
    455             break;
    456 #endif /* VBOX_GUI_USE_SDL */
    457 #if 0 // TODO: Enable DDraw frame buffer!
    458 #ifdef VBOX_GUI_USE_DDRAW
    459         case VBoxDefs::DDRAWMode:
    460             m_pFrameBuffer = new UIDDRAWFrameBuffer(this);
    461             if (!m_pFrameBuffer || m_pFrameBuffer->address() == NULL)
    462             {
    463                 if (m_pFrameBuffer)
    464                     delete m_pFrameBuffer;
    465                 m_mode = VBoxDefs::QImageMode;
    466                 m_pFrameBuffer = new UIFrameBufferQImage(this);
    467             }
    468             break;
    469 #endif /* VBOX_GUI_USE_DDRAW */
    470 #endif
    471 #ifdef VBOX_GUI_USE_QUARTZ2D
    472         case VBoxDefs::Quartz2DMode:
    473             /* Indicate that we are doing all drawing stuff ourself: */
    474             viewport()->setAttribute(Qt::WA_PaintOnScreen);
    475 # ifdef VBOX_WITH_VIDEOHWACCEL
    476             if (m_fAccelerate2DVideo)
    477             {
    478                 UIFrameBuffer* pFramebuffer = uisession()->frameBuffer(screenId());
    479                 if (pFramebuffer)
    480                     pFramebuffer->setView(this);
    481                 else
    482                 {
    483                     /* these two additional template args is a workaround to this [VBox|UI] duplication
    484                      * @todo: they are to be removed once VBox stuff is gone */
    485                     pFramebuffer = new VBoxOverlayFrameBuffer<UIFrameBufferQuartz2D, UIMachineView, UIResizeEvent>(this, &machineWindowWrapper()->session(), (uint32_t)screenId());
    486                     uisession()->setFrameBuffer(screenId(), pFramebuffer);
    487                 }
    488                 m_pFrameBuffer = pFramebuffer;
    489             }
    490             else
    491                 m_pFrameBuffer = new UIFrameBufferQuartz2D(this);
    492 # else
    493             m_pFrameBuffer = new UIFrameBufferQuartz2D(this);
    494 # endif
    495             break;
    496 #endif /* VBOX_GUI_USE_QUARTZ2D */
    497         default:
    498             AssertReleaseMsgFailed(("Render mode must be valid: %d\n", vboxGlobal().vmRenderMode()));
    499             LogRel(("Invalid render mode: %d\n", vboxGlobal().vmRenderMode()));
    500             qApp->exit(1);
    501             break;
    502     }
    503     if (m_pFrameBuffer)
    504     {
    505 #ifdef VBOX_WITH_VIDEOHWACCEL
    506         CFramebuffer fb(NULL);
    507         if (m_fAccelerate2DVideo)
    508         {
    509             LONG XOrigin, YOrigin;
    510             /* check if the framebuffer is already assigned
    511              * in this case we do not need to re-assign it
    512              * neither do we need to AddRef */
    513             display.GetFramebuffer(m_uScreenId, fb, XOrigin, YOrigin);
    514         }
    515         if (fb.raw() != m_pFrameBuffer) /* <-this will evaluate to true iff m_fAccelerate2DVideo is disabled or iff no framebuffer is yet assigned */
    516 #endif
    517         {
    518             m_pFrameBuffer->AddRef();
    519         }
    520 
    521         /* always perform SetFramebuffer to ensure 3D gets notified */
    522         display.SetFramebuffer(m_uScreenId, CFramebuffer(m_pFrameBuffer));
    523     }
    524 
    525 #ifdef Q_WS_X11
    526     /* Processing pseudo resize-event to synchronize frame-buffer
    527      * with stored framebuffer size in case of machine state was 'saved': */
    528     if (session().GetMachine().GetState() == KMachineState_Saved)
    529     {
    530         QSize size = guestSizeHint();
    531         UIResizeEvent event(FramebufferPixelFormat_Opaque, NULL, 0, 0, size.width(), size.height());
    532         frameBuffer()->resizeEvent(&event);
    533     }
    534 #endif /* Q_WS_X11 */
    535 }
    536 
    537 void UIMachineView::prepareCommon()
    538 {
    539     /* Prepare view frame: */
    540     setFrameStyle(QFrame::NoFrame);
     550{
     551    /* Prepare: */
     552    prepareCommon();
     553
     554    /* Load settings: */
     555    loadSettings();
     556
     557    /* Initialize: */
     558    sltMachineStateChanged();
     559}
     560
     561/* Keyboard-handler destructor: */
     562UIKeyboardHandler::~UIKeyboardHandler()
     563{
     564    /* Cleanup: */
     565    cleanupCommon();
     566}
     567
     568void UIKeyboardHandler::prepareCommon()
     569{
     570    /* Machine state-change updater: */
     571    connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged()));
    541572
    542573    /* Pressed keys: */
    543574    ::memset(m_pressedKeys, 0, sizeof(m_pressedKeys));
    544 
    545     /* Setup palette: */
    546     QPalette palette(viewport()->palette());
    547     palette.setColor(viewport()->backgroundRole(), Qt::black);
    548     viewport()->setPalette(palette);
    549 
    550     /* Setup focus policy: */
    551     setFocusPolicy(Qt::WheelFocus);
    552 
    553 #if defined Q_WS_PM
    554     bool ok = VBoxHlpInstallKbdHook(0, winId(), UM_PREACCEL_CHAR);
    555     Assert(ok);
    556     NOREF(ok);
     575}
     576
     577void UIKeyboardHandler::loadSettings()
     578{
     579    /* Global settings: */
     580#ifdef Q_WS_X11
     581    /* Initialize the X keyboard subsystem: */
     582    initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes"));
    557583#endif
    558584
    559     /* Register mouse-handler: */
    560     machineLogic()->mouseHandler()->addMachineView(screenId(), this);
    561 }
    562 
    563 void UIMachineView::prepareFilters()
    564 {
    565     /* Enable MouseMove events: */
    566     viewport()->setMouseTracking(true);
    567 
    568     /* QScrollView does the below on its own, but let's
    569      * do it anyway for the case it will not do it in the future: */
    570     viewport()->installEventFilter(this);
    571 
    572     /* We want to be notified on some parent's events: */
    573     machineWindowWrapper()->machineWindow()->installEventFilter(this);
    574 }
    575 
    576 void UIMachineView::prepareConsoleConnections()
    577 {
    578     /* Machine state-change updater: */
    579     connect(uisession(), SIGNAL(sigMachineStateChange()), this, SLOT(sltMachineStateChanged()));
    580 }
    581 
    582 void UIMachineView::loadMachineViewSettings()
    583 {
    584     /* Global settings: */
    585     {
    586 #ifdef Q_WS_X11
    587         /* Initialize the X keyboard subsystem: */
    588         initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes"));
    589 #endif
    590 
    591         /* Remember the desktop geometry and register for geometry
    592          * change events for telling the guest about video modes we like: */
    593         QString desktopGeometry = vboxGlobal().settings().publicProperty("GUI/MaxGuestResolution");
    594         if ((desktopGeometry == QString::null) || (desktopGeometry == "auto"))
    595             setDesktopGeometry(DesktopGeo_Automatic, 0, 0);
    596         else if (desktopGeometry == "any")
    597             setDesktopGeometry(DesktopGeo_Any, 0, 0);
    598         else
    599         {
    600             int width = desktopGeometry.section(',', 0, 0).toInt();
    601             int height = desktopGeometry.section(',', 1, 1).toInt();
    602             setDesktopGeometry(DesktopGeo_Fixed, width, height);
    603         }
    604     }
    605 
    606     /* Exatra data settings: */
     585    /* Extra data settings: */
    607586    {
    608587        /* CAD settings: */
    609588        QString passCAD = session().GetConsole().GetMachine().GetExtraData(VBoxDefs::GUI_PassCAD);
    610         if (!passCAD.isEmpty() && ((passCAD != "false") || (passCAD != "no")))
     589        if (!passCAD.isEmpty() && passCAD != "false" && passCAD != "no")
    611590            m_fPassCAD = true;
    612591    }
    613592}
    614593
    615 void UIMachineView::cleanupCommon()
    616 {
    617     /* Unregister mouse-handler: */
    618     machineLogic()->mouseHandler()->delMachineView(screenId());
    619 
    620 #ifdef Q_WS_PM
    621     bool ok = VBoxHlpUninstallKbdHook(0, winId(), UM_PREACCEL_CHAR);
    622     Assert(ok);
    623     NOREF(ok);
    624 #endif /* Q_WS_PM */
    625 
    626 #ifdef Q_WS_WIN
    627     if (gKbdHook)
    628         UnhookWindowsHookEx(gKbdHook);
    629     gView = 0;
    630 #endif /* Q_WS_WIN */
    631 
    632 #ifdef Q_WS_MAC
    633     /* We have to make sure the callback for the keyboard events is released
    634      * when closing this view. */
     594void UIKeyboardHandler::cleanupCommon()
     595{
     596#if defined(Q_WS_WIN)
     597    /* Cleaning keyboard-hook: */
     598    if (m_keyboardHook)
     599    {
     600        UnhookWindowsHookEx(m_keyboardHook);
     601        m_keyboardHook = NULL;
     602    }
     603#elif defined(Q_WS_MAC)
     604    /* We have to make sure the callback for the keyboard events
     605     * is released when closing this view. */
    635606    if (m_fKeyboardGrabbed)
    636         darwinGrabKeyboardEvents (false);
    637 #endif /* Q_WS_MAC */
    638 }
    639 
    640 void UIMachineView::cleanupFrameBuffer()
    641 {
    642     if (m_pFrameBuffer)
    643     {
    644         /* Process pending frame-buffer resize events: */
    645         QApplication::sendPostedEvents(this, VBoxDefs::ResizeEventType);
    646 #ifdef VBOX_WITH_VIDEOHWACCEL
    647         if (m_fAccelerate2DVideo)
    648         {
    649             /* When 2D is enabled we do not re-create Framebuffers. This is done to
    650              * 1. avoid 2D command loss during the time slot when no framebuffer is assigned to the display
    651              * 2. make it easier to preserve the current 2D state */
    652             Assert(m_pFrameBuffer == uisession()->frameBuffer(screenId()));
    653             m_pFrameBuffer->setView(NULL);
    654         }
    655         else
     607        darwinGrabKeyboardEvents(false);
    656608#endif
    657         {
    658             /* Warn framebuffer about its no more necessary: */
    659             m_pFrameBuffer->setDeleted(true);
    660             /* Detach framebuffer from Display: */
    661             CDisplay display = session().GetConsole().GetDisplay();
    662             display.SetFramebuffer(m_uScreenId, CFramebuffer(NULL));
    663             /* Release the reference: */
    664             m_pFrameBuffer->Release();
    665 //          delete m_pFrameBuffer; // TODO_NEW_CORE: possibly necessary to really cleanup
    666             m_pFrameBuffer = NULL;
    667         }
    668     }
    669 }
    670 
    671 bool UIMachineView::event(QEvent *pEvent)
    672 {
    673     switch (pEvent->type())
    674     {
    675         case QEvent::FocusIn:
    676         {
    677             if (uisession()->isRunning())
    678                 focusEvent(true);
    679             break;
    680         }
    681         case QEvent::FocusOut:
    682         {
    683             if (uisession()->isRunning())
    684                 focusEvent(false);
    685             else
    686             {
    687                 /* Release the host key and all other pressed keys too even when paused
    688                  * (otherwise, we will get stuck keys in the guest when doing sendChangedKeyStates() on resume
    689                  * because key presses were already recorded in m_pressedKeys but key releases will most likely
    690                  * not reach us but the new focus window instead): */
    691                 releaseAllPressedKeys(true /* including host key? */);
    692             }
    693             break;
    694         }
    695 
    696         case VBoxDefs::RepaintEventType:
    697         {
    698             UIRepaintEvent *pPaintEvent = static_cast<UIRepaintEvent*>(pEvent);
    699             viewport()->repaint(pPaintEvent->x() - contentsX(), pPaintEvent->y() - contentsY(),
    700                                 pPaintEvent->width(), pPaintEvent->height());
    701 
    702             return true;
    703         }
    704 
    705 #ifdef VBOX_WITH_VIDEOHWACCEL
    706         case VBoxDefs::VHWACommandProcessType:
    707         {
    708             m_pFrameBuffer->doProcessVHWACommand(pEvent);
    709             return true;
    710         }
    711 #endif
    712 
    713         case QEvent::KeyPress:
    714         case QEvent::KeyRelease:
    715         {
    716             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    717 
    718 #ifdef Q_WS_PM
    719             // TODO: that a temporary solution to send Alt+Tab and friends to the guest.
    720             // The proper solution is to write a keyboard driver that will steal these combos from the host
    721             // (it's impossible to do so using hooks on OS/2):
    722 
    723             if (m_bIsHostkeyPressed)
    724             {
    725                 bool pressed = pEvent->type() == QEvent::KeyPress;
    726                 CKeyboard keyboard = session().GetConsole().GetKeyboard();
    727 
    728                 /* Whether the host key is Shift so that it will modify the hot key values?
    729                  * Note that we don't distinguish between left and right shift here (too much hassle): */
    730                 const bool kShift = (m_globalSettings.hostKey() == VK_SHIFT ||
    731                                     m_globalSettings.hostKey() == VK_LSHIFT) &&
    732                                     (pKeyEvent->state() & Qt::ShiftModifier);
    733                 /* define hot keys according to the Shift state */
    734                 const int kAltTab      = kShift ? Qt::Key_Exclam     : Qt::Key_1;
    735                 const int kAltShiftTab = kShift ? Qt::Key_At         : Qt::Key_2;
    736                 const int kCtrlEsc     = kShift ? Qt::Key_AsciiTilde : Qt::Key_QuoteLeft;
    737 
    738                 /* Simulate Alt+Tab on Host+1 and Alt+Shift+Tab on Host+2 */
    739                 if (pKeyEvent->key() == kAltTab || pKeyEvent->key() == kAltShiftTab)
    740                 {
    741                     if (pressed)
     609}
     610
     611/* Machine-logic getter: */
     612UIMachineLogic* UIKeyboardHandler::machineLogic() const
     613{
     614    return m_pMachineLogic;
     615}
     616
     617/* UI Session getter: */
     618UISession* UIKeyboardHandler::uisession() const
     619{
     620    return machineLogic()->uisession();
     621}
     622
     623/* Main Session getter: */
     624CSession& UIKeyboardHandler::session() const
     625{
     626    return uisession()->session();
     627}
     628
     629/* Event handler for prepared listener(s): */
     630bool UIKeyboardHandler::eventFilter(QObject *pWatchedObject, QEvent *pEvent)
     631{
     632    /* Check if pWatchedObject object is window: */
     633    if (UIMachineWindow *pWatchedWindow = isItListenedWindow(pWatchedObject))
     634    {
     635        /* Get corresponding screen index: */
     636        ulong uScreenId = m_windows.key(pWatchedWindow);
     637        NOREF(uScreenId);
     638        /* Handle window events: */
     639        switch (pEvent->type())
     640        {
     641#if defined(Q_WS_WIN)
     642            /* Install/uninstall low-level keyboard-hook on every activation/deactivation to:
     643             * a) avoid excess hook calls when we're not active and;
     644             * b) be always in front of any other possible hooks. */
     645            case QEvent::WindowActivate:
     646            {
     647                /* If keyboard hook is NOT currently created;
     648                 * Or created but NOT for that window: */
     649                if (!m_keyboardHook || m_iKeyboardHookViewIndex != uScreenId)
     650                {
     651                    /* If keyboard-hook present: */
     652                    if (m_keyboardHook)
    742653                    {
    743                         /* Send the Alt press to the guest */
    744                         if (!(m_pressedKeysCopy[0x38] & IsKeyPressed))
    745                         {
    746                             /* Store the press in *Copy to have it automatically
    747                              * released when the Host key is released: */
    748                             m_pressedKeysCopy[0x38] |= IsKeyPressed;
    749                             keyboard.PutScancode(0x38);
    750                         }
    751 
    752                         /* Make sure Shift is pressed if it's Key_2 and released if it's Key_1: */
    753                         if (pKeyEvent->key() == kAltTab &&
    754                             (m_pressedKeysCopy[0x2A] & IsKeyPressed))
    755                         {
    756                             m_pressedKeysCopy[0x2A] &= ~IsKeyPressed;
    757                             keyboard.PutScancode(0xAA);
    758                         }
    759                         else
    760                         if (pKeyEvent->key() == kAltShiftTab &&
    761                             !(m_pressedKeysCopy[0x2A] & IsKeyPressed))
    762                         {
    763                             m_pressedKeysCopy[0x2A] |= IsKeyPressed;
    764                             keyboard.PutScancode(0x2A);
    765                         }
     654                        /* We should remove existing keyboard-hook first: */
     655                        UnhookWindowsHookEx(m_keyboardHook);
     656                        m_keyboardHook = NULL;
    766657                    }
    767 
    768                     keyboard.PutScancode(pressed ? 0x0F : 0x8F);
    769 
    770                     pKeyEvent->accept();
    771                     return true;
    772                 }
    773 
    774                 /* Simulate Ctrl+Esc on Host+Tilde */
    775                 if (pKeyEvent->key() == kCtrlEsc)
    776                 {
    777                     /* Send the Ctrl press to the guest */
    778                     if (pressed && !(m_pressedKeysCopy[0x1d] & IsKeyPressed))
    779                     {
    780                         /* store the press in *Copy to have it automatically
    781                          * released when the Host key is released */
    782                         m_pressedKeysCopy[0x1d] |= IsKeyPressed;
    783                         keyboard.PutScancode(0x1d);
    784                     }
    785 
    786                     keyboard.PutScancode(pressed ? 0x01 : 0x81);
    787 
    788                     pKeyEvent->accept();
    789                     return true;
    790                 }
    791             }
    792 #endif /* Q_WS_PM */
    793 
    794             if (m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyPress)
    795             {
    796                 /* Passing F1-F12 keys to the guest: */
    797                 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F12)
    798                 {
    799                     QVector <LONG> combo(6);
    800                     combo[0] = 0x1d; /* Ctrl down */
    801                     combo[1] = 0x38; /* Alt  down */
    802                     combo[4] = 0xb8; /* Alt  up   */
    803                     combo[5] = 0x9d; /* Ctrl up   */
    804                     if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F10)
    805                     {
    806                         combo[2] = 0x3b + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 down */
    807                         combo[3] = 0xbb + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 up   */
    808                     }
    809                     /* some scan slice */
    810                     else if (pKeyEvent->key() >= Qt::Key_F11 && pKeyEvent->key() <= Qt::Key_F12)
    811                     {
    812                         combo[2] = 0x57 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 down */
    813                         combo[3] = 0xd7 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 up   */
    814                     }
    815                     else
    816                         Assert(0);
    817 
    818                     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    819                     keyboard.PutScancodes(combo);
    820                 }
    821 
    822                 /* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */
    823                 machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(pKeyEvent->key()));
    824             }
    825             else if (!m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyRelease)
    826             {
    827                 /* Show a possible warning on key release which seems to be more expected by the end user: */
    828                 if (uisession()->isPaused())
    829                 {
    830                     /* Iif the reminder is disabled we pass the event to Qt to enable normal
    831                      * keyboard functionality (for example, menu access with Alt+Letter): */
    832                     if (!vboxProblem().remindAboutPausedVMInput())
    833                         break;
    834                 }
    835             }
    836 
    837             pKeyEvent->accept();
    838             return true;
    839         }
    840 
    841 #ifdef Q_WS_MAC
    842         /* posted OnShowWindow */
    843         case VBoxDefs::ShowWindowEventType:
    844         {
    845             /* Dunno what Qt3 thinks a window that has minimized to the dock should be - it is not hidden,
    846              * neither is it minimized. OTOH it is marked shown and visible, but not activated.
    847              * This latter isn't of much help though, since at this point nothing is marked activated.
    848              * I might have overlooked something, but I'm buggered what if I know what. So, I'll just always
    849              * show & activate the stupid window to make it get out of the dock when the user wishes to show a VM: */
    850             window()->show();
    851             window()->activateWindow();
    852             return true;
    853         }
    854 #endif
    855 
    856         default:
    857             break;
    858     }
    859 
    860     return QAbstractScrollArea::event(pEvent);
    861 }
    862 
    863 bool UIMachineView::eventFilter(QObject *pWatched, QEvent *pEvent)
    864 {
    865 #ifdef VBOX_WITH_VIDEOHWACCEL
    866     if (pWatched == viewport())
    867     {
    868         switch (pEvent->type())
    869         {
    870             case QEvent::Resize:
    871             {
    872                 if (m_pFrameBuffer)
    873                     m_pFrameBuffer->viewportResized(static_cast<QResizeEvent*>(pEvent));
    874                 break;
    875             }
    876             default:
    877                 break;
    878         }
    879     }
    880 #endif /* VBOX_WITH_VIDEOHWACCEL */
    881     if (pWatched == machineWindowWrapper()->machineWindow())
    882     {
    883         switch (pEvent->type())
    884         {
    885             case QEvent::WindowStateChange:
    886             {
    887                 /* During minimizing and state restoring machineWindowWrapper() gets
    888                  * the focus which belongs to console view window, so returning it properly. */
    889                 QWindowStateChangeEvent *pWindowEvent = static_cast<QWindowStateChangeEvent*>(pEvent);
    890                 if (pWindowEvent->oldState() & Qt::WindowMinimized)
    891                 {
    892                     if (QApplication::focusWidget())
    893                     {
    894                         QApplication::focusWidget()->clearFocus();
    895                         qApp->processEvents();
    896                     }
    897                     QTimer::singleShot(0, this, SLOT(setFocus()));
    898                 }
    899                 break;
    900             }
    901 #ifdef Q_WS_WIN
    902             /* Install/uninstall low-level kbd hook on every activation/deactivation to:
    903              * a) avoid excess hook calls when we're not active and
    904              * b) be always in front of any other possible hooks */
    905             case QEvent::WindowActivate:
    906             {
    907                 gView = this;
    908                 gKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0);
    909                 AssertMsg(gKbdHook, ("SetWindowsHookEx(): err=%d", GetLastError()));
     658                    /* Register new keyboard-hook: */
     659                    m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0);
     660                    AssertMsg(m_keyboardHook, ("SetWindowsHookEx(): err=%d", GetLastError()));
     661                    /* Remember which view had captured keyboard: */
     662                    m_iKeyboardHookViewIndex = uScreenId;
     663                }
    910664                break;
    911665            }
    912666            case QEvent::WindowDeactivate:
    913667            {
    914                 if (gKbdHook)
    915                 {
    916                     UnhookWindowsHookEx(gKbdHook);
    917                     gKbdHook = NULL;
    918                     if (gView == this)
    919                         gView = 0;
    920                 }
    921                 break;
    922             }
    923 #endif /* Q_WS_WIN */
    924 #ifdef Q_WS_MAC
    925             /* Install/remove the keyboard event handler: */
     668                /* If keyboard is currently captured: */
     669                if (m_keyboardHook && m_iKeyboardHookViewIndex == uScreenId)
     670                {
     671                    /* We should remove existing keyboard-hook: */
     672                    UnhookWindowsHookEx(m_keyboardHook);
     673                    m_keyboardHook = NULL;
     674                    /* Remember what there is no window captured keyboard: */
     675                    m_iKeyboardHookViewIndex = -1;
     676                }
     677                break;
     678            }
     679#elif defined(Q_WS_MAC)
     680            /* Install the keyboard event handler: */
    926681            case QEvent::WindowActivate:
    927682                darwinGrabKeyboardEvents(true);
    928683                break;
     684            /* Remove the keyboard event handler: */
    929685            case QEvent::WindowDeactivate:
    930686                darwinGrabKeyboardEvents(false);
    931687                break;
    932 #endif /* Q_WS_MAC */
     688#endif
    933689            default:
    934690                break;
     
    936692    }
    937693
    938     return QAbstractScrollArea::eventFilter (pWatched, pEvent);
    939 }
    940 
    941 void UIMachineView::sltMachineStateChanged()
    942 {
    943     /* Get machine state: */
    944     KMachineState state = uisession()->machineState();
    945     switch (state)
    946     {
    947         case KMachineState_Paused:
    948         case KMachineState_TeleportingPausedVM:
    949         {
    950             if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode &&  m_pFrameBuffer &&
    951                 (state != KMachineState_TeleportingPausedVM || m_previousState != KMachineState_Teleporting))
    952             {
    953                 /* Take a screen snapshot. Note that TakeScreenShot() always needs a 32bpp image: */
    954                 QImage shot = QImage(m_pFrameBuffer->width(), m_pFrameBuffer->height(), QImage::Format_RGB32);
    955                 /* If TakeScreenShot fails or returns no image, just show a black image. */
    956                 shot.fill(0);
    957                 CDisplay dsp = session().GetConsole().GetDisplay();
    958                 dsp.TakeScreenShot(screenId(), shot.bits(), shot.width(), shot.height());
    959                 /* TakeScreenShot() may fail if, e.g. the Paused notification was delivered
    960                  * after the machine execution was resumed. It's not fatal: */
    961                 if (dsp.isOk())
    962                 {
    963                     dimImage(shot);
    964                 }
    965                 m_pauseShot = QPixmap::fromImage(shot);
    966                 /* Fully repaint to pick up m_pauseShot: */
    967                 viewport()->repaint();
    968             }
    969             /* Reuse the focus event handler to uncapture keyboard: */
    970             if (hasFocus())
    971                 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);
    972             break;
    973         }
    974         case KMachineState_Stuck:
    975         {
    976             /* Reuse the focus event handler to uncapture keyboard: */
    977             if (hasFocus())
    978                 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);
    979             break;
    980         }
    981         case KMachineState_Running:
    982         {
    983             if (   m_previousState == KMachineState_Paused
    984                 || m_previousState == KMachineState_TeleportingPausedVM
    985                 || m_previousState == KMachineState_Restoring)
    986             {
    987                 if (vboxGlobal().vmRenderMode() != VBoxDefs::TimerMode && m_pFrameBuffer)
    988                 {
    989                     /* Reset the pixmap to free memory: */
    990                     m_pauseShot = QPixmap();
    991                     /* Ask for full guest display update (it will also update
    992                      * the viewport through IFramebuffer::NotifyUpdate): */
    993                     CDisplay dsp = session().GetConsole().GetDisplay();
    994                     dsp.InvalidateAndUpdate();
    995                 }
    996             }
    997             /* Reuse the focus event handler to capture keyboard: */
    998             if (hasFocus())
    999                 focusEvent(true /* aHasFocus */);
    1000             break;
    1001         }
    1002         default:
    1003             break;
    1004     }
    1005 
    1006     m_previousState = state;
    1007 }
    1008 
    1009 void UIMachineView::focusEvent(bool fHasFocus, bool fReleaseHostKey /* = true */)
    1010 {
    1011     if (fHasFocus)
    1012     {
    1013 #ifdef Q_WS_WIN32
    1014         if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow())
    1015 #else
    1016         if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture())
    1017 #endif
    1018         {
    1019             captureKbd(true);
    1020         }
    1021 
    1022         /* Reset the single-time disable capture flag: */
    1023         if (uisession()->isAutoCaptureDisabled())
    1024             uisession()->setAutoCaptureDisabled(false);
    1025     }
    1026694    else
    1027     {
    1028         captureKbd(false, false);
    1029         releaseAllPressedKeys(fReleaseHostKey);
    1030     }
    1031 }
    1032 
    1033 bool UIMachineView::keyEvent(int iKey, uint8_t uScan, int fFlags, wchar_t *pUniKey /* = NULL */)
    1034 {
    1035     const bool isHostKey = iKey == m_globalSettings.hostKey();
    1036 
    1037     LONG buf[16];
    1038     LONG *codes = buf;
    1039     uint count = 0;
    1040     uint8_t whatPressed = 0;
    1041 
    1042     if (!isHostKey && !m_bIsHostkeyPressed)
    1043     {
    1044         if (fFlags & KeyPrint)
    1045         {
    1046             static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 };
    1047             static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA };
    1048             if (fFlags & KeyPressed)
    1049             {
    1050                 codes = PrintMake;
    1051                 count = SIZEOF_ARRAY(PrintMake);
    1052             }
    1053             else
    1054             {
    1055                 codes = PrintBreak;
    1056                 count = SIZEOF_ARRAY(PrintBreak);
    1057             }
    1058         }
    1059         else if (fFlags & KeyPause)
    1060         {
    1061             if (fFlags & KeyPressed)
    1062             {
    1063                 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 };
    1064                 codes = Pause;
    1065                 count = SIZEOF_ARRAY(Pause);
    1066             }
    1067             else
    1068             {
    1069                 /* Pause shall not produce a break code */
    1070                 return true;
    1071             }
    1072         }
    1073         else
    1074         {
    1075             if (fFlags & KeyPressed)
    1076             {
    1077                 /* Check if the guest has the same view on the modifier keys (NumLock,
    1078                  * CapsLock, ScrollLock) as the X server. If not, send KeyPress events
    1079                  * to synchronize the state. */
    1080                 fixModifierState(codes, &count);
    1081             }
    1082 
    1083             /* Check if it's C-A-D and GUI/PassCAD is not true */
    1084             if (!m_fPassCAD &&
    1085                 uScan == 0x53 /* Del */ &&
    1086                 ((m_pressedKeys[0x38] & IsKeyPressed) /* Alt */ ||
    1087                  (m_pressedKeys[0x38] & IsExtKeyPressed)) &&
    1088                 ((m_pressedKeys[0x1d] & IsKeyPressed) /* Ctrl */ ||
    1089                  (m_pressedKeys[0x1d] & IsExtKeyPressed)))
    1090             {
    1091                 /* Use the C-A-D combination as a last resort to get the
    1092                  * keyboard and mouse back to the host when the user forgets
    1093                  * the Host Key. Note that it's always possible to send C-A-D
    1094                  * to the guest using the Host+Del combination. BTW, it would
    1095                  * be preferrable to completely ignore C-A-D in guests, but
    1096                  * that's not possible because we cannot predict what other
    1097                  * keys will be pressed next when one of C, A, D is held. */
    1098                 if (uisession()->isRunning() && m_bIsKeyboardCaptured)
    1099                 {
    1100                     captureKbd(false);
    1101                     if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()))
    1102                         machineLogic()->mouseHandler()->captureMouse(screenId());
    1103                 }
    1104 
    1105                 return true;
    1106             }
    1107 
    1108             /* Process the scancode and update the table of pressed keys: */
    1109             whatPressed = IsKeyPressed;
    1110 
    1111             if (fFlags & KeyExtended)
    1112             {
    1113                 codes[count++] = 0xE0;
    1114                 whatPressed = IsExtKeyPressed;
    1115             }
    1116 
    1117             if (fFlags & KeyPressed)
    1118             {
    1119                 codes[count++] = uScan;
    1120                 m_pressedKeys[uScan] |= whatPressed;
    1121             }
    1122             else
    1123             {
    1124                 /* If we haven't got this key's press message, we ignore its release: */
    1125                 if (!(m_pressedKeys[uScan] & whatPressed))
    1126                     return true;
    1127                 codes[count++] = uScan | 0x80;
    1128                 m_pressedKeys[uScan] &= ~whatPressed;
    1129             }
    1130 
    1131             if (m_bIsKeyboardCaptured)
    1132                 m_pressedKeys[uScan] |= IsKbdCaptured;
    1133             else
    1134                 m_pressedKeys[uScan] &= ~IsKbdCaptured;
    1135         }
    1136     }
    1137     else
    1138     {
    1139         /* Currently this is used in winLowKeyboardEvent() only: */
    1140         m_bIsHostkeyInCapture = m_bIsKeyboardCaptured;
    1141     }
    1142 
    1143     bool emitSignal = false;
    1144     int hotkey = 0;
    1145 
    1146     /* Process the host key: */
    1147     if (fFlags & KeyPressed)
    1148     {
    1149         if (isHostKey)
    1150         {
    1151             if (!m_bIsHostkeyPressed)
    1152             {
    1153                 m_bIsHostkeyPressed = m_bIsHostkeyAlone = true;
     695
     696    /* Check if pWatchedObject object is view: */
     697    if (UIMachineView *pWatchedView = isItListenedView(pWatchedObject))
     698    {
     699        /* Get corresponding screen index: */
     700        ulong uScreenId = m_views.key(pWatchedView);
     701        NOREF(uScreenId);
     702        /* Handle view events: */
     703        switch (pEvent->type())
     704        {
     705            case QEvent::FocusIn:
    1154706                if (uisession()->isRunning())
    1155                     saveKeyStates();
    1156                 emitSignal = true;
    1157             }
    1158         }
    1159         else
    1160         {
    1161             if (m_bIsHostkeyPressed)
    1162             {
    1163                 if (m_bIsHostkeyAlone)
    1164                 {
    1165                     hotkey = iKey;
    1166                     m_bIsHostkeyAlone = false;
    1167                 }
    1168             }
    1169         }
    1170     }
    1171     else
    1172     {
    1173         if (isHostKey)
    1174         {
    1175             if (m_bIsHostkeyPressed)
    1176             {
    1177                 m_bIsHostkeyPressed = false;
    1178 
    1179                 if (m_bIsHostkeyAlone)
    1180                 {
     707                {
     708                    /* Capture keyboard: */
     709#ifdef Q_WS_WIN
     710                    if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture() &&
     711                        GetAncestor(pWatchedView->winId(), GA_ROOT) == GetForegroundWindow())
     712#else /* Q_WS_WIN */
     713                    if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture())
     714#endif /* !Q_WS_WIN */
     715                        captureKeyboard(uScreenId);
     716                    /* Reset the single-time disable capture flag: */
     717                    if (uisession()->isAutoCaptureDisabled())
     718                        uisession()->setAutoCaptureDisabled(false);
     719                }
     720                break;
     721            case QEvent::FocusOut:
     722                /* Release keyboard: */
     723                if (uisession()->isRunning())
     724                    releaseKeyboard();
     725                /* And all pressed keys: */
     726                releaseAllPressedKeys(true);
     727                break;
     728            case QEvent::KeyPress:
     729            case QEvent::KeyRelease:
     730            {
     731                QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
     732
     733                if (m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyPress)
     734                {
     735                    /* Passing F1-F12 keys to the guest: */
     736                    if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F12)
     737                    {
     738                        QVector <LONG> combo(6);
     739                        combo[0] = 0x1d; /* Ctrl down */
     740                        combo[1] = 0x38; /* Alt  down */
     741                        combo[4] = 0xb8; /* Alt  up   */
     742                        combo[5] = 0x9d; /* Ctrl up   */
     743                        if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F10)
     744                        {
     745                            combo[2] = 0x3b + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 down */
     746                            combo[3] = 0xbb + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 up   */
     747                        }
     748                        /* There is some scan slice between F10 and F11 keys, so its separated: */
     749                        else if (pKeyEvent->key() >= Qt::Key_F11 && pKeyEvent->key() <= Qt::Key_F12)
     750                        {
     751                            combo[2] = 0x57 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 down */
     752                            combo[3] = 0xd7 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 up   */
     753                        }
     754                        CKeyboard keyboard = session().GetConsole().GetKeyboard();
     755                        keyboard.PutScancodes(combo);
     756                    }
     757                    /* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */
     758                    machineLogic()->actionsPool()->processHotKey(QKeySequence(pKeyEvent->key()));
     759                }
     760                else if (!m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyRelease)
     761                {
     762                    /* Show a possible warning on key release which seems to be more expected by the end user: */
    1181763                    if (uisession()->isPaused())
    1182764                    {
    1183                         vboxProblem().remindAboutPausedVMInput();
     765                        /* If the reminder is disabled we pass the event to Qt to enable normal
     766                         * keyboard functionality (for example, menu access with Alt+Letter): */
     767                        if (!vboxProblem().remindAboutPausedVMInput())
     768                            break;
    1184769                    }
    1185                     else if (uisession()->isRunning())
    1186                     {
    1187                         bool captured = m_bIsKeyboardCaptured;
    1188                         bool ok = true;
    1189                         if (!captured)
    1190                         {
    1191                             /* temporarily disable auto capture that will take
    1192                              * place after this dialog is dismissed because
    1193                              * the capture state is to be defined by the
    1194                              * dialog result itself */
    1195                             uisession()->setAutoCaptureDisabled(true);
    1196                             bool autoConfirmed = false;
    1197                             ok = vboxProblem().confirmInputCapture (&autoConfirmed);
    1198                             if (autoConfirmed)
    1199                                 uisession()->setAutoCaptureDisabled(false);
    1200                             /* otherwise, the disable flag will be reset in
    1201                              * the next console view's foucs in event (since
    1202                              * may happen asynchronously on some platforms,
    1203                              * after we return from this code) */
    1204                         }
    1205 
    1206                         if (ok)
    1207                         {
    1208                             captureKbd (!captured, false);
    1209                             if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()))
    1210                             {
    1211 #ifdef Q_WS_X11
    1212                                 /* make sure that pending FocusOut events from the
    1213                                  * previous message box are handled, otherwise the
    1214                                  * mouse is immediately ungrabbed. */
    1215                                 qApp->processEvents();
    1216 #endif
    1217                                 if (m_bIsKeyboardCaptured)
    1218                                     machineLogic()->mouseHandler()->captureMouse(screenId());
    1219                                 else
    1220                                     machineLogic()->mouseHandler()->releaseMouse();
    1221                             }
    1222                         }
    1223                     }
    1224                 }
    1225 
    1226                 if (uisession()->isRunning())
    1227                     sendChangedKeyStates();
    1228 
    1229                 emitSignal = true;
    1230             }
    1231         }
    1232         else
    1233         {
    1234             if (m_bIsHostkeyPressed)
    1235                 m_bIsHostkeyAlone = false;
    1236         }
    1237     }
    1238 
    1239     /* emit the keyboard state change signal */
    1240     if (emitSignal)
    1241         emitKeyboardStateChanged();
    1242 
    1243     /* Process Host+<key> shortcuts. currently, <key> is limited to
    1244      * alphanumeric chars. Other Host+<key> combinations are handled in
    1245      * event(). */
    1246     if (hotkey)
    1247     {
    1248         bool processed = false;
    1249 #if defined (Q_WS_WIN32)
    1250         NOREF(pUniKey);
    1251         int n = GetKeyboardLayoutList(0, NULL);
    1252         Assert (n);
    1253         HKL *list = new HKL[n];
    1254         GetKeyboardLayoutList(n, list);
    1255         for (int i = 0; i < n && !processed; i++)
    1256         {
    1257             wchar_t ch;
    1258             static BYTE keys[256] = {0};
    1259             if (!ToUnicodeEx(hotkey, 0, keys, &ch, 1, 0, list[i]) == 1)
    1260                 ch = 0;
    1261             if (ch)
    1262                 processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence((Qt::UNICODE_ACCEL + QChar(ch).toUpper().unicode())));
    1263         }
    1264         delete[] list;
    1265 #elif defined (Q_WS_X11)
    1266         NOREF(pUniKey);
    1267         Display *display = QX11Info::display();
    1268         int keysyms_per_keycode = getKeysymsPerKeycode();
    1269         KeyCode kc = XKeysymToKeycode (display, iKey);
    1270         for (int i = 0; i < keysyms_per_keycode && !processed; i += 2)
    1271         {
    1272             KeySym ks = XKeycodeToKeysym(display, kc, i);
    1273             char ch = 0;
    1274             if (!XkbTranslateKeySym(display, &ks, 0, &ch, 1, NULL) == 1)
    1275                 ch = 0;
    1276             if (ch)
    1277                 QChar c = QString::fromLocal8Bit(&ch, 1)[0];
    1278         }
    1279 #elif defined (Q_WS_MAC)
    1280         if (pUniKey && pUniKey[0] && !pUniKey[1])
    1281             processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode()));
    1282 
    1283         /* Don't consider the hot key as pressed since the guest never saw
    1284          * it. (probably a generic thing) */
    1285         m_pressedKeys[uScan] &= ~whatPressed;
    1286 #endif
    1287 
    1288         /* Grab the key from Qt if processed, or pass it to Qt otherwise
    1289          * in order to process non-alphanumeric keys in event(), after they are
    1290          * converted to Qt virtual keys. */
    1291         return processed;
    1292     }
    1293 
    1294     /* No more to do, if the host key is in action or the VM is paused: */
    1295     if (m_bIsHostkeyPressed || isHostKey || uisession()->isPaused())
    1296     {
    1297         /* Grab the key from Qt and from VM if it's a host key,
    1298          * otherwise just pass it to Qt */
    1299         return isHostKey;
    1300     }
    1301 
    1302     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    1303     Assert(!keyboard.isNull());
    1304 
    1305 #if defined (Q_WS_WIN32)
    1306     /* send pending WM_PAINT events */
    1307     ::UpdateWindow(viewport()->winId());
    1308 #endif
    1309 
    1310     std::vector <LONG> scancodes(codes, &codes[count]);
    1311     keyboard.PutScancodes(QVector<LONG>::fromStdVector(scancodes));
    1312 
    1313     /* Grab the key from Qt: */
    1314     return true;
    1315 }
    1316 
    1317 void UIMachineView::resizeEvent(QResizeEvent *pEvent)
    1318 {
    1319     updateSliders();
    1320     return QAbstractScrollArea::resizeEvent(pEvent);
    1321 }
    1322 
    1323 void UIMachineView::moveEvent(QMoveEvent *pEvent)
    1324 {
    1325     return QAbstractScrollArea::moveEvent(pEvent);
    1326 }
    1327 
    1328 void UIMachineView::paintEvent(QPaintEvent *pPaintEvent)
    1329 {
    1330     if (m_pauseShot.isNull())
    1331     {
    1332         /* Delegate the paint function to the VBoxFrameBuffer interface: */
    1333         if (m_pFrameBuffer)
    1334             m_pFrameBuffer->paintEvent(pPaintEvent);
    1335 #ifdef Q_WS_MAC
    1336         /* Update the dock icon if we are in the running state */
    1337         if (uisession()->isRunning())
    1338             updateDockIcon();
    1339 #endif /* Q_WS_MAC */
    1340         return;
    1341     }
    1342 
    1343 #ifdef VBOX_GUI_USE_QUARTZ2D
    1344     if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode && m_pFrameBuffer)
    1345     {
    1346         m_pFrameBuffer->paintEvent(pPaintEvent);
    1347         updateDockIcon();
    1348     }
    1349     else
    1350 #endif /* VBOX_GUI_USE_QUARTZ2D */
    1351     {
    1352         /* We have a snapshot for the paused state: */
    1353         QRect r = pPaintEvent->rect().intersect(viewport()->rect());
    1354         /* We have to disable paint on screen if we are using the regular painter: */
    1355         bool paintOnScreen = viewport()->testAttribute(Qt::WA_PaintOnScreen);
    1356         viewport()->setAttribute(Qt::WA_PaintOnScreen, false);
    1357         QPainter pnt(viewport());
    1358         pnt.drawPixmap(r.x(), r.y(), m_pauseShot, r.x() + contentsX(), r.y() + contentsY(), r.width(), r.height());
    1359         /* Restore the attribute to its previous state: */
    1360         viewport()->setAttribute(Qt::WA_PaintOnScreen, paintOnScreen);
    1361 #ifdef Q_WS_MAC
    1362         updateDockIcon();
    1363 #endif /* Q_WS_MAC */
    1364     }
    1365 }
    1366 
    1367 #if defined(Q_WS_WIN32)
    1368 
    1369 LRESULT CALLBACK UIMachineView::lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    1370 {
    1371     if (gView && nCode == HC_ACTION && gView->winLowKeyboardEvent(wParam, *(KBDLLHOOKSTRUCT *)lParam))
     770                }
     771                break;
     772            }
     773            default:
     774                break;
     775        }
     776    }
     777
     778    /* Else just propagate to base-class: */
     779    return QObject::eventFilter(pWatchedObject, pEvent);
     780}
     781
     782#if defined(Q_WS_WIN)
     783
     784LRESULT CALLBACK UIKeyboardHandler::lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
     785{
     786    if (nCode == HC_ACTION && m_pKeyboardHandler->winLowKeyboardEvent(wParam, *(KBDLLHOOKSTRUCT*)lParam))
    1372787        return 1;
    1373788
     
    1375790}
    1376791
    1377 bool UIMachineView::winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event)
     792bool UIKeyboardHandler::winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event)
    1378793{
    1379794    /* Sometimes it happens that Win inserts additional events on some key
     
    1387802     * of these strange events.  Let's hope we are not missing anything else
    1388803     * of importance! */
    1389     if (hasFocus() && (event.scanCode & ~0xFF))
     804    if (m_views[m_iKeyboardHookViewIndex]->hasFocus() && (event.scanCode & ~0xFF))
    1390805    {
    1391806        if (event.vkCode == VK_CAPITAL)
     
    1395810    }
    1396811
    1397     if (!m_bIsKeyboardCaptured)
     812    if (!m_fIsKeyboardCaptured)
    1398813        return false;
    1399814
    1400     /* it's possible that a key has been pressed while the keyboard was not
     815    /* It's possible that a key has been pressed while the keyboard was not
    1401816     * captured, but is being released under the capture. Detect this situation
    1402817     * and return false to let Windows process the message normally and update
     
    1409824
    1410825    MSG message;
    1411     message.hwnd = winId();
     826    message.hwnd = m_views[m_iKeyboardHookViewIndex]->winId();
    1412827    message.message = msg;
    1413828    message.wParam = event.vkCode;
     
    1419834        message.lParam &= ~0x1000000;
    1420835
    1421     /* we suppose here that this hook is always called on the main GUI thread */
     836    /* We suppose here that this hook is always called on the main GUI thread */
    1422837    long dummyResult;
    1423     return winEvent(&message, &dummyResult);
    1424 }
    1425 
    1426 bool UIMachineView::winEvent(MSG *aMsg, long* /* aResult */)
    1427 {
    1428     if (!(aMsg->message == WM_KEYDOWN || aMsg->message == WM_SYSKEYDOWN ||
    1429           aMsg->message == WM_KEYUP || aMsg->message == WM_SYSKEYUP))
     838    return m_views[m_iKeyboardHookViewIndex]->winEvent(&message, &dummyResult);
     839}
     840
     841#elif defined(Q_WS_MAC)
     842
     843void UIKeyboardHandler::darwinGrabKeyboardEvents(bool fGrab)
     844{
     845    m_fKeyboardGrabbed = fGrab;
     846    if (fGrab)
     847    {
     848        /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */
     849        ::CGSetLocalEventsSuppressionInterval(0.0);
     850        machineLogic()->mouseHandler()->setMouseCoalescingEnabled(false);
     851
     852        /* Register the event callback/hook and grab the keyboard. */
     853        UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
     854                                                                UIKeyboardHandler::darwinEventHandlerProc, this);
     855
     856        ::DarwinGrabKeyboard(false);
     857    }
     858    else
     859    {
     860        ::DarwinReleaseKeyboard();
     861        UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
     862                                                                  UIKeyboardHandler::darwinEventHandlerProc, this);
     863    }
     864}
     865
     866bool UIKeyboardHandler::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
     867{
     868    UIKeyboardHandler *pKeyboardHandler = (UIKeyboardHandler*)pvUser;
     869    EventRef inEvent = (EventRef)pvCarbonEvent;
     870    UInt32 eventClass = ::GetEventClass(inEvent);
     871
     872    /* Check if this is an application key combo. In that case we will not pass
     873     * the event to the guest, but let the host process it. */
     874    if (::darwinIsApplicationCommand(pvCocoaEvent))
    1430875        return false;
    1431876
    1432     /* Check for the special flag possibly set at the end of this function */
    1433     if (aMsg->lParam & (0x1 << 25))
    1434     {
    1435         aMsg->lParam &= ~(0x1 << 25);
    1436         return false;
    1437     }
    1438 
    1439     int scan = (aMsg->lParam >> 16) & 0x7F;
    1440     /* scancodes 0x80 and 0x00 are ignored */
    1441     if (!scan)
    1442         return true;
    1443 
    1444     int vkey = aMsg->wParam;
    1445 
    1446     /* When one of the SHIFT keys is held and one of the cursor movement
    1447      * keys is pressed, Windows duplicates SHIFT press/release messages,
    1448      * but with the virtual key code set to 0xFF. These virtual keys are also
    1449      * sent in some other situations (Pause, PrtScn, etc.). Ignore such
    1450      * messages. */
    1451     if (vkey == 0xFF)
    1452         return true;
    1453 
    1454     int flags = 0;
    1455     if (aMsg->lParam & 0x1000000)
    1456         flags |= KeyExtended;
    1457     if (!(aMsg->lParam & 0x80000000))
    1458         flags |= KeyPressed;
    1459 
    1460     switch (vkey)
    1461     {
    1462         case VK_SHIFT:
    1463         case VK_CONTROL:
    1464         case VK_MENU:
    1465         {
    1466             /* overcome stupid Win32 modifier key generalization */
    1467             int keyscan = scan;
    1468             if (flags & KeyExtended)
    1469                 keyscan |= 0xE000;
    1470             switch (keyscan)
    1471             {
    1472                 case 0x002A: vkey = VK_LSHIFT; break;
    1473                 case 0x0036: vkey = VK_RSHIFT; break;
    1474                 case 0x001D: vkey = VK_LCONTROL; break;
    1475                 case 0xE01D: vkey = VK_RCONTROL; break;
    1476                 case 0x0038: vkey = VK_LMENU; break;
    1477                 case 0xE038: vkey = VK_RMENU; break;
    1478             }
    1479             break;
    1480         }
    1481         case VK_NUMLOCK:
    1482             /* Win32 sets the extended bit for the NumLock key. Reset it. */
    1483             flags &= ~KeyExtended;
    1484             break;
    1485         case VK_SNAPSHOT:
    1486             flags |= KeyPrint;
    1487             break;
    1488         case VK_PAUSE:
    1489             flags |= KeyPause;
    1490             break;
    1491     }
    1492 
    1493     bool result = keyEvent(vkey, scan, flags);
    1494     if (!result && m_bIsKeyboardCaptured)
    1495     {
    1496         /* keyEvent() returned that it didn't process the message, but since the
    1497          * keyboard is captured, we don't want to pass it to Windows. We just want
    1498          * to let Qt process the message (to handle non-alphanumeric <HOST>+key
    1499          * shortcuts for example). So send it direcltly to the window with the
    1500          * special flag in the reserved area of lParam (to avoid recursion). */
    1501         ::SendMessage(aMsg->hwnd, aMsg->message,
    1502                       aMsg->wParam, aMsg->lParam | (0x1 << 25));
    1503         return true;
    1504     }
    1505 
    1506     /* These special keys have to be handled by Windows as well to update the
    1507      * internal modifier state and to enable/disable the keyboard LED */
    1508     if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT)
    1509         return false;
    1510 
    1511     return result;
    1512 }
    1513 
    1514 #elif defined(Q_WS_PM)
    1515 
    1516 bool UIMachineView::pmEvent(QMSG *aMsg)
    1517 {
    1518     if (aMsg->msg == UM_PREACCEL_CHAR)
    1519     {
    1520         /* We are inside the input hook
    1521          * let the message go through the normal system pipeline. */
    1522         if (!m_bIsKeyboardCaptured)
    1523             return false;
    1524     }
    1525 
    1526     if (aMsg->msg != WM_CHAR && aMsg->msg != UM_PREACCEL_CHAR)
    1527         return false;
    1528 
    1529     /* check for the special flag possibly set at the end of this function */
    1530     if (SHORT2FROMMP(aMsg->mp2) & 0x8000)
    1531     {
    1532         aMsg->mp2 = MPFROM2SHORT(SHORT1FROMMP(aMsg->mp2), SHORT2FROMMP(aMsg->mp2) & ~0x8000);
    1533         return false;
    1534     }
    1535 
    1536     USHORT ch = SHORT1FROMMP(aMsg->mp2);
    1537     USHORT f = SHORT1FROMMP(aMsg->mp1);
    1538 
    1539     int scan = (unsigned int)CHAR4FROMMP(aMsg->mp1);
    1540     if (!scan || scan > 0x7F)
    1541         return true;
    1542 
    1543     int vkey = QIHotKeyEdit::virtualKey(aMsg);
    1544 
    1545     int flags = 0;
    1546 
    1547     if ((ch & 0xFF) == 0xE0)
    1548     {
    1549         flags |= KeyExtended;
    1550         scan = ch >> 8;
    1551     }
    1552     else if (scan == 0x5C && (ch & 0xFF) == '/')
    1553     {
    1554         /* this is the '/' key on the keypad */
    1555         scan = 0x35;
    1556         flags |= KeyExtended;
    1557     }
    1558     else
    1559     {
    1560         /* For some keys, the scan code passed in QMSG is a pseudo scan
    1561          * code. We replace it with a real hardware scan code, according to
    1562          * http://www.computer-engineering.org/ps2keyboard/scancodes1.html.
    1563          * Also detect Pause and PrtScn and set flags. */
    1564         switch (vkey)
    1565         {
    1566             case VK_ENTER:     scan = 0x1C; flags |= KeyExtended; break;
    1567             case VK_CTRL:      scan = 0x1D; flags |= KeyExtended; break;
    1568             case VK_ALTGRAF:   scan = 0x38; flags |= KeyExtended; break;
    1569             case VK_LWIN:      scan = 0x5B; flags |= KeyExtended; break;
    1570             case VK_RWIN:      scan = 0x5C; flags |= KeyExtended; break;
    1571             case VK_WINMENU:   scan = 0x5D; flags |= KeyExtended; break;
    1572             case VK_FORWARD:   scan = 0x69; flags |= KeyExtended; break;
    1573             case VK_BACKWARD:  scan = 0x6A; flags |= KeyExtended; break;
    1574 #if 0
    1575             /// @todo this would send 0xE0 0x46 0xE0 0xC6. It's not fully
    1576             // clear what is more correct
    1577             case VK_BREAK:     scan = 0x46; flags |= KeyExtended; break;
    1578 #else
    1579             case VK_BREAK:     scan = 0;    flags |= KeyPause; break;
    1580 #endif
    1581             case VK_PAUSE:     scan = 0;    flags |= KeyPause;    break;
    1582             case VK_PRINTSCRN: scan = 0;    flags |= KeyPrint;    break;
    1583             default:;
    1584         }
    1585     }
    1586 
    1587     if (!(f & KC_KEYUP))
    1588         flags |= KeyPressed;
    1589 
    1590     bool result = keyEvent (vkey, scan, flags);
    1591     if (!result && m_bIsKeyboardCaptured)
    1592     {
    1593         /* keyEvent() returned that it didn't process the message, but since the
    1594          * keyboard is captured, we don't want to pass it to PM. We just want
    1595          * to let Qt process the message (to handle non-alphanumeric <HOST>+key
    1596          * shortcuts for example). So send it direcltly to the window with the
    1597          * special flag in the reserved area of lParam (to avoid recursion). */
    1598         ::WinSendMsg (aMsg->hwnd, WM_CHAR, aMsg->mp1,
    1599                       MPFROM2SHORT (SHORT1FROMMP (aMsg->mp2), SHORT2FROMMP (aMsg->mp2) | 0x8000));
    1600         return true;
    1601     }
    1602     return result;
    1603 }
    1604 
    1605 #elif defined(Q_WS_X11)
    1606 
    1607 static Bool VBoxConsoleViewCompEvent(Display *, XEvent *pEvent, XPointer pvArg)
    1608 {
    1609     XEvent *pKeyEvent = (XEvent*)pvArg;
    1610     if ((pEvent->type == XKeyPress) && (pEvent->xkey.keycode == pKeyEvent->xkey.keycode))
    1611         return True;
    1612     else
    1613         return False;
    1614 }
    1615 
    1616 bool UIMachineView::x11Event(XEvent *pEvent)
    1617 {
    1618     switch (pEvent->type)
    1619     {
    1620         /* We have to handle XFocusOut right here as this event is not passed
    1621          * to UIMachineView::event(). Handling this event is important for
    1622          * releasing the keyboard before the screen saver gets active.
    1623          *
    1624          * See public ticket #3894: Apparently this makes problems with newer
    1625          * versions of Qt and this hack is probably not necessary anymore.
    1626          * So disable it for Qt >= 4.5.0. */
    1627         case XFocusOut:
    1628         case XFocusIn:
    1629             if (uisession()->isRunning())
    1630             {
    1631                 if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0))
    1632                 {
    1633                     focusEvent(pEvent->type == XFocusIn);
    1634                     if (pEvent->type == XFocusOut)
    1635                         machineLogic()->mouseHandler()->releaseMouse();
    1636                 }
    1637             }
    1638             return false;
    1639         case XKeyPress:
    1640         case XKeyRelease:
    1641             break;
    1642         default:
    1643             return false; /* pass the event to Qt */
    1644     }
    1645 
    1646     /* Translate the keycode to a PC scan code. */
    1647     unsigned scan = handleXKeyEvent(pEvent);
    1648 
    1649     /* scancodes 0x00 (no valid translation) and 0x80 are ignored */
    1650     if (!scan & 0x7F)
    1651         return true;
    1652 
    1653     /* Fix for http://www.virtualbox.org/ticket/1296:
    1654      * when X11 sends events for repeated keys, it always inserts an
    1655      * XKeyRelease before the XKeyPress. */
    1656     XEvent returnEvent;
    1657     if ((pEvent->type == XKeyRelease) && (XCheckIfEvent(pEvent->xkey.display, &returnEvent,
    1658         VBoxConsoleViewCompEvent, (XPointer)pEvent) == True))
    1659     {
    1660         XPutBackEvent(pEvent->xkey.display, &returnEvent);
    1661         /* Discard it, don't pass it to Qt. */
    1662         return true;
    1663     }
    1664 
    1665     KeySym ks = ::XKeycodeToKeysym(pEvent->xkey.display, pEvent->xkey.keycode, 0);
    1666 
    1667     int flags = 0;
    1668     if (scan >> 8)
    1669         flags |= KeyExtended;
    1670     if (pEvent->type == XKeyPress)
    1671         flags |= KeyPressed;
    1672 
    1673     /* Remove the extended flag */
    1674     scan &= 0x7F;
    1675 
    1676     switch (ks)
    1677     {
    1678         case XK_Print:
    1679             flags |= KeyPrint;
    1680             break;
    1681         case XK_Pause:
    1682             flags |= KeyPause;
    1683             break;
    1684     }
    1685 
    1686     return keyEvent(ks, scan, flags);
    1687 }
    1688 
    1689 #elif defined(Q_WS_MAC)
    1690 
    1691 bool UIMachineView::darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent)
     877    /* All keyboard class events needs to be handled. */
     878    if (eventClass == kEventClassKeyboard)
     879    {
     880        if (pKeyboardHandler->darwinKeyboardEvent(pvCocoaEvent, inEvent))
     881            return true;
     882    }
     883    /* Pass the event along. */
     884    return false;
     885}
     886
     887bool UIKeyboardHandler::darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent)
    1692888{
    1693889    bool ret = false;
     
    1695891    if (EventKind != kEventRawKeyModifiersChanged)
    1696892    {
    1697         /* convert keycode to set 1 scan code. */
     893        /* Convert keycode to set 1 scan code. */
    1698894        UInt32 keyCode = ~0U;
    1699895        ::GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode);
    1700         unsigned scanCode = ::DarwinKeycodeToSet1Scancode(keyCode);
     896        uint8_t scanCode = ::DarwinKeycodeToSet1Scancode(keyCode);
    1701897        if (scanCode)
    1702898        {
    1703             /* calc flags. */
     899            /* Calc flags. */
    1704900            int flags = 0;
    1705901            if (EventKind != kEventRawKeyUp)
     
    1710906            scanCode &= VBOXKEY_SCANCODE_MASK;
    1711907
    1712             /* get the unicode string (if present). */
     908            /* Get the unicode string (if present). */
    1713909            AssertCompileSize(wchar_t, 2);
    1714910            AssertCompileSize(UniChar, 2);
     
    1720916            ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */
    1721917
    1722             ret = keyEvent(keyCode, scanCode, flags, ucs[0] ? ucs : NULL);
     918            ret = keyEvent(keyCode, scanCode, flags, uScreenId, ucs[0] ? ucs : NULL);
    1723919        }
    1724920    }
     
    1737933                if (!(changed & (1 << bit)))
    1738934                    continue;
    1739                 unsigned scanCode = ::DarwinModifierMaskToSet1Scancode(1 << bit);
     935                uint8_t scanCode = ::DarwinModifierMaskToSet1Scancode(1 << bit);
    1740936                if (!scanCode)
    1741937                    continue;
     
    1749945                        flags |= KeyExtended;
    1750946                    scanCode &= VBOXKEY_SCANCODE_MASK;
    1751                     ret |= keyEvent(keyCode, scanCode & 0xff, flags);
     947                    ret |= keyEvent(keyCode, scanCode & 0xff, flags, uScreenId);
    1752948                }
    1753949                else
     
    1757953                        flags |= KeyExtended;
    1758954                    scanCode &= VBOXKEY_SCANCODE_MASK;
    1759                     keyEvent(keyCode, scanCode, flags | KeyPressed);
    1760                     keyEvent(keyCode, scanCode, flags);
     955                    keyEvent(keyCode, scanCode, flags | KeyPressed, uScreenId);
     956                    keyEvent(keyCode, scanCode, flags, uScreenId);
    1761957                }
    1762958            }
     
    1773969}
    1774970
    1775 void UIMachineView::darwinGrabKeyboardEvents(bool fGrab)
    1776 {
    1777     m_fKeyboardGrabbed = fGrab;
    1778     if (fGrab)
    1779     {
    1780         /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */
    1781         ::CGSetLocalEventsSuppressionInterval(0.0);
    1782         machineLogic()->mouseHandler()->setMouseCoalescingEnabled(false);
    1783 
    1784         /* Register the event callback/hook and grab the keyboard. */
    1785         UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
    1786                                                                 UIMachineView::darwinEventHandlerProc, this);
    1787 
    1788         ::DarwinGrabKeyboard (false);
     971#endif
     972
     973bool UIKeyboardHandler::keyEvent(int iKey, uint8_t uScan, int fFlags, ulong uScreenId, wchar_t *pUniKey /* = NULL */)
     974{
     975    const bool isHostKey = iKey == m_globalSettings.hostKey();
     976
     977    LONG buf[16];
     978    LONG *codes = buf;
     979    uint count = 0;
     980    uint8_t whatPressed = 0;
     981
     982    if (!isHostKey && !m_bIsHostkeyPressed)
     983    {
     984        if (fFlags & KeyPrint)
     985        {
     986            static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 };
     987            static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA };
     988            if (fFlags & KeyPressed)
     989            {
     990                codes = PrintMake;
     991                count = SIZEOF_ARRAY(PrintMake);
     992            }
     993            else
     994            {
     995                codes = PrintBreak;
     996                count = SIZEOF_ARRAY(PrintBreak);
     997            }
     998        }
     999        else if (fFlags & KeyPause)
     1000        {
     1001            if (fFlags & KeyPressed)
     1002            {
     1003                static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 };
     1004                codes = Pause;
     1005                count = SIZEOF_ARRAY(Pause);
     1006            }
     1007            else
     1008            {
     1009                /* Pause shall not produce a break code */
     1010                return true;
     1011            }
     1012        }
     1013        else
     1014        {
     1015            if (fFlags & KeyPressed)
     1016            {
     1017                /* Check if the guest has the same view on the modifier keys (NumLock,
     1018                 * CapsLock, ScrollLock) as the X server. If not, send KeyPress events
     1019                 * to synchronize the state. */
     1020                fixModifierState(codes, &count);
     1021            }
     1022
     1023            /* Check if it's C-A-D and GUI/PassCAD is not true */
     1024            if (!m_fPassCAD &&
     1025                uScan == 0x53 /* Del */ &&
     1026                ((m_pressedKeys[0x38] & IsKeyPressed) /* Alt */ ||
     1027                 (m_pressedKeys[0x38] & IsExtKeyPressed)) &&
     1028                ((m_pressedKeys[0x1d] & IsKeyPressed) /* Ctrl */ ||
     1029                 (m_pressedKeys[0x1d] & IsExtKeyPressed)))
     1030            {
     1031                /* Use the C-A-D combination as a last resort to get the
     1032                 * keyboard and mouse back to the host when the user forgets
     1033                 * the Host Key. Note that it's always possible to send C-A-D
     1034                 * to the guest using the Host+Del combination. BTW, it would
     1035                 * be preferrable to completely ignore C-A-D in guests, but
     1036                 * that's not possible because we cannot predict what other
     1037                 * keys will be pressed next when one of C, A, D is held. */
     1038                if (uisession()->isRunning() && m_fIsKeyboardCaptured)
     1039                {
     1040                    releaseKeyboard();
     1041                    if (!uisession()->isMouseSupportsAbsolute() || !uisession()->isMouseIntegrated())
     1042                        machineLogic()->mouseHandler()->releaseMouse();
     1043                }
     1044                return true;
     1045            }
     1046
     1047            /* Process the scancode and update the table of pressed keys: */
     1048            whatPressed = IsKeyPressed;
     1049
     1050            if (fFlags & KeyExtended)
     1051            {
     1052                codes[count++] = 0xE0;
     1053                whatPressed = IsExtKeyPressed;
     1054            }
     1055
     1056            if (fFlags & KeyPressed)
     1057            {
     1058                codes[count++] = uScan;
     1059                m_pressedKeys[uScan] |= whatPressed;
     1060            }
     1061            else
     1062            {
     1063                /* If we haven't got this key's press message, we ignore its release: */
     1064                if (!(m_pressedKeys[uScan] & whatPressed))
     1065                    return true;
     1066                codes[count++] = uScan | 0x80;
     1067                m_pressedKeys[uScan] &= ~whatPressed;
     1068            }
     1069
     1070            if (m_fIsKeyboardCaptured)
     1071                m_pressedKeys[uScan] |= IsKbdCaptured;
     1072            else
     1073                m_pressedKeys[uScan] &= ~IsKbdCaptured;
     1074        }
    17891075    }
    17901076    else
    17911077    {
    1792         ::DarwinReleaseKeyboard();
    1793         UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
    1794                                                                   UIMachineView::darwinEventHandlerProc, this);
    1795     }
    1796 }
    1797 
    1798 bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
    1799 {
    1800     UIMachineView *view = (UIMachineView*)pvUser;
    1801     EventRef inEvent = (EventRef)pvCarbonEvent;
    1802     UInt32 eventClass = ::GetEventClass(inEvent);
    1803 
    1804     /* Check if this is an application key combo. In that case we will not pass
    1805      * the event to the guest, but let the host process it. */
    1806     if (::darwinIsApplicationCommand(pvCocoaEvent))
    1807         return false;
    1808 
    1809     /* All keyboard class events needs to be handled. */
    1810     if (eventClass == kEventClassKeyboard)
    1811     {
    1812         if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent))
    1813             return true;
    1814     }
    1815     /* Pass the event along. */
    1816     return false;
    1817 }
    1818 
     1078        /* Currently this is used in winLowKeyboardEvent() only: */
     1079        m_bIsHostkeyInCapture = m_fIsKeyboardCaptured;
     1080    }
     1081
     1082    bool emitSignal = false;
     1083    int hotkey = 0;
     1084
     1085    /* Process the host key: */
     1086    if (fFlags & KeyPressed)
     1087    {
     1088        if (isHostKey)
     1089        {
     1090            if (!m_bIsHostkeyPressed)
     1091            {
     1092                m_bIsHostkeyPressed = m_bIsHostkeyAlone = true;
     1093                if (uisession()->isRunning())
     1094                    saveKeyStates();
     1095                emitSignal = true;
     1096            }
     1097        }
     1098        else
     1099        {
     1100            if (m_bIsHostkeyPressed)
     1101            {
     1102                if (m_bIsHostkeyAlone)
     1103                {
     1104                    hotkey = iKey;
     1105                    m_bIsHostkeyAlone = false;
     1106                }
     1107            }
     1108        }
     1109    }
     1110    else
     1111    {
     1112        if (isHostKey)
     1113        {
     1114            if (m_bIsHostkeyPressed)
     1115            {
     1116                m_bIsHostkeyPressed = false;
     1117
     1118                if (m_bIsHostkeyAlone)
     1119                {
     1120                    if (uisession()->isPaused())
     1121                    {
     1122                        vboxProblem().remindAboutPausedVMInput();
     1123                    }
     1124                    else if (uisession()->isRunning())
     1125                    {
     1126                        bool ok = true;
     1127                        if (!m_fIsKeyboardCaptured)
     1128                        {
     1129                            /* Temporarily disable auto capture that will take
     1130                             * place after this dialog is dismissed because
     1131                             * the capture state is to be defined by the
     1132                             * dialog result itself */
     1133                            uisession()->setAutoCaptureDisabled(true);
     1134                            bool autoConfirmed = false;
     1135                            ok = vboxProblem().confirmInputCapture(&autoConfirmed);
     1136                            if (autoConfirmed)
     1137                                uisession()->setAutoCaptureDisabled(false);
     1138                            /* Otherwise, the disable flag will be reset in
     1139                             * the next console view's foucs in event (since
     1140                             * may happen asynchronously on some platforms,
     1141                             * after we return from this code) */
     1142                        }
     1143
     1144                        if (ok)
     1145                        {
     1146                            if (m_fIsKeyboardCaptured)
     1147                                releaseKeyboard();
     1148                            else
     1149                                captureKeyboard(uScreenId);
     1150                            if (!uisession()->isMouseSupportsAbsolute() || !uisession()->isMouseIntegrated())
     1151                            {
     1152#ifdef Q_WS_X11
     1153                                /* Make sure that pending FocusOut events from the
     1154                                 * previous message box are handled, otherwise the
     1155                                 * mouse is immediately ungrabbed. */
     1156                                qApp->processEvents();
    18191157#endif
    1820 
    1821 void UIMachineView::fixModifierState(LONG *piCodes, uint *puCount)
     1158                                if (m_fIsKeyboardCaptured)
     1159                                    machineLogic()->mouseHandler()->captureMouse(uScreenId);
     1160                                else
     1161                                    machineLogic()->mouseHandler()->releaseMouse();
     1162                            }
     1163                        }
     1164                    }
     1165                }
     1166
     1167                if (uisession()->isRunning())
     1168                    sendChangedKeyStates();
     1169
     1170                emitSignal = true;
     1171            }
     1172        }
     1173        else
     1174        {
     1175            if (m_bIsHostkeyPressed)
     1176                m_bIsHostkeyAlone = false;
     1177        }
     1178    }
     1179
     1180    /* Notify all listeners: */
     1181    emit keyboardStateChanged(keyboardState());
     1182
     1183    /* Process Host+<key> shortcuts. currently, <key> is limited to
     1184     * alphanumeric chars. Other Host+<key> combinations are handled in
     1185     * event(). */
     1186    if (hotkey)
     1187    {
     1188        bool processed = false;
     1189#if defined (Q_WS_WIN)
     1190        NOREF(pUniKey);
     1191        int n = GetKeyboardLayoutList(0, NULL);
     1192        Assert(n);
     1193        HKL *list = new HKL[n];
     1194        GetKeyboardLayoutList(n, list);
     1195        for (int i = 0; i < n && !processed; i++)
     1196        {
     1197            wchar_t ch;
     1198            static BYTE keys[256] = {0};
     1199            if (!ToUnicodeEx(hotkey, 0, keys, &ch, 1, 0, list[i]) == 1)
     1200                ch = 0;
     1201            if (ch)
     1202                processed = machineLogic()->actionsPool()->processHotKey(QKeySequence((Qt::UNICODE_ACCEL + QChar(ch).toUpper().unicode())));
     1203        }
     1204        delete[] list;
     1205#elif defined (Q_WS_X11)
     1206        NOREF(pUniKey);
     1207        Display *display = QX11Info::display();
     1208        int keysyms_per_keycode = getKeysymsPerKeycode();
     1209        KeyCode kc = XKeysymToKeycode (display, iKey);
     1210        for (int i = 0; i < keysyms_per_keycode && !processed; i += 2)
     1211        {
     1212            KeySym ks = XKeycodeToKeysym(display, kc, i);
     1213            char ch = 0;
     1214            if (!XkbTranslateKeySym(display, &ks, 0, &ch, 1, NULL) == 1)
     1215                ch = 0;
     1216            if (ch)
     1217                QChar c = QString::fromLocal8Bit(&ch, 1)[0];
     1218        }
     1219#elif defined (Q_WS_MAC)
     1220        if (pUniKey && pUniKey[0] && !pUniKey[1])
     1221            processed = machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode()));
     1222
     1223        /* Don't consider the hot key as pressed since the guest never saw
     1224         * it. (probably a generic thing) */
     1225        m_pressedKeys[uScan] &= ~whatPressed;
     1226#endif
     1227        /* Grab the key from Qt if processed, or pass it to Qt otherwise
     1228         * in order to process non-alphanumeric keys in event(), after they are
     1229         * converted to Qt virtual keys. */
     1230        return processed;
     1231    }
     1232
     1233    /* No more to do, if the host key is in action or the VM is paused: */
     1234    if (m_bIsHostkeyPressed || isHostKey || uisession()->isPaused())
     1235    {
     1236        /* Grab the key from Qt and from VM if it's a host key,
     1237         * otherwise just pass it to Qt */
     1238        return isHostKey;
     1239    }
     1240
     1241    CKeyboard keyboard = session().GetConsole().GetKeyboard();
     1242    Assert(!keyboard.isNull());
     1243
     1244#ifdef Q_WS_WIN
     1245    /* Send pending WM_PAINT events: */
     1246    ::UpdateWindow(m_views[uScreenId]->viewport()->winId());
     1247#endif /* Q_WS_WIN */
     1248
     1249    std::vector <LONG> scancodes(codes, &codes[count]);
     1250    keyboard.PutScancodes(QVector<LONG>::fromStdVector(scancodes));
     1251
     1252    /* Grab the key from Qt: */
     1253    return true;
     1254}
     1255
     1256void UIKeyboardHandler::fixModifierState(LONG *piCodes, uint *puCount)
    18221257{
    18231258    /* Synchronize the views of the host and the guest to the modifier keys.
    18241259     * This function will add up to 6 additional keycodes to codes. */
    1825 
    18261260#if defined(Q_WS_X11)
    1827 
    18281261    Window   wDummy1, wDummy2;
    18291262    int      iDummy3, iDummy4, iDummy5, iDummy6;
     
    18671300        }
    18681301    }
    1869 
    1870 #elif defined(Q_WS_WIN32)
    1871 
     1302#elif defined(Q_WS_WIN)
    18721303    if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK))))
    18731304    {
     
    18901321        }
    18911322    }
    1892 
    18931323#elif defined(Q_WS_MAC)
    1894 
    18951324    /* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */
    18961325    if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))
     
    19081337        }
    19091338    }
    1910 
    19111339#else
    1912 
    1913 //#warning Adapt UIMachineView::fixModifierState
    1914 
     1340//#warning Adapt UIKeyboardHandler::fixModifierState
    19151341#endif
    19161342}
    19171343
    1918 QPoint UIMachineView::viewportToContents(const QPoint &vp) const
    1919 {
    1920     return QPoint(vp.x() + contentsX(), vp.y() + contentsY());
    1921 }
    1922 
    1923 void UIMachineView::scrollBy(int dx, int dy)
    1924 {
    1925     horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx);
    1926     verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);
    1927 }
    1928 
    1929 #ifdef VBOX_WITH_VIDEOHWACCEL
    1930 void UIMachineView::scrollContentsBy(int dx, int dy)
    1931 {
    1932     if (m_pFrameBuffer)
    1933     {
    1934         m_pFrameBuffer->viewportScrolled(dx, dy);
    1935     }
    1936     QAbstractScrollArea::scrollContentsBy(dx, dy);
    1937 }
    1938 #endif
    1939 
    1940 void UIMachineView::emitKeyboardStateChanged()
    1941 {
    1942     emit keyboardStateChanged(keyboardState());
    1943 }
    1944 
    1945 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */)
    1946 {
    1947     if (m_bIsKeyboardCaptured == fCapture)
    1948         return;
    1949 
    1950 #if defined(Q_WS_WIN32)
    1951     /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */
    1952 #elif defined(Q_WS_X11)
    1953     /* On X11, we are using passive XGrabKey for normal (windowed) mode
    1954      * instead of XGrabKeyboard (called by QWidget::grabKeyboard())
    1955      * because XGrabKeyboard causes a problem under metacity - a window cannot be moved
    1956      * using the mouse if it is currently actively grabing the keyboard;
    1957      * For static modes we are using usual (active) keyboard grabbing. */
    1958     switch (machineLogic()->visualStateType())
    1959     {
    1960         /* If window is moveable we are making passive keyboard grab: */
    1961         case UIVisualStateType_Normal:
    1962         {
    1963             if (fCapture)
    1964                 XGrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync);
    1965             else
    1966                 XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId());
    1967             break;
    1968         }
    1969         /* If window is NOT moveable we are making active keyboard grab: */
    1970         case UIVisualStateType_Fullscreen:
    1971         case UIVisualStateType_Seamless:
    1972         {
    1973             if (fCapture)
    1974             {
    1975                 /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager.
    1976                  * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times,
    1977                  * and after we will just ignore that issue: */
    1978                 int cTriesLeft = 50;
    1979                 while (cTriesLeft && XGrabKeyboard(QX11Info::display(), machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; }
    1980             }
    1981             else
    1982                 XUngrabKeyboard(QX11Info::display(), CurrentTime);
    1983             break;
    1984         }
    1985         /* Should we try to grab keyboard in default case? I think - NO. */
    1986         default:
    1987             break;
    1988     }
    1989 #elif defined(Q_WS_MAC)
    1990     /* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers
    1991      * (for right/left separation). */
    1992     if (fCapture)
    1993     {
    1994         ::DarwinDisableGlobalHotKeys(true);
    1995         grabKeyboard();
    1996     }
    1997     else
    1998     {
    1999         ::DarwinDisableGlobalHotKeys(false);
    2000         releaseKeyboard();
    2001     }
    2002 #else
    2003     if (fCapture)
    2004         grabKeyboard();
    2005     else
    2006         releaseKeyboard();
    2007 #endif
    2008 
    2009     m_bIsKeyboardCaptured = fCapture;
    2010 
    2011     if (fEmitSignal)
    2012         emitKeyboardStateChanged();
    2013 }
    2014 
    2015 void UIMachineView::saveKeyStates()
     1344void UIKeyboardHandler::saveKeyStates()
    20161345{
    20171346    ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys));
    20181347}
    20191348
    2020 void UIMachineView::releaseAllPressedKeys(bool aReleaseHostKey /* = true */)
     1349void UIKeyboardHandler::releaseAllPressedKeys(bool aReleaseHostKey /* = true */)
    20211350{
    20221351    CKeyboard keyboard = session().GetConsole().GetKeyboard();
     
    20611390    m_darwinKeyModifiers &=
    20621391        alphaLock | kEventKeyModifierNumLockMask |
    2063         (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (m_globalSettings.hostKey()));
     1392        (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask(m_globalSettings.hostKey()));
    20641393#endif
    20651394
    2066     emitKeyboardStateChanged();
    2067 }
    2068 
    2069 void UIMachineView::sendChangedKeyStates()
     1395    emit keyboardStateChanged(keyboardState());
     1396}
     1397
     1398void UIKeyboardHandler::sendChangedKeyStates()
    20701399{
    20711400    QVector <LONG> codes(2);
     
    20931422}
    20941423
    2095 void UIMachineView::dimImage(QImage &img)
    2096 {
    2097     for (int y = 0; y < img.height(); ++ y)
    2098     {
    2099         if (y % 2)
    2100         {
    2101             if (img.depth() == 32)
    2102             {
    2103                 for (int x = 0; x < img.width(); ++ x)
    2104                 {
    2105                     int gray = qGray(img.pixel (x, y)) / 2;
    2106                     img.setPixel(x, y, qRgb (gray, gray, gray));
    2107                 }
    2108             }
    2109             else
    2110             {
    2111                 ::memset(img.scanLine (y), 0, img.bytesPerLine());
    2112             }
    2113         }
    2114         else
    2115         {
    2116             if (img.depth() == 32)
    2117             {
    2118                 for (int x = 0; x < img.width(); ++ x)
    2119                 {
    2120                     int gray = (2 * qGray (img.pixel (x, y))) / 3;
    2121                     img.setPixel(x, y, qRgb (gray, gray, gray));
    2122                 }
    2123             }
    2124         }
    2125     }
    2126 }
    2127 
    2128 #ifdef Q_WS_MAC
    2129 CGImageRef UIMachineView::vmContentImage()
    2130 {
    2131     if (!m_pauseShot.isNull())
    2132     {
    2133         CGImageRef pauseImg = ::darwinToCGImageRef(&m_pauseShot);
    2134         /* Use the pause image as background */
    2135         return pauseImg;
    2136     }
    2137     else
    2138     {
    2139 # ifdef VBOX_GUI_USE_QUARTZ2D
    2140         if (vboxGlobal().vmRenderMode() == VBoxDefs::Quartz2DMode)
    2141         {
    2142             /* If the render mode is Quartz2D we could use the CGImageRef
    2143              * of the framebuffer for the dock icon creation. This saves
    2144              * some conversion time. */
    2145             CGImageRef image = static_cast<UIFrameBufferQuartz2D*>(m_pFrameBuffer)->imageRef();
    2146             CGImageRetain(image); /* Retain it, cause the consumer will release it. */
    2147             return image;
    2148         }
    2149         else
    2150 # endif /* VBOX_GUI_USE_QUARTZ2D */
    2151             /* In image mode we have to create the image ref out of the
    2152              * framebuffer */
    2153             return frameBuffertoCGImageRef(m_pFrameBuffer);
    2154     }
    2155     return 0;
    2156 }
    2157 
    2158 CGImageRef UIMachineView::frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer)
    2159 {
    2160     CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
    2161     Assert(cs);
    2162     /* Create the image copy of the framebuffer */
    2163     CGDataProviderRef dp = CGDataProviderCreateWithData(pFrameBuffer, pFrameBuffer->address(), pFrameBuffer->bitsPerPixel() / 8 * pFrameBuffer->width() * pFrameBuffer->height(), NULL);
    2164     Assert(dp);
    2165     CGImageRef ir = CGImageCreate(pFrameBuffer->width(), pFrameBuffer->height(), 8, 32, pFrameBuffer->bytesPerLine(), cs,
    2166                                   kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host, dp, 0, false,
    2167                                   kCGRenderingIntentDefault);
    2168     Assert(ir);
    2169     CGDataProviderRelease(dp);
    2170     CGColorSpaceRelease(cs);
    2171 
    2172     return ir;
    2173 }
    2174 
    2175 void UIMachineView::updateDockIcon()
    2176 {
    2177     machineLogic()->updateDockIcon();
    2178 }
    2179 #endif /* Q_WS_MAC */
    2180 
     1424UIMachineWindow* UIKeyboardHandler::isItListenedWindow(QObject *pWatchedObject) const
     1425{
     1426    UIMachineWindow *pResultWindow = 0;
     1427    QMap<ulong, UIMachineWindow*>::const_iterator i = m_windows.constBegin();
     1428    while (!pResultWindow && i != m_windows.constEnd())
     1429    {
     1430        switch (machineLogic()->visualStateType())
     1431        {
     1432            case UIVisualStateType_Normal:
     1433            {
     1434                UIMachineWindowNormal *pIteratedWindow = static_cast<UIMachineWindowNormal*>(i.value());
     1435                if (pIteratedWindow == pWatchedObject)
     1436                {
     1437                    pResultWindow = pIteratedWindow;
     1438                    continue;
     1439                }
     1440                break;
     1441            }
     1442            case UIVisualStateType_Fullscreen:
     1443            {
     1444                UIMachineWindowFullscreen *pIteratedWindow = static_cast<UIMachineWindowFullscreen*>(i.value());
     1445                if (pIteratedWindow == pWatchedObject)
     1446                {
     1447                    pResultWindow = pIteratedWindow;
     1448                    continue;
     1449                }
     1450                break;
     1451            }
     1452            case UIVisualStateType_Seamless:
     1453            {
     1454                UIMachineWindowSeamless *pIteratedWindow = static_cast<UIMachineWindowSeamless*>(i.value());
     1455                if (pIteratedWindow == pWatchedObject)
     1456                {
     1457                    pResultWindow = pIteratedWindow;
     1458                    continue;
     1459                }
     1460                break;
     1461            }
     1462            default:
     1463                break;
     1464        }
     1465        ++i;
     1466    }
     1467    return pResultWindow;
     1468}
     1469
     1470UIMachineView* UIKeyboardHandler::isItListenedView(QObject *pWatchedObject) const
     1471{
     1472    UIMachineView *pResultView = 0;
     1473    QMap<ulong, UIMachineView*>::const_iterator i = m_views.constBegin();
     1474    while (!pResultView && i != m_views.constEnd())
     1475    {
     1476        UIMachineView *pIteratedView = qobject_cast<UIMachineView*>(i.value());
     1477        if (pIteratedView == pWatchedObject)
     1478        {
     1479            pResultView = pIteratedView;
     1480            continue;
     1481        }
     1482        ++i;
     1483    }
     1484    return pResultView;
     1485}
     1486
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.h

    r30458 r30637  
    22 *
    33 * VBox frontends: Qt GUI ("VirtualBox"):
    4  * UIMachineView class declaration
     4 * UIKeyboardHandler class declaration
    55 */
    66
     
    1717 */
    1818
    19 #ifndef ___UIMachineView_h___
    20 #define ___UIMachineView_h___
     19#ifndef ___UIKeyboardHandler_h___
     20#define ___UIKeyboardHandler_h___
    2121
    2222/* Global includes */
    23 #include <QAbstractScrollArea>
    24 #include <QEventLoop>
     23#include <QObject>
     24#include <QMap>
    2525
    2626/* Local includes */
     27#include "UIMachineDefs.h"
    2728#include "COMDefs.h"
    28 #include "UIMachineDefs.h"
    2929
    30 #ifdef Q_WS_MAC
    31 # include <CoreFoundation/CFBase.h>
    32 #endif /* Q_WS_MAC */
     30/* Global forwards */
     31class QWidget;
    3332
    3433/* Local forwards */
     34class CSession;
    3535class UISession;
    36 class UIFrameBuffer;
     36class UIMachineLogic;
    3737class UIMachineWindow;
    38 class UIMachineLogic;
     38class UIMachineView;
    3939class VBoxGlobalSettings;
     40#ifdef Q_WS_X11
     41typedef union  _XEvent XEvent;
     42#endif /* Q_WS_X11 */
    4043
    41 class UIMachineView : public QAbstractScrollArea
     44/* Delegate to control VM keyboard functionality: */
     45class UIKeyboardHandler : public QObject
    4246{
    4347    Q_OBJECT;
     
    4549public:
    4650
    47     /* Desktop geometry types: */
    48     enum DesktopGeo { DesktopGeo_Invalid = 0, DesktopGeo_Fixed, DesktopGeo_Automatic, DesktopGeo_Any };
     51    /* Factory functions to create/destroy keyboard-handler: */
     52    static UIKeyboardHandler* create(UIMachineLogic *pMachineLogic, UIVisualStateType visualStateType);
     53    static void destroy(UIKeyboardHandler *pKeyboardHandler);
    4954
    50     /* Factory function to create required view sub-child: */
    51     static UIMachineView* create(  UIMachineWindow *pMachineWindow
    52 #ifdef VBOX_WITH_VIDEOHWACCEL
    53                                  , bool bAccelerate2DVideo
    54 #endif
    55                                  , UIVisualStateType visualStateType
    56                                  , ulong uScreenId);
    57     static void destroy(UIMachineView *pWhichView);
     55    /* Prepare/cleanup listeners: */
     56    void prepareListener(ulong uIndex, UIMachineWindow *pMachineWindow);
     57    void cleanupListener(ulong uIndex);
    5858
    59     /* Public getters: */
     59    /* Commands to capture/release keyboard: */
     60    void captureKeyboard(ulong uScreenId);
     61    void releaseKeyboard();
     62
     63    /* Current keyboard state: */
    6064    int keyboardState() const;
    61     virtual QRegion lastVisibleRegion() const { return QRegion(); }
    6265
    63     /* Public setters: */
    64     virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {}
    65 
    66     /* Public members: */
    67     virtual void normalizeGeometry(bool /* bAdjustPosition = false */) = 0;
    68 
    69 signals:
    70 
    71     /* Keyboard state-change signals: */
    72     void keyboardStateChanged(int iState);
    73 
    74     /* Utility signals: */
    75     void resizeHintDone();
    76 
    77 protected:
    78 
    79     /* Machine view constructor/destructor: */
    80     UIMachineView(  UIMachineWindow *pMachineWindow
    81 #ifdef VBOX_WITH_VIDEOHWACCEL
    82                   , bool bAccelerate2DVideo
    83 #endif
    84                   , ulong uScreenId);
    85     virtual ~UIMachineView();
    86 
    87     /* Protected getters: */
    88     UISession* uisession() const;
    89     CSession& session();
    90     QSize sizeHint() const;
    91     int contentsX() const;
    92     int contentsY() const;
    93     int contentsWidth() const;
    94     int contentsHeight() const;
    95     int visibleWidth() const;
    96     int visibleHeight() const;
    97     ulong screenId() const { return m_uScreenId; }
    98     UIFrameBuffer* frameBuffer() const { return m_pFrameBuffer; }
    99     UIMachineWindow* machineWindowWrapper() const { return m_pMachineWindow; }
    100     UIMachineLogic* machineLogic() const;
     66    /* Some getters required by side-code: */
    10167    bool isHostKeyPressed() const { return m_bIsHostkeyPressed; }
    102     bool isMachineWindowResizeIgnored() const { return m_bIsMachineWindowResizeIgnored; }
    103     const QPixmap& pauseShot() const { return m_pauseShot; }
    104     QSize storedConsoleSize() const { return m_storedConsoleSize; }
    105     DesktopGeo desktopGeometryType() const { return m_desktopGeometryType; }
    106     QSize desktopGeometry() const;
    107     QSize guestSizeHint();
    10868#ifdef Q_WS_MAC
    109     /* These getters are temporary here while UIKeyboardHandler is not implemented: */
    11069    bool isHostKeyAlone() const { return m_bIsHostkeyAlone; }
    11170    bool isKeyboardGrabbed() const { return m_fKeyboardGrabbed; }
    11271#endif /* Q_WS_MAC */
    11372
    114     /* Protected setters: */
    115     void setDesktopGeometry(DesktopGeo geometry, int iWidth, int iHeight);
    116     void storeConsoleSize(int iWidth, int iHeight);
    117     void setMachineWindowResizeIgnored(bool fIgnore = true) { m_bIsMachineWindowResizeIgnored = fIgnore; }
    118     void storeGuestSizeHint(const QSize &sizeHint);
     73    /* External event-filters: */
     74#if defined(Q_WS_WIN)
     75    bool winEventFilter(MSG *pMsg, ulong uScreenId);
     76#elif defined(Q_WS_X11)
     77    bool x11EventFilter(XEvent *pEvent, ulong uScreenId);
     78#endif
    11979
    120     /* Protected helpers: */
    121     virtual QRect workingArea() = 0;
    122     virtual void calculateDesktopGeometry() = 0;
    123     virtual void maybeRestrictMinimumSize() = 0;
    124     virtual void updateSliders();
     80signals:
    12581
    126 #ifdef Q_WS_MAC
    127     void updateDockIcon();
    128     CGImageRef vmContentImage();
    129     CGImageRef frameBuffertoCGImageRef(UIFrameBuffer *pFrameBuffer);
    130 #endif /* Q_WS_MAC */
    131 
    132     /* Prepare routines: */
    133     virtual void prepareFrameBuffer();
    134     virtual void prepareCommon();
    135     virtual void prepareFilters();
    136     virtual void prepareConsoleConnections();
    137     virtual void loadMachineViewSettings();
    138 
    139     /* Cleanup routines: */
    140     //virtual void saveMachineViewSettings() {}
    141     //virtual void cleanupConsoleConnections() {}
    142     //virtual void cleanupFilters() {}
    143     virtual void cleanupCommon();
    144     virtual void cleanupFrameBuffer();
    145 
    146     /* Cross-platforms event processors: */
    147     bool event(QEvent *pEvent);
    148     bool eventFilter(QObject *pWatched, QEvent *pEvent);
    149 
    150     /* Protected variables: */
    151     QSize m_desktopGeometry;
     82    /* Notifies listeners about keyboard state-change: */
     83    void keyboardStateChanged(int iNewState);
    15284
    15385protected slots:
    15486
    155     /* Console callback handlers: */
     87    /* Machine state-change handler: */
    15688    virtual void sltMachineStateChanged();
    157     virtual void sltPerformGuestResize(const QSize & /* toSize */) {};
    15889
    159     /* Various helper slots: */
    160     virtual void sltNormalizeGeometry() { normalizeGeometry(true); }
     90protected:
    16191
    162 private:
     92    /* Keyboard-handler constructor/destructor: */
     93    UIKeyboardHandler(UIMachineLogic *pMachineLogic);
     94    virtual ~UIKeyboardHandler();
    16395
    164     /* Cross-platforms event processors: */
    165     void focusEvent(bool aHasFocus, bool aReleaseHostKey = true);
    166     bool keyEvent(int aKey, uint8_t aScan, int aFlags, wchar_t *aUniKey = NULL);
    167     void resizeEvent(QResizeEvent *pEvent);
    168     void moveEvent(QMoveEvent *pEvent);
    169     void paintEvent(QPaintEvent *pEvent);
     96    /* Prepare helpers: */
     97    virtual void prepareCommon();
     98    virtual void loadSettings();
    17099
    171     /* Platform specific event processors: */
    172 #if defined(Q_WS_WIN32)
     100    /* Cleanup helpers: */
     101    //virtual void saveSettings() {}
     102    virtual void cleanupCommon();
     103
     104    /* Common getters: */
     105    UIMachineLogic* machineLogic() const;
     106    UISession* uisession() const;
     107    CSession& session() const;
     108
     109    /* Event handler for registered machine-view(s): */
     110    bool eventFilter(QObject *pWatchedObject, QEvent *pEvent);
     111#if defined(Q_WS_WIN)
    173112    static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
    174113    bool winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event);
    175     bool winEvent(MSG *aMsg, long *aResult);
    176 #elif defined(Q_WS_PM)
    177     bool pmEvent(QMSG *aMsg);
    178 #elif defined(Q_WS_X11)
    179     bool x11Event(XEvent *event);
    180114#elif defined(Q_WS_MAC)
     115    void darwinGrabKeyboardEvents(bool fGrab);
    181116    bool darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent);
    182     void darwinGrabKeyboardEvents(bool fGrab);
    183117    static bool darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser);
    184118#endif
    185119
     120    /* Separate function to handle most of existing keyboard-events: */
     121    bool keyEvent(int iKey, uint8_t uScan, int fFlags, ulong uScreenId, wchar_t *pUniKey = 0);
     122
    186123    /* Private helpers: */
    187124    void fixModifierState(LONG *piCodes, uint *puCount);
    188     QPoint viewportToContents(const QPoint &vp) const;
    189     void scrollBy(int dx, int dy);
    190 #ifdef VBOX_WITH_VIDEOHWACCEL
    191     void scrollContentsBy(int dx, int dy);
    192 #endif
    193     void emitKeyboardStateChanged();
    194     void captureKbd(bool fCapture, bool fEmitSignal = true);
    195125    void saveKeyStates();
    196126    void releaseAllPressedKeys(bool aReleaseHostKey = true);
    197127    void sendChangedKeyStates();
    198128
    199     static void dimImage(QImage &img);
     129    UIMachineWindow* isItListenedWindow(QObject *pWatchedObject) const;
     130    UIMachineView* isItListenedView(QObject *pWatchedObject) const;
    200131
    201     /* Private members: */
    202     UIMachineWindow *m_pMachineWindow;
    203     ulong m_uScreenId;
     132    /* Machine logic parent: */
     133    UIMachineLogic *m_pMachineLogic;
     134
     135    /* Registered machine-window(s): */
     136    QMap<ulong, UIMachineWindow*> m_windows;
     137    /* Registered machine-view(s): */
     138    QMap<ulong, UIMachineView*> m_views;
     139
     140    /* Other keyboard variables: */
     141    int m_iKeyboardCaptureViewIndex;
    204142    const VBoxGlobalSettings &m_globalSettings;
    205     UIFrameBuffer *m_pFrameBuffer;
    206     KMachineState m_previousState;
    207 
    208     DesktopGeo m_desktopGeometryType;
    209     QSize m_storedConsoleSize;
    210143
    211144    uint8_t m_pressedKeys[128];
    212145    uint8_t m_pressedKeysCopy[128];
    213146
    214     bool m_bIsKeyboardCaptured : 1;
     147    bool m_fIsKeyboardCaptured : 1;
    215148    bool m_bIsHostkeyPressed : 1;
    216149    bool m_bIsHostkeyAlone : 1;
    217150    bool m_bIsHostkeyInCapture : 1;
    218     bool m_bIsMachineWindowResizeIgnored : 1;
    219151    bool m_fPassCAD : 1;
    220 #ifdef VBOX_WITH_VIDEOHWACCEL
    221     bool m_fAccelerate2DVideo;
    222 #endif
    223152
    224 #ifdef Q_WS_MAC
    225     /** The current modifier key mask. Used to figure out which modifier
    226      *  key was pressed when we get a kEventRawKeyModifiersChanged event. */
     153#if defined(Q_WS_WIN)
     154    /* Keyboard hook required to capture keyboard event under windows. */
     155    static UIKeyboardHandler *m_pKeyboardHandler;
     156    HHOOK m_keyboardHook;
     157    int m_iKeyboardHookViewIndex;
     158#elif defined(Q_WS_MAC)
     159    /* The current modifier key mask. Used to figure out which modifier
     160     * key was pressed when we get a kEventRawKeyModifiersChanged event. */
    227161    UInt32 m_darwinKeyModifiers;
    228162    bool m_fKeyboardGrabbed;
    229 #endif /* Q_WS_MAC */
    230 
    231     QPixmap m_pauseShot;
    232 
    233     /* Friend classes: */
    234     friend class UIMouseHandler;
    235     friend class UIMachineLogic;
    236     friend class UIFrameBuffer;
    237     friend class UIFrameBufferQImage;
    238     friend class UIFrameBufferQuartz2D;
    239     friend class UIFrameBufferQGL;
    240     template<class, class, class> friend class VBoxOverlayFrameBuffer;
     163#endif
    241164};
    242165
    243 /* This maintenance class is a part of future roll-back mechanism.
    244  * It allows to block main GUI thread until specific event received.
    245  * Later it will become more abstract but now its just used to help
    246  * fullscreen & seamless modes to restore normal guest size hint. */
    247 class UIMachineViewBlocker : public QEventLoop
    248 {
    249     Q_OBJECT;
     166#endif // !___UIKeyboardHandler_h___
    250167
    251 public:
    252 
    253     UIMachineViewBlocker()
    254         : QEventLoop(0)
    255         , m_iTimerId(0)
    256     {
    257         /* Also start timer to unlock pool in case of
    258          * required condition doesn't happens by some reason: */
    259         m_iTimerId = startTimer(3000);
    260     }
    261 
    262     virtual ~UIMachineViewBlocker()
    263     {
    264         /* Kill the timer: */
    265         killTimer(m_iTimerId);
    266     }
    267 
    268 protected:
    269 
    270     void timerEvent(QTimerEvent *pEvent)
    271     {
    272         /* If that timer event occurs => it seems
    273          * guest resize event doesn't comes in time,
    274          * shame on it, but we just unlocking 'this': */
    275         QEventLoop::timerEvent(pEvent);
    276         exit();
    277     }
    278 
    279     int m_iTimerId;
    280 };
    281 
    282 #endif // !___UIMachineView_h___
    283 
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.cpp

    r30543 r30637  
    2424#include "UIDownloaderAdditions.h"
    2525#include "UIIconPool.h"
     26#include "UIKeyboardHandler.h"
    2627#include "UIMouseHandler.h"
    2728#include "UIMachineLogic.h"
     
    372373{
    373374    m_machineWindowsList << pMachineWindow;
     375}
     376
     377void UIMachineLogic::setKeyboardHandler(UIKeyboardHandler *pKeyboardHandler)
     378{
     379    m_pKeyboardHandler = pKeyboardHandler;
    374380}
    375381
     
    556562void UIMachineLogic::prepareHandlers()
    557563{
     564    /* Create keyboard-handler: */
     565    setKeyboardHandler(UIKeyboardHandler::create(this, visualStateType()));
     566
    558567    /* Create mouse-handler: */
    559568    setMouseHandler(UIMouseHandler::create(this, visualStateType()));
     
    658667    /* Cleanup mouse-handler: */
    659668    UIMouseHandler::destroy(mouseHandler());
     669
     670    /* Cleanup keyboard-handler: */
     671    UIKeyboardHandler::destroy(keyboardHandler());
    660672}
    661673
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineLogic.h

    r30543 r30637  
    3939class UISession;
    4040class UIActionsPool;
     41class UIKeyboardHandler;
    4142class UIMouseHandler;
    4243class UIMachineWindow;
     
    6970    UIVisualStateType visualStateType() const { return m_visualStateType; }
    7071    const QList<UIMachineWindow*>& machineWindows() const { return m_machineWindowsList; }
     72    UIKeyboardHandler* keyboardHandler() const { return m_pKeyboardHandler; }
    7173    UIMouseHandler* mouseHandler() const { return m_pMouseHandler; }
    7274    UIMachineWindow* mainMachineWindow() const;
     
    102104
    103105    /* Protected members: */
     106    void setKeyboardHandler(UIKeyboardHandler *pKeyboardHandler);
    104107    void setMouseHandler(UIMouseHandler *pMouseHandler);
    105108    void addMachineWindow(UIMachineWindow *pMachineWindow);
     
    197200    UIActionsPool *m_pActionsPool;
    198201    UIVisualStateType m_visualStateType;
     202    UIKeyboardHandler *m_pKeyboardHandler;
    199203    UIMouseHandler *m_pMouseHandler;
    200204    QList<UIMachineWindow*> m_machineWindowsList;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp

    r30551 r30637  
    3636#include "UISession.h"
    3737#include "UIActionsPool.h"
     38#include "UIKeyboardHandler.h"
    3839#include "UIMouseHandler.h"
    3940#include "UIMachineLogic.h"
     
    4748#include "UIMachineViewSeamless.h"
    4849
    49 #ifdef Q_WS_WIN
    50 #undef LOWORD
    51 #undef HIWORD
    52 #undef LOBYTE
    53 #undef HIBYTE
    54 #include <windows.h>
    55 static UIMachineView *gView = 0;
    56 static HHOOK gKbdHook = 0;
    57 #endif /* Q_WS_WIN */
    58 
    5950#ifdef Q_WS_X11
    6051# include <QX11Info>
    61 # define XK_XKB_KEYS
    62 # define XK_MISCELLANY
    6352# include <X11/XKBlib.h>
    64 # include <X11/keysym.h>
    6553# ifdef KeyPress
    6654const int XFocusOut = FocusOut;
     
    7361#  undef FocusIn
    7462# endif
    75 # include "XKeyboard.h"
    7663#endif /* Q_WS_X11 */
    7764
     
    10390};
    10491
    105 enum { KeyExtended = 0x01, KeyPressed = 0x02, KeyPause = 0x04, KeyPrint = 0x08 };
    106 enum { IsKeyPressed = 0x01, IsExtKeyPressed = 0x02, IsKbdCaptured = 0x80 };
    107 
    10892UIMachineView* UIMachineView::create(  UIMachineWindow *pMachineWindow
    10993                                     , ulong uScreenId
     
    150134{
    151135    delete pMachineView;
    152 }
    153 
    154 int UIMachineView::keyboardState() const
    155 {
    156     return (m_bIsKeyboardCaptured ? UIViewStateType_KeyboardCaptured : 0) |
    157            (m_bIsHostkeyPressed ? UIViewStateType_HostKeyPressed : 0);
    158136}
    159137
     
    186164                viewport()->repaint();
    187165            }
    188             /* Reuse the focus event handler to uncapture keyboard: */
    189             if (hasFocus())
    190                 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);
    191             break;
    192         }
    193         case KMachineState_Stuck:
    194         {
    195             /* Reuse the focus event handler to uncapture keyboard: */
    196             if (hasFocus())
    197                 focusEvent(false /* aHasFocus*/, false /* aReleaseHostKey */);
    198166            break;
    199167        }
     
    214182                }
    215183            }
    216             /* Reuse the focus event handler to capture keyboard: */
    217             if (hasFocus())
    218                 focusEvent(true /* aHasFocus */);
    219184            break;
    220185        }
     
    234199    , m_pMachineWindow(pMachineWindow)
    235200    , m_uScreenId(uScreenId)
    236     , m_globalSettings(vboxGlobal().settings())
    237201    , m_pFrameBuffer(0)
    238202    , m_previousState(KMachineState_Null)
    239203    , m_desktopGeometryType(DesktopGeo_Invalid)
    240     , m_bIsKeyboardCaptured(false)
    241     , m_bIsHostkeyPressed(false)
    242     , m_bIsHostkeyAlone (false)
    243     , m_bIsHostkeyInCapture(false)
    244204    , m_bIsMachineWindowResizeIgnored(false)
    245     , m_fPassCAD(false)
    246205#ifdef VBOX_WITH_VIDEOHWACCEL
    247206    , m_fAccelerate2DVideo(bAccelerate2DVideo)
    248207#endif /* VBOX_WITH_VIDEOHWACCEL */
    249 #ifdef Q_WS_MAC
    250     , m_darwinKeyModifiers(0)
    251     , m_fKeyboardGrabbed (false)
    252 #endif /* Q_WS_MAC */
    253208{
    254209}
     
    433388    setFrameStyle(QFrame::NoFrame);
    434389
    435     /* Pressed keys: */
    436     ::memset(m_pressedKeys, 0, sizeof(m_pressedKeys));
    437 
    438390    /* Setup palette: */
    439391    QPalette palette(viewport()->palette());
     
    468420    /* Global settings: */
    469421    {
    470 #ifdef Q_WS_X11
    471         /* Initialize the X keyboard subsystem: */
    472         initMappedX11Keyboard(QX11Info::display(), vboxGlobal().settings().publicProperty("GUI/RemapScancodes"));
    473 #endif /* Q_WS_X11 */
    474 
    475422        /* Remember the desktop geometry and register for geometry
    476423         * change events for telling the guest about video modes we like: */
     
    487434        }
    488435    }
    489 
    490     /* Exatra data settings: */
    491     {
    492         /* CAD settings: */
    493         QString passCAD = session().GetConsole().GetMachine().GetExtraData(VBoxDefs::GUI_PassCAD);
    494         if (!passCAD.isEmpty() && ((passCAD != "false") || (passCAD != "no")))
    495             m_fPassCAD = true;
    496     }
    497 }
    498 
    499 void UIMachineView::cleanupCommon()
    500 {
    501 #ifdef Q_WS_WIN
    502     if (gKbdHook)
    503         UnhookWindowsHookEx(gKbdHook);
    504     gView = 0;
    505 #endif /* Q_WS_WIN */
    506 
    507 #ifdef Q_WS_MAC
    508     /* We have to make sure the callback for the keyboard events is released
    509      * when closing this view. */
    510     if (m_fKeyboardGrabbed)
    511         darwinGrabKeyboardEvents (false);
    512 #endif /* Q_WS_MAC */
    513436}
    514437
     
    717640}
    718641
    719 void UIMachineView::fixModifierState(LONG *piCodes, uint *puCount)
    720 {
    721     /* Synchronize the views of the host and the guest to the modifier keys.
    722      * This function will add up to 6 additional keycodes to codes. */
    723 
    724 #if defined(Q_WS_X11)
    725 
    726     Window   wDummy1, wDummy2;
    727     int      iDummy3, iDummy4, iDummy5, iDummy6;
    728     unsigned uMask;
    729     unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0, uKeyMaskScroll = 0;
    730 
    731     uKeyMaskCaps          = LockMask;
    732     XModifierKeymap* map  = XGetModifierMapping(QX11Info::display());
    733     KeyCode keyCodeNum    = XKeysymToKeycode(QX11Info::display(), XK_Num_Lock);
    734     KeyCode keyCodeScroll = XKeysymToKeycode(QX11Info::display(), XK_Scroll_Lock);
    735 
    736     for (int i = 0; i < 8; ++ i)
    737     {
    738         if (keyCodeNum != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeNum)
    739             uKeyMaskNum = 1 << i;
    740         else if (keyCodeScroll != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeScroll)
    741             uKeyMaskScroll = 1 << i;
    742     }
    743     XQueryPointer(QX11Info::display(), DefaultRootWindow(QX11Info::display()), &wDummy1, &wDummy2,
    744                   &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask);
    745     XFreeModifiermap(map);
    746 
    747     if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(uMask & uKeyMaskNum)))
    748     {
    749         uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1);
    750         piCodes[(*puCount)++] = 0x45;
    751         piCodes[(*puCount)++] = 0x45 | 0x80;
    752     }
    753     if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(uMask & uKeyMaskCaps)))
    754     {
    755         uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);
    756         piCodes[(*puCount)++] = 0x3a;
    757         piCodes[(*puCount)++] = 0x3a | 0x80;
    758         /* Some keyboard layouts require shift to be pressed to break
    759          * capslock.  For simplicity, only do this if shift is not
    760          * already held down. */
    761         if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
    762         {
    763             piCodes[(*puCount)++] = 0x2a;
    764             piCodes[(*puCount)++] = 0x2a | 0x80;
    765         }
    766     }
    767 
    768 #elif defined(Q_WS_WIN)
    769 
    770     if (uisession()->numLockAdaptionCnt() && (uisession()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK))))
    771     {
    772         uisession()->setNumLockAdaptionCnt(uisession()->numLockAdaptionCnt() - 1);
    773         piCodes[(*puCount)++] = 0x45;
    774         piCodes[(*puCount)++] = 0x45 | 0x80;
    775     }
    776     if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL))))
    777     {
    778         uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);
    779         piCodes[(*puCount)++] = 0x3a;
    780         piCodes[(*puCount)++] = 0x3a | 0x80;
    781         /* Some keyboard layouts require shift to be pressed to break
    782          * capslock.  For simplicity, only do this if shift is not
    783          * already held down. */
    784         if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
    785         {
    786             piCodes[(*puCount)++] = 0x2a;
    787             piCodes[(*puCount)++] = 0x2a | 0x80;
    788         }
    789     }
    790 
    791 #elif defined(Q_WS_MAC)
    792 
    793     /* if (uisession()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */
    794     if (uisession()->capsLockAdaptionCnt() && (uisession()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))
    795     {
    796         uisession()->setCapsLockAdaptionCnt(uisession()->capsLockAdaptionCnt() - 1);
    797         piCodes[(*puCount)++] = 0x3a;
    798         piCodes[(*puCount)++] = 0x3a | 0x80;
    799         /* Some keyboard layouts require shift to be pressed to break
    800          * capslock.  For simplicity, only do this if shift is not
    801          * already held down. */
    802         if (uisession()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
    803         {
    804             piCodes[(*puCount)++] = 0x2a;
    805             piCodes[(*puCount)++] = 0x2a | 0x80;
    806         }
    807     }
    808 
    809 #else
    810 
    811 //#warning Adapt UIMachineView::fixModifierState
    812 
    813 #endif
    814 }
    815 
    816642QPoint UIMachineView::viewportToContents(const QPoint &vp) const
    817643{
     
    823649    horizontalScrollBar()->setValue(horizontalScrollBar()->value() + dx);
    824650    verticalScrollBar()->setValue(verticalScrollBar()->value() + dy);
    825 }
    826 
    827 void UIMachineView::emitKeyboardStateChanged()
    828 {
    829     emit keyboardStateChanged(keyboardState());
    830 }
    831 
    832 void UIMachineView::captureKbd(bool fCapture, bool fEmitSignal /* = true */)
    833 {
    834     if (m_bIsKeyboardCaptured == fCapture)
    835         return;
    836 
    837 #if defined(Q_WS_WIN)
    838     /* On Win32, keyboard grabbing is ineffective, a low-level keyboard hook is used instead. */
    839 #elif defined(Q_WS_X11)
    840     /* On X11, we are using passive XGrabKey for normal (windowed) mode
    841      * instead of XGrabKeyboard (called by QWidget::grabKeyboard())
    842      * because XGrabKeyboard causes a problem under metacity - a window cannot be moved
    843      * using the mouse if it is currently actively grabing the keyboard;
    844      * For static modes we are using usual (active) keyboard grabbing. */
    845     switch (machineLogic()->visualStateType())
    846     {
    847         /* If window is moveable we are making passive keyboard grab: */
    848         case UIVisualStateType_Normal:
    849         {
    850             if (fCapture)
    851                 XGrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync);
    852             else
    853                 XUngrabKey(QX11Info::display(), AnyKey, AnyModifier, machineWindowWrapper()->machineWindow()->winId());
    854             break;
    855         }
    856         /* If window is NOT moveable we are making active keyboard grab: */
    857         case UIVisualStateType_Fullscreen:
    858         case UIVisualStateType_Seamless:
    859         {
    860             if (fCapture)
    861             {
    862                 /* Keyboard grabbing can fail because of some keyboard shortcut is still grabbed by window manager.
    863                  * We can't be sure this shortcut will be released at all, so we will retry to grab keyboard for 50 times,
    864                  * and after we will just ignore that issue: */
    865                 int cTriesLeft = 50;
    866                 while (cTriesLeft && XGrabKeyboard(QX11Info::display(), machineWindowWrapper()->machineWindow()->winId(), False, GrabModeAsync, GrabModeAsync, CurrentTime)) { --cTriesLeft; }
    867             }
    868             else
    869                 XUngrabKeyboard(QX11Info::display(), CurrentTime);
    870             break;
    871         }
    872         /* Should we try to grab keyboard in default case? I think - NO. */
    873         default:
    874             break;
    875     }
    876 #elif defined(Q_WS_MAC)
    877     /* On Mac OS X, we use the Qt methods + disabling global hot keys + watching modifiers
    878      * (for right/left separation). */
    879     if (fCapture)
    880     {
    881         ::DarwinDisableGlobalHotKeys(true);
    882         grabKeyboard();
    883     }
    884     else
    885     {
    886         ::DarwinDisableGlobalHotKeys(false);
    887         releaseKeyboard();
    888     }
    889 #else
    890     if (fCapture)
    891         grabKeyboard();
    892     else
    893         releaseKeyboard();
    894 #endif
    895 
    896     m_bIsKeyboardCaptured = fCapture;
    897 
    898     if (fEmitSignal)
    899         emitKeyboardStateChanged();
    900 }
    901 
    902 void UIMachineView::saveKeyStates()
    903 {
    904     ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys));
    905 }
    906 
    907 void UIMachineView::releaseAllPressedKeys(bool aReleaseHostKey /* = true */)
    908 {
    909     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    910     bool fSentRESEND = false;
    911 
    912     /* Send a dummy scan code (RESEND) to prevent the guest OS from recognizing
    913      * a single key click (for ex., Alt) and performing an unwanted action
    914      * (for ex., activating the menu) when we release all pressed keys below.
    915      * Note, that it's just a guess that sending RESEND will give the desired
    916      * effect :), but at least it works with NT and W2k guests. */
    917     for (uint i = 0; i < SIZEOF_ARRAY (m_pressedKeys); i++)
    918     {
    919         if (m_pressedKeys[i] & IsKeyPressed)
    920         {
    921             if (!fSentRESEND)
    922             {
    923                 keyboard.PutScancode (0xFE);
    924                 fSentRESEND = true;
    925             }
    926             keyboard.PutScancode(i | 0x80);
    927         }
    928         else if (m_pressedKeys[i] & IsExtKeyPressed)
    929         {
    930             if (!fSentRESEND)
    931             {
    932                 keyboard.PutScancode(0xFE);
    933                 fSentRESEND = true;
    934             }
    935             QVector <LONG> codes(2);
    936             codes[0] = 0xE0;
    937             codes[1] = i | 0x80;
    938             keyboard.PutScancodes(codes);
    939         }
    940         m_pressedKeys[i] = 0;
    941     }
    942 
    943     if (aReleaseHostKey)
    944         m_bIsHostkeyPressed = false;
    945 
    946 #ifdef Q_WS_MAC
    947     /* Clear most of the modifiers: */
    948     m_darwinKeyModifiers &=
    949         alphaLock | kEventKeyModifierNumLockMask |
    950         (aReleaseHostKey ? 0 : ::DarwinKeyCodeToDarwinModifierMask (m_globalSettings.hostKey()));
    951 #endif /* Q_WS_MAC */
    952 
    953     emitKeyboardStateChanged();
    954 }
    955 
    956 void UIMachineView::sendChangedKeyStates()
    957 {
    958     QVector <LONG> codes(2);
    959     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    960     for (uint i = 0; i < SIZEOF_ARRAY(m_pressedKeys); ++ i)
    961     {
    962         uint8_t os = m_pressedKeysCopy[i];
    963         uint8_t ns = m_pressedKeys[i];
    964         if ((os & IsKeyPressed) != (ns & IsKeyPressed))
    965         {
    966             codes[0] = i;
    967             if (!(ns & IsKeyPressed))
    968                 codes[0] |= 0x80;
    969             keyboard.PutScancode(codes[0]);
    970         }
    971         else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed))
    972         {
    973             codes[0] = 0xE0;
    974             codes[1] = i;
    975             if (!(ns & IsExtKeyPressed))
    976                 codes[1] |= 0x80;
    977             keyboard.PutScancodes(codes);
    978         }
    979     }
    980651}
    981652
     
    1081752    switch (pEvent->type())
    1082753    {
    1083         case QEvent::FocusIn:
    1084         {
    1085             if (uisession()->isRunning())
    1086                 focusEvent(true);
    1087             break;
    1088         }
    1089         case QEvent::FocusOut:
    1090         {
    1091             if (uisession()->isRunning())
    1092                 focusEvent(false);
    1093             else
    1094             {
    1095                 /* Release the host key and all other pressed keys too even when paused
    1096                  * (otherwise, we will get stuck keys in the guest when doing sendChangedKeyStates() on resume
    1097                  * because key presses were already recorded in m_pressedKeys but key releases will most likely
    1098                  * not reach us but the new focus window instead): */
    1099                 releaseAllPressedKeys(true /* including host key? */);
    1100             }
    1101             break;
    1102         }
    1103 
    1104754        case VBoxDefs::RepaintEventType:
    1105755        {
     
    1107757            viewport()->repaint(pPaintEvent->x() - contentsX(), pPaintEvent->y() - contentsY(),
    1108758                                pPaintEvent->width(), pPaintEvent->height());
    1109 
    1110             return true;
    1111         }
    1112 
    1113         case QEvent::KeyPress:
    1114         case QEvent::KeyRelease:
    1115         {
    1116             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    1117 
    1118             if (m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyPress)
    1119             {
    1120                 /* Passing F1-F12 keys to the guest: */
    1121                 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F12)
    1122                 {
    1123                     QVector <LONG> combo(6);
    1124                     combo[0] = 0x1d; /* Ctrl down */
    1125                     combo[1] = 0x38; /* Alt  down */
    1126                     combo[4] = 0xb8; /* Alt  up   */
    1127                     combo[5] = 0x9d; /* Ctrl up   */
    1128                     if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F10)
    1129                     {
    1130                         combo[2] = 0x3b + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 down */
    1131                         combo[3] = 0xbb + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 up   */
    1132                     }
    1133                     /* some scan slice */
    1134                     else if (pKeyEvent->key() >= Qt::Key_F11 && pKeyEvent->key() <= Qt::Key_F12)
    1135                     {
    1136                         combo[2] = 0x57 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 down */
    1137                         combo[3] = 0xd7 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 up   */
    1138                     }
    1139                     else
    1140                         Assert(0);
    1141 
    1142                     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    1143                     keyboard.PutScancodes(combo);
    1144                 }
    1145 
    1146                 /* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */
    1147                 machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(pKeyEvent->key()));
    1148             }
    1149             else if (!m_bIsHostkeyPressed && pEvent->type() == QEvent::KeyRelease)
    1150             {
    1151                 /* Show a possible warning on key release which seems to be more expected by the end user: */
    1152                 if (uisession()->isPaused())
    1153                 {
    1154                     /* Iif the reminder is disabled we pass the event to Qt to enable normal
    1155                      * keyboard functionality (for example, menu access with Alt+Letter): */
    1156                     if (!vboxProblem().remindAboutPausedVMInput())
    1157                         break;
    1158                 }
    1159             }
    1160 
    1161             pKeyEvent->accept();
    1162759            return true;
    1163760        }
     
    1231828                break;
    1232829            }
    1233 #ifdef Q_WS_WIN
    1234             /* Install/uninstall low-level kbd hook on every activation/deactivation to:
    1235              * a) avoid excess hook calls when we're not active and
    1236              * b) be always in front of any other possible hooks */
    1237             case QEvent::WindowActivate:
    1238             {
    1239                 gView = this;
    1240                 gKbdHook = SetWindowsHookEx(WH_KEYBOARD_LL, lowLevelKeyboardProc, GetModuleHandle(NULL), 0);
    1241                 AssertMsg(gKbdHook, ("SetWindowsHookEx(): err=%d", GetLastError()));
    1242                 break;
    1243             }
    1244             case QEvent::WindowDeactivate:
    1245             {
    1246                 if (gKbdHook)
    1247                 {
    1248                     UnhookWindowsHookEx(gKbdHook);
    1249                     gKbdHook = NULL;
    1250                     if (gView == this)
    1251                         gView = 0;
    1252                 }
    1253                 break;
    1254             }
    1255 #endif /* Q_WS_WIN */
    1256 #ifdef Q_WS_MAC
    1257             /* Install/remove the keyboard event handler: */
    1258             case QEvent::WindowActivate:
    1259                 darwinGrabKeyboardEvents(true);
    1260                 break;
    1261             case QEvent::WindowDeactivate:
    1262                 darwinGrabKeyboardEvents(false);
    1263                 break;
    1264 #endif /* Q_WS_MAC */
    1265830            default:
    1266831                break;
     
    1269834
    1270835    return QAbstractScrollArea::eventFilter(pWatched, pEvent);
    1271 }
    1272 
    1273 void UIMachineView::focusEvent(bool fHasFocus, bool fReleaseHostKey /* = true */)
    1274 {
    1275     if (fHasFocus)
    1276     {
    1277 #ifdef Q_WS_WIN
    1278         if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture() && GetAncestor(winId(), GA_ROOT) == GetForegroundWindow())
    1279 #else /* Q_WS_WIN */
    1280         if (!uisession()->isAutoCaptureDisabled() && m_globalSettings.autoCapture())
    1281 #endif /* !Q_WS_WIN */
    1282         {
    1283             captureKbd(true);
    1284         }
    1285 
    1286         /* Reset the single-time disable capture flag: */
    1287         if (uisession()->isAutoCaptureDisabled())
    1288             uisession()->setAutoCaptureDisabled(false);
    1289     }
    1290     else
    1291     {
    1292         captureKbd(false, false);
    1293         releaseAllPressedKeys(fReleaseHostKey);
    1294     }
    1295 }
    1296 
    1297 bool UIMachineView::keyEvent(int iKey, uint8_t uScan, int fFlags, wchar_t *pUniKey /* = NULL */)
    1298 {
    1299     const bool isHostKey = iKey == m_globalSettings.hostKey();
    1300 
    1301     LONG buf[16];
    1302     LONG *codes = buf;
    1303     uint count = 0;
    1304     uint8_t whatPressed = 0;
    1305 
    1306     if (!isHostKey && !m_bIsHostkeyPressed)
    1307     {
    1308         if (fFlags & KeyPrint)
    1309         {
    1310             static LONG PrintMake[] = { 0xE0, 0x2A, 0xE0, 0x37 };
    1311             static LONG PrintBreak[] = { 0xE0, 0xB7, 0xE0, 0xAA };
    1312             if (fFlags & KeyPressed)
    1313             {
    1314                 codes = PrintMake;
    1315                 count = SIZEOF_ARRAY(PrintMake);
    1316             }
    1317             else
    1318             {
    1319                 codes = PrintBreak;
    1320                 count = SIZEOF_ARRAY(PrintBreak);
    1321             }
    1322         }
    1323         else if (fFlags & KeyPause)
    1324         {
    1325             if (fFlags & KeyPressed)
    1326             {
    1327                 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 };
    1328                 codes = Pause;
    1329                 count = SIZEOF_ARRAY(Pause);
    1330             }
    1331             else
    1332             {
    1333                 /* Pause shall not produce a break code */
    1334                 return true;
    1335             }
    1336         }
    1337         else
    1338         {
    1339             if (fFlags & KeyPressed)
    1340             {
    1341                 /* Check if the guest has the same view on the modifier keys (NumLock,
    1342                  * CapsLock, ScrollLock) as the X server. If not, send KeyPress events
    1343                  * to synchronize the state. */
    1344                 fixModifierState(codes, &count);
    1345             }
    1346 
    1347             /* Check if it's C-A-D and GUI/PassCAD is not true */
    1348             if (!m_fPassCAD &&
    1349                 uScan == 0x53 /* Del */ &&
    1350                 ((m_pressedKeys[0x38] & IsKeyPressed) /* Alt */ ||
    1351                  (m_pressedKeys[0x38] & IsExtKeyPressed)) &&
    1352                 ((m_pressedKeys[0x1d] & IsKeyPressed) /* Ctrl */ ||
    1353                  (m_pressedKeys[0x1d] & IsExtKeyPressed)))
    1354             {
    1355                 /* Use the C-A-D combination as a last resort to get the
    1356                  * keyboard and mouse back to the host when the user forgets
    1357                  * the Host Key. Note that it's always possible to send C-A-D
    1358                  * to the guest using the Host+Del combination. BTW, it would
    1359                  * be preferrable to completely ignore C-A-D in guests, but
    1360                  * that's not possible because we cannot predict what other
    1361                  * keys will be pressed next when one of C, A, D is held. */
    1362                 if (uisession()->isRunning() && m_bIsKeyboardCaptured)
    1363                 {
    1364                     captureKbd(false);
    1365                     if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()))
    1366                         machineLogic()->mouseHandler()->captureMouse(screenId());
    1367                 }
    1368 
    1369                 return true;
    1370             }
    1371 
    1372             /* Process the scancode and update the table of pressed keys: */
    1373             whatPressed = IsKeyPressed;
    1374 
    1375             if (fFlags & KeyExtended)
    1376             {
    1377                 codes[count++] = 0xE0;
    1378                 whatPressed = IsExtKeyPressed;
    1379             }
    1380 
    1381             if (fFlags & KeyPressed)
    1382             {
    1383                 codes[count++] = uScan;
    1384                 m_pressedKeys[uScan] |= whatPressed;
    1385             }
    1386             else
    1387             {
    1388                 /* If we haven't got this key's press message, we ignore its release: */
    1389                 if (!(m_pressedKeys[uScan] & whatPressed))
    1390                     return true;
    1391                 codes[count++] = uScan | 0x80;
    1392                 m_pressedKeys[uScan] &= ~whatPressed;
    1393             }
    1394 
    1395             if (m_bIsKeyboardCaptured)
    1396                 m_pressedKeys[uScan] |= IsKbdCaptured;
    1397             else
    1398                 m_pressedKeys[uScan] &= ~IsKbdCaptured;
    1399         }
    1400     }
    1401     else
    1402     {
    1403         /* Currently this is used in winLowKeyboardEvent() only: */
    1404         m_bIsHostkeyInCapture = m_bIsKeyboardCaptured;
    1405     }
    1406 
    1407     bool emitSignal = false;
    1408     int hotkey = 0;
    1409 
    1410     /* Process the host key: */
    1411     if (fFlags & KeyPressed)
    1412     {
    1413         if (isHostKey)
    1414         {
    1415             if (!m_bIsHostkeyPressed)
    1416             {
    1417                 m_bIsHostkeyPressed = m_bIsHostkeyAlone = true;
    1418                 if (uisession()->isRunning())
    1419                     saveKeyStates();
    1420                 emitSignal = true;
    1421             }
    1422         }
    1423         else
    1424         {
    1425             if (m_bIsHostkeyPressed)
    1426             {
    1427                 if (m_bIsHostkeyAlone)
    1428                 {
    1429                     hotkey = iKey;
    1430                     m_bIsHostkeyAlone = false;
    1431                 }
    1432             }
    1433         }
    1434     }
    1435     else
    1436     {
    1437         if (isHostKey)
    1438         {
    1439             if (m_bIsHostkeyPressed)
    1440             {
    1441                 m_bIsHostkeyPressed = false;
    1442 
    1443                 if (m_bIsHostkeyAlone)
    1444                 {
    1445                     if (uisession()->isPaused())
    1446                     {
    1447                         vboxProblem().remindAboutPausedVMInput();
    1448                     }
    1449                     else if (uisession()->isRunning())
    1450                     {
    1451                         bool captured = m_bIsKeyboardCaptured;
    1452                         bool ok = true;
    1453                         if (!captured)
    1454                         {
    1455                             /* temporarily disable auto capture that will take
    1456                              * place after this dialog is dismissed because
    1457                              * the capture state is to be defined by the
    1458                              * dialog result itself */
    1459                             uisession()->setAutoCaptureDisabled(true);
    1460                             bool autoConfirmed = false;
    1461                             ok = vboxProblem().confirmInputCapture (&autoConfirmed);
    1462                             if (autoConfirmed)
    1463                                 uisession()->setAutoCaptureDisabled(false);
    1464                             /* otherwise, the disable flag will be reset in
    1465                              * the next console view's foucs in event (since
    1466                              * may happen asynchronously on some platforms,
    1467                              * after we return from this code) */
    1468                         }
    1469 
    1470                         if (ok)
    1471                         {
    1472                             captureKbd (!captured, false);
    1473                             if (!(uisession()->isMouseSupportsAbsolute() && uisession()->isMouseIntegrated()))
    1474                             {
    1475 #ifdef Q_WS_X11
    1476                                 /* make sure that pending FocusOut events from the
    1477                                  * previous message box are handled, otherwise the
    1478                                  * mouse is immediately ungrabbed. */
    1479                                 qApp->processEvents();
    1480 #endif /* Q_WS_X11 */
    1481                                 if (m_bIsKeyboardCaptured)
    1482                                     machineLogic()->mouseHandler()->captureMouse(screenId());
    1483                                 else
    1484                                     machineLogic()->mouseHandler()->releaseMouse();
    1485                             }
    1486                         }
    1487                     }
    1488                 }
    1489 
    1490                 if (uisession()->isRunning())
    1491                     sendChangedKeyStates();
    1492 
    1493                 emitSignal = true;
    1494             }
    1495         }
    1496         else
    1497         {
    1498             if (m_bIsHostkeyPressed)
    1499                 m_bIsHostkeyAlone = false;
    1500         }
    1501     }
    1502 
    1503     /* emit the keyboard state change signal */
    1504     if (emitSignal)
    1505         emitKeyboardStateChanged();
    1506 
    1507     /* Process Host+<key> shortcuts. currently, <key> is limited to
    1508      * alphanumeric chars. Other Host+<key> combinations are handled in
    1509      * event(). */
    1510     if (hotkey)
    1511     {
    1512         bool processed = false;
    1513 #if defined (Q_WS_WIN)
    1514         NOREF(pUniKey);
    1515         int n = GetKeyboardLayoutList(0, NULL);
    1516         Assert (n);
    1517         HKL *list = new HKL[n];
    1518         GetKeyboardLayoutList(n, list);
    1519         for (int i = 0; i < n && !processed; i++)
    1520         {
    1521             wchar_t ch;
    1522             static BYTE keys[256] = {0};
    1523             if (!ToUnicodeEx(hotkey, 0, keys, &ch, 1, 0, list[i]) == 1)
    1524                 ch = 0;
    1525             if (ch)
    1526                 processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence((Qt::UNICODE_ACCEL + QChar(ch).toUpper().unicode())));
    1527         }
    1528         delete[] list;
    1529 #elif defined (Q_WS_X11)
    1530         NOREF(pUniKey);
    1531         Display *display = QX11Info::display();
    1532         int keysyms_per_keycode = getKeysymsPerKeycode();
    1533         KeyCode kc = XKeysymToKeycode (display, iKey);
    1534         for (int i = 0; i < keysyms_per_keycode && !processed; i += 2)
    1535         {
    1536             KeySym ks = XKeycodeToKeysym(display, kc, i);
    1537             char ch = 0;
    1538             if (!XkbTranslateKeySym(display, &ks, 0, &ch, 1, NULL) == 1)
    1539                 ch = 0;
    1540             if (ch)
    1541                 QChar c = QString::fromLocal8Bit(&ch, 1)[0];
    1542         }
    1543 #elif defined (Q_WS_MAC)
    1544         if (pUniKey && pUniKey[0] && !pUniKey[1])
    1545             processed = machineWindowWrapper()->machineLogic()->actionsPool()->processHotKey(QKeySequence(Qt::UNICODE_ACCEL + QChar(pUniKey[0]).toUpper().unicode()));
    1546 
    1547         /* Don't consider the hot key as pressed since the guest never saw
    1548          * it. (probably a generic thing) */
    1549         m_pressedKeys[uScan] &= ~whatPressed;
    1550 #endif
    1551 
    1552         /* Grab the key from Qt if processed, or pass it to Qt otherwise
    1553          * in order to process non-alphanumeric keys in event(), after they are
    1554          * converted to Qt virtual keys. */
    1555         return processed;
    1556     }
    1557 
    1558     /* No more to do, if the host key is in action or the VM is paused: */
    1559     if (m_bIsHostkeyPressed || isHostKey || uisession()->isPaused())
    1560     {
    1561         /* Grab the key from Qt and from VM if it's a host key,
    1562          * otherwise just pass it to Qt */
    1563         return isHostKey;
    1564     }
    1565 
    1566     CKeyboard keyboard = session().GetConsole().GetKeyboard();
    1567     Assert(!keyboard.isNull());
    1568 
    1569 #ifdef Q_WS_WIN
    1570     /* send pending WM_PAINT events */
    1571     ::UpdateWindow(viewport()->winId());
    1572 #endif /* Q_WS_WIN */
    1573 
    1574     std::vector <LONG> scancodes(codes, &codes[count]);
    1575     keyboard.PutScancodes(QVector<LONG>::fromStdVector(scancodes));
    1576 
    1577     /* Grab the key from Qt: */
    1578     return true;
    1579836}
    1580837
     
    1631888#if defined(Q_WS_WIN)
    1632889
    1633 LRESULT CALLBACK UIMachineView::lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    1634 {
    1635     if (gView && nCode == HC_ACTION && gView->winLowKeyboardEvent(wParam, *(KBDLLHOOKSTRUCT *)lParam))
    1636         return 1;
    1637 
    1638     return CallNextHookEx(NULL, nCode, wParam, lParam);
    1639 }
    1640 
    1641 bool UIMachineView::winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event)
    1642 {
    1643     /* Sometimes it happens that Win inserts additional events on some key
    1644      * press/release. For example, it prepends ALT_GR in German layout with
    1645      * the VK_LCONTROL vkey with curious 0x21D scan code (seems to be necessary
    1646      * to specially treat ALT_GR to enter additional chars to regular apps).
    1647      * These events are definitely unwanted in VM, so filter them out. */
    1648     /* Note (michael): it also sometimes sends the VK_CAPITAL vkey with scan
    1649      * code 0x23a. If this is not passed through then it is impossible to
    1650      * cancel CapsLock on a French keyboard.  I didn't find any other examples
    1651      * of these strange events.  Let's hope we are not missing anything else
    1652      * of importance! */
    1653     if (hasFocus() && (event.scanCode & ~0xFF))
    1654     {
    1655         if (event.vkCode == VK_CAPITAL)
    1656             return false;
    1657         else
    1658             return true;
    1659     }
    1660 
    1661     if (!m_bIsKeyboardCaptured)
    1662         return false;
    1663 
    1664     /* it's possible that a key has been pressed while the keyboard was not
    1665      * captured, but is being released under the capture. Detect this situation
    1666      * and return false to let Windows process the message normally and update
    1667      * its key state table (to avoid the stuck key effect). */
    1668     uint8_t what_pressed = (event.flags & 0x01) && (event.vkCode != VK_RSHIFT) ? IsExtKeyPressed : IsKeyPressed;
    1669     if ((event.flags & 0x80) /* released */ &&
    1670         ((event.vkCode == m_globalSettings.hostKey() && !m_bIsHostkeyInCapture) ||
    1671          (m_pressedKeys[event.scanCode] & (IsKbdCaptured | what_pressed)) == what_pressed))
    1672         return false;
    1673 
    1674     MSG message;
    1675     message.hwnd = winId();
    1676     message.message = msg;
    1677     message.wParam = event.vkCode;
    1678     message.lParam = 1 | (event.scanCode & 0xFF) << 16 | (event.flags & 0xFF) << 24;
    1679 
    1680     /* Windows sets here the extended bit when the Right Shift key is pressed,
    1681      * which is totally wrong. Undo it. */
    1682     if (event.vkCode == VK_RSHIFT)
    1683         message.lParam &= ~0x1000000;
    1684 
    1685     /* we suppose here that this hook is always called on the main GUI thread */
    1686     long dummyResult;
    1687     return winEvent(&message, &dummyResult);
    1688 }
    1689 
    1690 bool UIMachineView::winEvent(MSG *aMsg, long* /* aResult */)
    1691 {
    1692     if (!(aMsg->message == WM_KEYDOWN || aMsg->message == WM_SYSKEYDOWN ||
    1693           aMsg->message == WM_KEYUP || aMsg->message == WM_SYSKEYUP))
    1694         return false;
    1695 
    1696     /* Check for the special flag possibly set at the end of this function */
    1697     if (aMsg->lParam & (0x1 << 25))
    1698     {
    1699         aMsg->lParam &= ~(0x1 << 25);
    1700         return false;
    1701     }
    1702 
    1703     int scan = (aMsg->lParam >> 16) & 0x7F;
    1704     /* scancodes 0x80 and 0x00 are ignored */
    1705     if (!scan)
    1706         return true;
    1707 
    1708     int vkey = aMsg->wParam;
    1709 
    1710     /* When one of the SHIFT keys is held and one of the cursor movement
    1711      * keys is pressed, Windows duplicates SHIFT press/release messages,
    1712      * but with the virtual key code set to 0xFF. These virtual keys are also
    1713      * sent in some other situations (Pause, PrtScn, etc.). Ignore such
    1714      * messages. */
    1715     if (vkey == 0xFF)
    1716         return true;
    1717 
    1718     int flags = 0;
    1719     if (aMsg->lParam & 0x1000000)
    1720         flags |= KeyExtended;
    1721     if (!(aMsg->lParam & 0x80000000))
    1722         flags |= KeyPressed;
    1723 
    1724     switch (vkey)
    1725     {
    1726         case VK_SHIFT:
    1727         case VK_CONTROL:
    1728         case VK_MENU:
    1729         {
    1730             /* overcome stupid Win32 modifier key generalization */
    1731             int keyscan = scan;
    1732             if (flags & KeyExtended)
    1733                 keyscan |= 0xE000;
    1734             switch (keyscan)
    1735             {
    1736                 case 0x002A: vkey = VK_LSHIFT; break;
    1737                 case 0x0036: vkey = VK_RSHIFT; break;
    1738                 case 0x001D: vkey = VK_LCONTROL; break;
    1739                 case 0xE01D: vkey = VK_RCONTROL; break;
    1740                 case 0x0038: vkey = VK_LMENU; break;
    1741                 case 0xE038: vkey = VK_RMENU; break;
    1742             }
    1743             break;
    1744         }
    1745         case VK_NUMLOCK:
    1746             /* Win32 sets the extended bit for the NumLock key. Reset it. */
    1747             flags &= ~KeyExtended;
    1748             break;
    1749         case VK_SNAPSHOT:
    1750             flags |= KeyPrint;
    1751             break;
    1752         case VK_PAUSE:
    1753             flags |= KeyPause;
    1754             break;
    1755     }
    1756 
    1757     bool result = keyEvent(vkey, scan, flags);
    1758     if (!result && m_bIsKeyboardCaptured)
    1759     {
    1760         /* keyEvent() returned that it didn't process the message, but since the
    1761          * keyboard is captured, we don't want to pass it to Windows. We just want
    1762          * to let Qt process the message (to handle non-alphanumeric <HOST>+key
    1763          * shortcuts for example). So send it direcltly to the window with the
    1764          * special flag in the reserved area of lParam (to avoid recursion). */
    1765         ::SendMessage(aMsg->hwnd, aMsg->message,
    1766                       aMsg->wParam, aMsg->lParam | (0x1 << 25));
    1767         return true;
    1768     }
    1769 
    1770     /* These special keys have to be handled by Windows as well to update the
    1771      * internal modifier state and to enable/disable the keyboard LED */
    1772     if (vkey == VK_NUMLOCK || vkey == VK_CAPITAL || vkey == VK_LSHIFT || vkey == VK_RSHIFT)
    1773         return false;
    1774 
    1775     return result;
     890bool UIMachineView::winEvent(MSG *pMsg, long* /* piResult */)
     891{
     892    /* Check if some system event should be filtered-out.
     893     * Returning 'true' means filtering-out,
     894     * Returning 'false' means passing event to Qt. */
     895    bool fResult = false; /* Pass to Qt by default: */
     896    switch (pMsg->message)
     897    {
     898        case WM_KEYDOWN:
     899        case WM_KEYUP:
     900        case WM_SYSKEYDOWN:
     901        case WM_SYSKEYUP:
     902        {
     903            /* Filter using keyboard-filter: */
     904            bool fKeyboardFilteringResult = machineLogic()->keyboardHandler()->winEventFilter(pMsg, screenId());
     905            /* Keyboard filter rules the result: */
     906            fResult = fKeyboardFilteringResult;
     907            break;
     908        }
     909        default:
     910            break;
     911    }
     912    /* Return result: */
     913    return fResult;
    1776914}
    1777915
    1778916#elif defined(Q_WS_X11)
    1779917
    1780 static Bool VBoxConsoleViewCompEvent(Display *, XEvent *pEvent, XPointer pvArg)
    1781 {
    1782     XEvent *pKeyEvent = (XEvent*)pvArg;
    1783     if ((pEvent->type == XKeyPress) && (pEvent->xkey.keycode == pKeyEvent->xkey.keycode))
    1784         return True;
    1785     else
    1786         return False;
    1787 }
    1788 
    1789918bool UIMachineView::x11Event(XEvent *pEvent)
    1790919{
     920    /* Check if some system event should be filtered-out.
     921     * Returning 'true' means filtering-out,
     922     * Returning 'false' means passing event to Qt. */
     923    bool fResult = false; /* Pass to Qt by default: */
    1791924    switch (pEvent->type)
    1792925    {
    1793         /* We have to handle XFocusOut right here as this event is not passed
    1794          * to UIMachineView::event(). Handling this event is important for
    1795          * releasing the keyboard before the screen saver gets active.
    1796          *
    1797          * See public ticket #3894: Apparently this makes problems with newer
    1798          * versions of Qt and this hack is probably not necessary anymore.
    1799          * So disable it for Qt >= 4.5.0. */
    1800926        case XFocusOut:
    1801927        case XFocusIn:
    1802             if (uisession()->isRunning())
    1803             {
    1804                 if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0))
    1805                 {
    1806                     focusEvent(pEvent->type == XFocusIn);
    1807                     if (pEvent->type == XFocusOut)
    1808                         machineLogic()->mouseHandler()->releaseMouse();
    1809                 }
    1810             }
    1811             return false;
    1812928        case XKeyPress:
    1813929        case XKeyRelease:
    1814             break;
     930        {
     931            /* Filter using keyboard-filter: */
     932            bool fKeyboardFilteringResult = machineLogic()->keyboardHandler()->x11EventFilter(pEvent, screenId());
     933            /* Filter using mouse-filter: */
     934            bool fMouseFilteringResult = machineLogic()->mouseHandler()->x11EventFilter(pEvent, screenId());
     935            /* If at least one of filters wants to filter event out then the result is 'true': */
     936            fResult = fKeyboardFilteringResult || fMouseFilteringResult;
     937            break;
     938        }
    1815939        default:
    1816             return false; /* pass the event to Qt */
    1817     }
    1818 
    1819     /* Translate the keycode to a PC scan code. */
    1820     unsigned scan = handleXKeyEvent(pEvent);
    1821 
    1822     /* scancodes 0x00 (no valid translation) and 0x80 are ignored */
    1823     if (!scan & 0x7F)
    1824         return true;
    1825 
    1826     /* Fix for http://www.virtualbox.org/ticket/1296:
    1827      * when X11 sends events for repeated keys, it always inserts an
    1828      * XKeyRelease before the XKeyPress. */
    1829     XEvent returnEvent;
    1830     if ((pEvent->type == XKeyRelease) && (XCheckIfEvent(pEvent->xkey.display, &returnEvent,
    1831         VBoxConsoleViewCompEvent, (XPointer)pEvent) == True))
    1832     {
    1833         XPutBackEvent(pEvent->xkey.display, &returnEvent);
    1834         /* Discard it, don't pass it to Qt. */
    1835         return true;
    1836     }
    1837 
    1838     KeySym ks = ::XKeycodeToKeysym(pEvent->xkey.display, pEvent->xkey.keycode, 0);
    1839 
    1840     int flags = 0;
    1841     if (scan >> 8)
    1842         flags |= KeyExtended;
    1843     if (pEvent->type == XKeyPress)
    1844         flags |= KeyPressed;
    1845 
    1846     /* Remove the extended flag */
    1847     scan &= 0x7F;
    1848 
    1849     switch (ks)
    1850     {
    1851         case XK_Print:
    1852             flags |= KeyPrint;
    1853             break;
    1854         case XK_Pause:
    1855             flags |= KeyPause;
    1856             break;
    1857     }
    1858 
    1859     return keyEvent(ks, scan, flags);
    1860 }
    1861 
    1862 #elif defined(Q_WS_MAC)
    1863 
    1864 void UIMachineView::darwinGrabKeyboardEvents(bool fGrab)
    1865 {
    1866     m_fKeyboardGrabbed = fGrab;
    1867     if (fGrab)
    1868     {
    1869         /* Disable mouse and keyboard event compression/delaying to make sure we *really* get all of the events. */
    1870         ::CGSetLocalEventsSuppressionInterval(0.0);
    1871         machineLogic()->mouseHandler()->setMouseCoalescingEnabled(false);
    1872 
    1873         /* Register the event callback/hook and grab the keyboard. */
    1874         UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
    1875                                                                 UIMachineView::darwinEventHandlerProc, this);
    1876 
    1877         ::DarwinGrabKeyboard (false);
    1878     }
    1879     else
    1880     {
    1881         ::DarwinReleaseKeyboard();
    1882         UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown  | NSKeyUp | | NSFlagsChanged */,
    1883                                                                   UIMachineView::darwinEventHandlerProc, this);
    1884     }
    1885 }
    1886 
    1887 bool UIMachineView::darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
    1888 {
    1889     UIMachineView *view = (UIMachineView*)pvUser;
    1890     EventRef inEvent = (EventRef)pvCarbonEvent;
    1891     UInt32 eventClass = ::GetEventClass(inEvent);
    1892 
    1893     /* Check if this is an application key combo. In that case we will not pass
    1894      * the event to the guest, but let the host process it. */
    1895     if (::darwinIsApplicationCommand(pvCocoaEvent))
    1896         return false;
    1897 
    1898     /* All keyboard class events needs to be handled. */
    1899     if (eventClass == kEventClassKeyboard)
    1900     {
    1901         if (view->darwinKeyboardEvent (pvCocoaEvent, inEvent))
    1902             return true;
    1903     }
    1904     /* Pass the event along. */
    1905     return false;
    1906 }
    1907 
    1908 bool UIMachineView::darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent)
    1909 {
    1910     bool ret = false;
    1911     UInt32 EventKind = ::GetEventKind(inEvent);
    1912     if (EventKind != kEventRawKeyModifiersChanged)
    1913     {
    1914         /* convert keycode to set 1 scan code. */
    1915         UInt32 keyCode = ~0U;
    1916         ::GetEventParameter(inEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof (keyCode), NULL, &keyCode);
    1917         unsigned scanCode = ::DarwinKeycodeToSet1Scancode(keyCode);
    1918         if (scanCode)
    1919         {
    1920             /* calc flags. */
    1921             int flags = 0;
    1922             if (EventKind != kEventRawKeyUp)
    1923                 flags |= KeyPressed;
    1924             if (scanCode & VBOXKEY_EXTENDED)
    1925                 flags |= KeyExtended;
    1926             /** @todo KeyPause, KeyPrint. */
    1927             scanCode &= VBOXKEY_SCANCODE_MASK;
    1928 
    1929             /* get the unicode string (if present). */
    1930             AssertCompileSize(wchar_t, 2);
    1931             AssertCompileSize(UniChar, 2);
    1932             ByteCount cbWritten = 0;
    1933             wchar_t ucs[8];
    1934             if (::GetEventParameter(inEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL,
    1935                                     sizeof(ucs), &cbWritten, &ucs[0]) != 0)
    1936                 cbWritten = 0;
    1937             ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */
    1938 
    1939             ret = keyEvent(keyCode, scanCode, flags, ucs[0] ? ucs : NULL);
    1940         }
    1941     }
    1942     else
    1943     {
    1944         /* May contain multiple modifier changes, kind of annoying. */
    1945         UInt32 newMask = 0;
    1946         ::GetEventParameter(inEvent, kEventParamKeyModifiers, typeUInt32, NULL,
    1947                             sizeof(newMask), NULL, &newMask);
    1948         newMask = ::DarwinAdjustModifierMask(newMask, pvCocoaEvent);
    1949         UInt32 changed = newMask ^ m_darwinKeyModifiers;
    1950         if (changed)
    1951         {
    1952             for (UInt32 bit = 0; bit < 32; bit++)
    1953             {
    1954                 if (!(changed & (1 << bit)))
    1955                     continue;
    1956                 unsigned scanCode = ::DarwinModifierMaskToSet1Scancode(1 << bit);
    1957                 if (!scanCode)
    1958                     continue;
    1959                 unsigned keyCode = ::DarwinModifierMaskToDarwinKeycode(1 << bit);
    1960                 Assert(keyCode);
    1961 
    1962                 if (!(scanCode & VBOXKEY_LOCK))
    1963                 {
    1964                     unsigned flags = (newMask & (1 << bit)) ? KeyPressed : 0;
    1965                     if (scanCode & VBOXKEY_EXTENDED)
    1966                         flags |= KeyExtended;
    1967                     scanCode &= VBOXKEY_SCANCODE_MASK;
    1968                     ret |= keyEvent(keyCode, scanCode & 0xff, flags);
    1969                 }
    1970                 else
    1971                 {
    1972                     unsigned flags = 0;
    1973                     if (scanCode & VBOXKEY_EXTENDED)
    1974                         flags |= KeyExtended;
    1975                     scanCode &= VBOXKEY_SCANCODE_MASK;
    1976                     keyEvent(keyCode, scanCode, flags | KeyPressed);
    1977                     keyEvent(keyCode, scanCode, flags);
    1978                 }
    1979             }
    1980         }
    1981 
    1982         m_darwinKeyModifiers = newMask;
    1983 
    1984         /* Always return true here because we'll otherwise getting a Qt event
    1985            we don't want and that will only cause the Pause warning to pop up. */
    1986         ret = true;
    1987     }
    1988 
    1989     return ret;
     940            break;
     941    }
     942    /* Return result: */
     943    return fResult;
    1990944}
    1991945
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h

    r30636 r30637  
    3737class UIMachineWindow;
    3838class UIFrameBuffer;
    39 class VBoxGlobalSettings;
    4039
    4140class UIMachineView : public QAbstractScrollArea
     
    5958    static void destroy(UIMachineView *pMachineView);
    6059
    61     /* Public getters: */
    62     int keyboardState() const;
    63 
    6460    /* Public setters: */
    6561    virtual void setGuestAutoresizeEnabled(bool /* fEnabled */) {}
     
    6965
    7066signals:
    71 
    72     /* Keyboard state-change signals: */
    73     void keyboardStateChanged(int iState);
    7467
    7568    /* Utility signals: */
     
    10497    //virtual void cleanupConsoleConnections() {}
    10598    //virtual void cleanupFilters() {}
    106     virtual void cleanupCommon();
     99    //virtual void cleanupCommon() {}
    107100    virtual void cleanupFrameBuffer();
    108101
     
    121114    ulong screenId() const { return m_uScreenId; }
    122115    UIFrameBuffer* frameBuffer() const { return m_pFrameBuffer; }
    123     bool isHostKeyPressed() const { return m_bIsHostkeyPressed; }
    124116    bool isMachineWindowResizeIgnored() const { return m_bIsMachineWindowResizeIgnored; }
    125117    const QPixmap& pauseShot() const { return m_pauseShot; }
     
    128120    QSize desktopGeometry() const;
    129121    QSize guestSizeHint();
    130 #ifdef Q_WS_MAC
    131     /* These getters are temporary here while UIKeyboardHandler is not implemented: */
    132     bool isHostKeyAlone() const { return m_bIsHostkeyAlone; }
    133     bool isKeyboardGrabbed() const { return m_fKeyboardGrabbed; }
    134 #endif /* Q_WS_MAC */
    135122
    136123    /* Protected setters: */
     
    145132    virtual void maybeRestrictMinimumSize() = 0;
    146133    virtual void updateSliders();
    147     void fixModifierState(LONG *piCodes, uint *puCount);
    148134    QPoint viewportToContents(const QPoint &vp) const;
    149135    void scrollBy(int dx, int dy);
    150     void emitKeyboardStateChanged();
    151     void captureKbd(bool fCapture, bool fEmitSignal = true);
    152     void saveKeyStates();
    153     void releaseAllPressedKeys(bool aReleaseHostKey = true);
    154     void sendChangedKeyStates();
    155136    static void dimImage(QImage &img);
    156137#ifdef VBOX_WITH_VIDEOHWACCEL
     
    166147    bool event(QEvent *pEvent);
    167148    bool eventFilter(QObject *pWatched, QEvent *pEvent);
    168     void focusEvent(bool aHasFocus, bool aReleaseHostKey = true);
    169     bool keyEvent(int aKey, uint8_t aScan, int aFlags, wchar_t *aUniKey = NULL);
    170149    void resizeEvent(QResizeEvent *pEvent);
    171150    void moveEvent(QMoveEvent *pEvent);
     
    174153    /* Platform specific event processors: */
    175154#if defined(Q_WS_WIN)
    176     static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
    177     bool winLowKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event);
    178155    bool winEvent(MSG *pMsg, long *puResult);
    179156#elif defined(Q_WS_X11)
    180157    bool x11Event(XEvent *event);
    181 #elif defined(Q_WS_MAC)
    182     void darwinGrabKeyboardEvents(bool fGrab);
    183     static bool darwinEventHandlerProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser);
    184     bool darwinKeyboardEvent(const void *pvCocoaEvent, EventRef inEvent);
    185158#endif
    186159
     
    188161    UIMachineWindow *m_pMachineWindow;
    189162    ulong m_uScreenId;
    190     const VBoxGlobalSettings &m_globalSettings;
    191163    UIFrameBuffer *m_pFrameBuffer;
    192164    KMachineState m_previousState;
     
    196168    QSize m_storedConsoleSize;
    197169
    198     uint8_t m_pressedKeys[128];
    199     uint8_t m_pressedKeysCopy[128];
    200 
    201     bool m_bIsKeyboardCaptured : 1;
    202     bool m_bIsHostkeyPressed : 1;
    203     bool m_bIsHostkeyAlone : 1;
    204     bool m_bIsHostkeyInCapture : 1;
    205170    bool m_bIsMachineWindowResizeIgnored : 1;
    206     bool m_fPassCAD : 1;
    207171#ifdef VBOX_WITH_VIDEOHWACCEL
    208172    bool m_fAccelerate2DVideo : 1;
    209173#endif /* VBOX_WITH_VIDEOHWACCEL */
    210174
    211 #ifdef Q_WS_MAC
    212     /** The current modifier key mask. Used to figure out which modifier
    213      *  key was pressed when we get a kEventRawKeyModifiersChanged event. */
    214     UInt32 m_darwinKeyModifiers;
    215     bool m_fKeyboardGrabbed;
    216 #endif /* Q_WS_MAC */
    217 
    218175    QPixmap m_pauseShot;
    219176
    220177    /* Friend classes: */
     178    friend class UIKeyboardHandler;
    221179    friend class UIMouseHandler;
    222180    friend class UIMachineLogic;
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMachineWindow.cpp

    r30636 r30637  
    3535#include "UISession.h"
    3636#include "UIActionsPool.h"
     37#include "UIKeyboardHandler.h"
    3738#include "UIMouseHandler.h"
    3839#include "UIMachineLogic.h"
     
    466467void UIMachineWindow::prepareHandlers()
    467468{
     469    /* Register keyboard-handler: */
     470    machineLogic()->keyboardHandler()->prepareListener(m_uScreenId, this);
     471
    468472    /* Register machine-view in mouse-handler: */
    469473    machineLogic()->mouseHandler()->addMachineView(m_uScreenId, this->machineView());
     
    474478    /* Unregister machine-view from mouse-handler: */
    475479    machineLogic()->mouseHandler()->delMachineView(m_uScreenId);
     480
     481    /* Unregister keyboard-handler: */
     482    machineLogic()->keyboardHandler()->cleanupListener(m_uScreenId);
    476483}
    477484
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.cpp

    r30448 r30637  
    2525#include "VBoxGlobal.h"
    2626#include "VBoxProblemReporter.h"
     27#include "UIKeyboardHandler.h"
    2728#include "UIMouseHandler.h"
    2829#include "UISession.h"
    2930#include "UIMachineLogic.h"
    3031#include "UIMachineView.h"
     32
     33#ifdef Q_WS_X11
     34# include <X11/XKBlib.h>
     35# ifdef KeyPress
     36const int XFocusOut = FocusOut;
     37const int XFocusIn = FocusIn;
     38const int XKeyPress = KeyPress;
     39const int XKeyRelease = KeyRelease;
     40#  undef KeyRelease
     41#  undef KeyPress
     42#  undef FocusOut
     43#  undef FocusIn
     44# endif /* KeyPress */
     45#endif /* Q_WS_X11 */
    3146
    3247#ifdef Q_WS_MAC
     
    211226}
    212227#endif /* Q_WS_MAC */
     228
     229#ifdef Q_WS_X11
     230bool UIMouseHandler::x11EventFilter(XEvent *pEvent, ulong /* uScreenId */)
     231{
     232    /* Check if some system event should be filtered-out.
     233     * Returning 'true' means filtering-out,
     234     * Returning 'false' means passing event to Qt. */
     235    bool fResult = false; /* Pass to Qt by default: */
     236    switch (pEvent->type)
     237    {
     238        /* We have to handle XFocusOut right here as this event is not passed to UIMachineView::event().
     239         * Handling this event is important for releasing the keyboard before the screen saver gets active.
     240         * See public ticket #3894: Apparently this makes problems with newer versions of Qt
     241         * and this hack is probably not necessary anymore. So disable it for Qt >= 4.5.0. */
     242        case XFocusOut:
     243        {
     244            if (uisession()->isRunning())
     245            {
     246                if (VBoxGlobal::qtRTVersion() < ((4 << 16) | (5 << 8) | 0))
     247                    releaseMouse();
     248            }
     249            fResult = false;
     250        }
     251        default:
     252            break;
     253    }
     254    /* Return result: */
     255    return fResult;
     256}
     257#endif /* Q_WS_X11 */
    213258
    214259/* Machine state-change handler: */
     
    483528                     * Only do this if the keyboard/mouse is grabbed
    484529                     * (this is when we have a valid event handler): */
    485                     if (m_views[uScreenId]->isKeyboardGrabbed())
     530                    if (machineLogic()->keyboardHandler()->isKeyboardGrabbed())
    486531                        setMouseCoalescingEnabled(false);
    487532                    break;
     
    545590#ifdef Q_WS_MAC
    546591    /* Simulate the right click on host-key + left-mouse-button: */
    547     if (m_views[uScreenId]->isHostKeyPressed() &&
    548         m_views[uScreenId]->isHostKeyAlone() &&
     592    if (machineLogic()->keyboardHandler()->isHostKeyPressed() &&
     593        machineLogic()->keyboardHandler()->isHostKeyAlone() &&
    549594        iMouseButtonsState == KMouseButtonState_LeftButton)
    550595        iMouseButtonsState = KMouseButtonState_RightButton;
     
    744789                        qApp->processEvents();
    745790#endif
    746                         /* Actually that will be a call to keyboard-handler, not no machine-view,
    747                          * but now keyboard-handler is not implemented yet. */
    748                         m_views[uScreenId]->captureKbd(true);
    749 
     791                        machineLogic()->keyboardHandler()->captureKeyboard(uScreenId);
    750792                        captureMouse(uScreenId);
    751793                    }
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIMouseHandler.h

    r30410 r30637  
    3636class UIMachineLogic;
    3737class UIMachineView;
     38#ifdef Q_WS_X11
     39typedef union  _XEvent XEvent;
     40#endif /* Q_WS_X11 */
    3841
    3942/* Delegate to control VM mouse functionality: */
     
    6972    void setMouseCoalescingEnabled(bool fOn);
    7073#endif /* Q_WS_MAC */
     74
     75#ifdef Q_WS_X11
     76    bool x11EventFilter(XEvent *pEvent, ulong uScreenId);
     77#endif /* Q_WS_X11 */
    7178
    7279signals:
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIKeyboardHandlerFullscreen.cpp

    r30551 r30637  
    33 *
    44 * VBox frontends: Qt GUI ("VirtualBox"):
    5  * UIMachineViewFullscreen class implementation
     5 * UIKeyboardHandlerFullscreen class implementation
    66 */
    77
     
    1919
    2020/* Global includes */
    21 #include <QApplication>
    22 #include <QDesktopWidget>
    23 #include <QMainWindow>
     21#include <QKeyEvent>
    2422#include <QTimer>
    25 #ifdef Q_WS_MAC
    26 #include <QMenuBar>
    27 #endif
    28 #ifdef Q_WS_X11
    29 #include <limits.h>
    30 #endif
     23#include <QWidget>
    3124
    3225/* Local includes */
    33 #include "VBoxGlobal.h"
    34 #include "UISession.h"
    35 #include "UIActionsPool.h"
    36 #include "UIMachineLogic.h"
     26#include "UIKeyboardHandlerFullscreen.h"
    3727#include "UIMachineWindow.h"
    38 #include "UIFrameBuffer.h"
    39 #include "UIMachineLogicFullscreen.h"
    40 #include "UIMachineViewFullscreen.h"
    4128
    42 UIMachineViewFullscreen::UIMachineViewFullscreen(  UIMachineWindow *pMachineWindow
    43                                                  , ulong uScreenId
    44 #ifdef VBOX_WITH_VIDEOHWACCEL
    45                                                  , bool bAccelerate2DVideo
    46 #endif
    47                                                  )
    48     : UIMachineView(  pMachineWindow
    49                     , uScreenId
    50 #ifdef VBOX_WITH_VIDEOHWACCEL
    51                     , bAccelerate2DVideo
    52 #endif
    53                     )
    54     , m_bIsGuestAutoresizeEnabled(pMachineWindow->machineLogic()->actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize)->isChecked())
    55     , m_fShouldWeDoResize(false)
    56     , m_pSyncBlocker(0)
     29/* Fullscreen keyboard-handler constructor: */
     30UIKeyboardHandlerFullscreen::UIKeyboardHandlerFullscreen(UIMachineLogic* pMachineLogic)
     31    : UIKeyboardHandler(pMachineLogic)
    5732{
    58     /* Load machine view settings: */
    59     loadMachineViewSettings();
    60 
    61     /* Prepare frame buffer: */
    62     prepareFrameBuffer();
    63 
    64     /* Prepare common things: */
    65     prepareCommon();
    66 
    67     /* Prepare event-filters: */
    68     prepareFilters();
    69 
    70     /* Prepare console connections: */
    71     prepareConsoleConnections();
    72 
    73     /* Prepare fullscreen: */
    74     prepareFullscreen();
    75 
    76     /* Initialization: */
    77     sltMachineStateChanged();
    7833}
    7934
    80 UIMachineViewFullscreen::~UIMachineViewFullscreen()
     35/* Fullscreen keyboard-handler destructor: */
     36UIKeyboardHandlerFullscreen::~UIKeyboardHandlerFullscreen()
    8137{
    82     /* Cleanup fullscreen: */
    83     cleanupFullscreen();
    84 
    85     /* Cleanup common things: */
    86     cleanupCommon();
    87 
    88     /* Cleanup frame buffer: */
    89     cleanupFrameBuffer();
    9038}
    9139
    92 void UIMachineViewFullscreen::sltPerformGuestResize(const QSize &toSize)
     40/* Event handler for prepared listener(s): */
     41bool UIKeyboardHandlerFullscreen::eventFilter(QObject *pWatchedObject, QEvent *pEvent)
    9342{
    94     if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
     43    /* Check if pWatchedObject object is view: */
     44    if (UIMachineView *pWatchedView = isItListenedView(pWatchedObject))
    9545    {
    96         /* Get machine window: */
    97         QMainWindow *pMachineWindow = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    98                                       qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    99 
    100         /* If this slot is invoked directly then use the passed size otherwise get
    101          * the available size for the guest display. We assume here that centralWidget()
    102          * contains this view only and gives it all available space: */
    103         QSize newSize(toSize.isValid() ? toSize : pMachineWindow ? pMachineWindow->centralWidget()->size() : QSize());
    104         AssertMsg(newSize.isValid(), ("Size should be valid!\n"));
    105 
    106         /* Do not send the same hints as we already have: */
    107         if ((newSize.width() == storedConsoleSize().width()) && (newSize.height() == storedConsoleSize().height()))
    108             return;
    109 
    110         /* We only actually send the hint if either an explicit new size was given
    111          * (e.g. if the request was triggered directly by a console resize event) or
    112          * if no explicit size was specified but a resize is flagged as being needed
    113          * (e.g. the autoresize was just enabled and the console was resized while it was disabled). */
    114         if (toSize.isValid() || m_fShouldWeDoResize)
    115         {
    116             /* Remember the new size: */
    117             storeConsoleSize(newSize.width(), newSize.height());
    118 
    119             /* Send new size-hint to the guest: */
    120             session().GetConsole().GetDisplay().SetVideoModeHint(newSize.width(), newSize.height(), 0, screenId());
    121         }
    122 
    123         /* We had requested resize now, rejecting other accident requests: */
    124         m_fShouldWeDoResize = false;
    125     }
    126 }
    127 
    128 void UIMachineViewFullscreen::sltAdditionsStateChanged()
    129 {
    130     /* Check if we should restrict minimum size: */
    131     maybeRestrictMinimumSize();
    132 
    133     /* Check if we should resize guest to fullscreen, all the
    134      * required features will be tested in sltPerformGuestResize(...): */
    135     if ((int)frameBuffer()->width() != workingArea().size().width() ||
    136         (int)frameBuffer()->height() != workingArea().size().height())
    137         sltPerformGuestResize(workingArea().size());
    138 }
    139 
    140 void UIMachineViewFullscreen::sltDesktopResized()
    141 {
    142     /* If the desktop geometry is set automatically, this will update it: */
    143     calculateDesktopGeometry();
    144 }
    145 
    146 bool UIMachineViewFullscreen::event(QEvent *pEvent)
    147 {
    148     switch (pEvent->type())
    149     {
    150         case VBoxDefs::ResizeEventType:
    151         {
    152             /* Some situations requires framebuffer resize events to be ignored at all,
    153              * leaving machine-window, machine-view and framebuffer sizes preserved: */
    154             if (uisession()->isGuestResizeIgnored())
    155                 return true;
    156 
    157             /* We are starting to perform machine-view resize: */
    158             bool oldIgnoreMainwndResize = isMachineWindowResizeIgnored();
    159             setMachineWindowResizeIgnored(true);
    160 
    161             /* Get guest resize-event: */
    162             UIResizeEvent *pResizeEvent = static_cast<UIResizeEvent*>(pEvent);
    163 
    164             /* Perform framebuffer resize: */
    165             frameBuffer()->resizeEvent(pResizeEvent);
    166 
    167             /* Reapply maximum size restriction for machine-view: */
    168             setMaximumSize(sizeHint());
    169 
    170             /* Store the new size to prevent unwanted resize hints being sent back: */
    171             storeConsoleSize(pResizeEvent->width(), pResizeEvent->height());
    172 
    173             /* Perform machine-view resize: */
    174             resize(pResizeEvent->width(), pResizeEvent->height());
    175 
    176             /* Let our toplevel widget calculate its sizeHint properly. */
    177 #ifdef Q_WS_X11
    178             /* We use processEvents rather than sendPostedEvents & set the time out value to max cause on X11 otherwise
    179              * the layout isn't calculated correctly. Dosn't find the bug in Qt, but this could be triggered through
    180              * the async nature of the X11 window event system. */
    181             QCoreApplication::processEvents(QEventLoop::AllEvents, INT_MAX);
    182 #else /* Q_WS_X11 */
    183             QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest);
    184 #endif /* Q_WS_X11 */
    185 
    186 #ifdef Q_WS_MAC
    187             machineLogic()->updateDockIconSize(screenId(), pResizeEvent->width(), pResizeEvent->height());
    188 #endif /* Q_WS_MAC */
    189 
    190             /* May be we have to restrict minimum size? */
    191             maybeRestrictMinimumSize();
    192 
    193             /* Update machine-view sliders: */
    194             updateSliders();
    195 
    196             /* Report to the VM thread that we finished resizing */
    197             session().GetConsole().GetDisplay().ResizeCompleted(screenId());
    198 
    199             /* We are finishing to perform machine-view resize: */
    200             setMachineWindowResizeIgnored(oldIgnoreMainwndResize);
    201 
    202             /* Make sure that all posted signals are processed: */
    203             qApp->processEvents();
    204 
    205             /* We also recalculate the desktop geometry if this is determined
    206              * automatically.  In fact, we only need this on the first resize,
    207              * but it is done every time to keep the code simpler. */
    208             calculateDesktopGeometry();
    209 
    210             /* Emit a signal about guest was resized: */
    211             emit resizeHintDone();
    212 
    213             /* Unlock after processing guest resize event: */
    214             if (m_pSyncBlocker && m_pSyncBlocker->isRunning())
    215                 m_pSyncBlocker->quit();
    216 
    217             return true;
    218         }
    219 
    220         case QEvent::KeyPress:
    221         case QEvent::KeyRelease:
    222         {
    223             /* Get key-event: */
    224             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    225 
    226             /* Process Host+Home for menu popup: */
    227             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    228             {
    229                 if (pKeyEvent->key() == Qt::Key_Home)
    230                     QTimer::singleShot(0, machineWindowWrapper()->machineWindow(), SLOT(sltPopupMainMenu()));
    231                 else
    232                     pEvent->ignore();
    233             }
    234 
    235             break;
    236         }
    237 
    238         default:
    239             break;
    240     }
    241     return UIMachineView::event(pEvent);
    242 }
    243 
    244 bool UIMachineViewFullscreen::eventFilter(QObject *pWatched, QEvent *pEvent)
    245 {
    246     /* Who are we watching? */
    247     QMainWindow *pMainDialog = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    248                                qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    249 
    250     if (pWatched != 0 && pWatched == pMainDialog)
    251     {
     46        /* Get corresponding screen index: */
     47        ulong uScreenId = m_views.key(pWatchedView);
     48        NOREF(uScreenId);
     49        /* Handle view events: */
    25250        switch (pEvent->type())
    25351        {
    254             case QEvent::Resize:
     52            case QEvent::KeyPress:
    25553            {
    256                 /* Send guest-resize hint only if top window resizing to required dimension: */
    257                 QResizeEvent *pResizeEvent = static_cast<QResizeEvent*>(pEvent);
    258                 if (pResizeEvent->size() != workingArea().size())
    259                     break;
    260 
    261                 /* Set the "guest needs to resize" hint.
    262                  * This hint is acted upon when (and only when) the autoresize property is "true": */
    263                 m_fShouldWeDoResize = uisession()->isGuestSupportsGraphics();
    264                 if (m_bIsGuestAutoresizeEnabled && m_fShouldWeDoResize)
    265                     QTimer::singleShot(0, this, SLOT(sltPerformGuestResize()));
     54                /* Get key-event: */
     55                QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
     56                /* Process Host+Home for menu popup: */
     57                if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
     58                {
     59                    if (pKeyEvent->key() == Qt::Key_Home)
     60                    {
     61                        /* Post request to show popup-menu: */
     62                        QTimer::singleShot(0, m_windows[uScreenId]->machineWindow(), SLOT(sltPopupMainMenu()));
     63                        /* Filter-out this event: */
     64                        return true;
     65                    }
     66                }
    26667                break;
    26768            }
     
    27172    }
    27273
    273     return UIMachineView::eventFilter(pWatched, pEvent);
     74    /* Else just propagate to base-class: */
     75    return UIKeyboardHandler::eventFilter(pWatchedObject, pEvent);
    27476}
    27577
    276 void UIMachineViewFullscreen::prepareCommon()
    277 {
    278     /* Base class common settings: */
    279     UIMachineView::prepareCommon();
    280 
    281     /* Setup size-policy: */
    282     setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
    283     /* Maximum size to sizehint: */
    284     setMaximumSize(sizeHint());
    285     /* Minimum size is ignored: */
    286     setMinimumSize(0, 0);
    287     /* No scrollbars: */
    288     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    289     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    290 }
    291 
    292 void UIMachineViewFullscreen::prepareFilters()
    293 {
    294     /* Base class filters: */
    295     UIMachineView::prepareFilters();
    296 
    297 #ifdef Q_WS_MAC // TODO: Is it really needed? See UIMachineViewSeamless::eventFilter(...);
    298     /* Menu bar filter: */
    299     qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->menuBar()->installEventFilter(this);
    300 #endif
    301 }
    302 
    303 void UIMachineViewFullscreen::prepareConnections()
    304 {
    305     connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(sltDesktopResized()));
    306 }
    307 
    308 void UIMachineViewFullscreen::prepareConsoleConnections()
    309 {
    310     /* Base class connections: */
    311     UIMachineView::prepareConsoleConnections();
    312 
    313     /* Guest additions state-change updater: */
    314     connect(uisession(), SIGNAL(sigAdditionsStateChange()), this, SLOT(sltAdditionsStateChanged()));
    315 }
    316 
    317 void UIMachineViewFullscreen::prepareFullscreen()
    318 {
    319     /* Create sync-blocker: */
    320     m_pSyncBlocker = new UIMachineViewBlocker;
    321 }
    322 
    323 void UIMachineViewFullscreen::cleanupFullscreen()
    324 {
    325     /* If machine still running: */
    326     if (uisession()->isRunning())
    327     {
    328         /* And guest supports advanced graphics management which is enabled: */
    329         if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
    330         {
    331             /* Rollback seamless frame-buffer size to normal: */
    332             machineWindowWrapper()->machineWindow()->hide();
    333             sltPerformGuestResize(guestSizeHint());
    334             m_pSyncBlocker->exec();
    335 
    336             /* Request to delete sync-blocker: */
    337             m_pSyncBlocker->deleteLater();
    338         }
    339     }
    340 }
    341 
    342 void UIMachineViewFullscreen::setGuestAutoresizeEnabled(bool fEnabled)
    343 {
    344     if (m_bIsGuestAutoresizeEnabled != fEnabled)
    345     {
    346         m_bIsGuestAutoresizeEnabled = fEnabled;
    347 
    348         maybeRestrictMinimumSize();
    349 
    350         sltPerformGuestResize();
    351     }
    352 }
    353 
    354 QRect UIMachineViewFullscreen::workingArea()
    355 {
    356     /* Get corresponding screen: */
    357     int iScreen = static_cast<UIMachineLogicFullscreen*>(machineLogic())->hostScreenForGuestScreen(screenId());
    358     /* Return available geometry for that screen: */
    359     return QApplication::desktop()->screenGeometry(iScreen);
    360 }
    361 
    362 void UIMachineViewFullscreen::calculateDesktopGeometry()
    363 {
    364     /* This method should not get called until we have initially set up the desktop geometry type: */
    365     Assert((desktopGeometryType() != DesktopGeo_Invalid));
    366     /* If we are not doing automatic geometry calculation then there is nothing to do: */
    367     if (desktopGeometryType() == DesktopGeo_Automatic)
    368         m_desktopGeometry = workingArea().size();
    369 }
    370 
    371 void UIMachineViewFullscreen::maybeRestrictMinimumSize()
    372 {
    373     /* Sets the minimum size restriction depending on the auto-resize feature state and the current rendering mode.
    374      * Currently, the restriction is set only in SDL mode and only when the auto-resize feature is inactive.
    375      * We need to do that because we cannot correctly draw in a scrolled window in SDL mode.
    376      * In all other modes, or when auto-resize is in force, this function does nothing. */
    377     if (vboxGlobal().vmRenderMode() == VBoxDefs::SDLMode)
    378     {
    379         if (!uisession()->isGuestSupportsGraphics() || !m_bIsGuestAutoresizeEnabled)
    380             setMinimumSize(sizeHint());
    381         else
    382             setMinimumSize(0, 0);
    383     }
    384 }
    385 
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIKeyboardHandlerFullscreen.h

    r30551 r30637  
    22 *
    33 * VBox frontends: Qt GUI ("VirtualBox"):
    4  * UIMachineViewFullscreen class declaration
     4 * UIKeyboardHandlerFullscreen class declaration
    55 */
    66
     
    1717 */
    1818
    19 #ifndef ___UIMachineViewFullscreen_h___
    20 #define ___UIMachineViewFullscreen_h___
     19#ifndef ___UIKeyboardHandlerFullscreen_h___
     20#define ___UIKeyboardHandlerFullscreen_h___
    2121
    2222/* Local includes */
    23 #include "UIMachineView.h"
     23#include "UIKeyboardHandler.h"
    2424
    25 class UIMachineViewFullscreen : public UIMachineView
     25class UIKeyboardHandlerFullscreen : public UIKeyboardHandler
    2626{
    2727    Q_OBJECT;
     
    2929protected:
    3030
    31     /* Fullscreen machine-view constructor: */
    32     UIMachineViewFullscreen(  UIMachineWindow *pMachineWindow
    33                             , ulong uScreenId
    34 #ifdef VBOX_WITH_VIDEOHWACCEL
    35                             , bool bAccelerate2DVideo
    36 #endif
    37     );
    38     /* Fullscreen machine-view destructor: */
    39     virtual ~UIMachineViewFullscreen();
    40 
    41 private slots:
    42 
    43     /* Slot to perform guest resize: */
    44     void sltPerformGuestResize(const QSize &aSize = QSize());
    45 
    46     /* Console callback handlers: */
    47     void sltAdditionsStateChanged();
    48 
    49     /* Watch dog for desktop resizes: */
    50     void sltDesktopResized();
     31    /* Fullscreen keyboard-handler constructor/destructor: */
     32    UIKeyboardHandlerFullscreen(UIMachineLogic *pMachineLogic);
     33    virtual ~UIKeyboardHandlerFullscreen();
    5134
    5235private:
    5336
    5437    /* Event handlers: */
    55     bool event(QEvent *pEvent);
    5638    bool eventFilter(QObject *pWatched, QEvent *pEvent);
    5739
    58     /* Prepare routines: */
    59     void prepareCommon();
    60     void prepareFilters();
    61     void prepareConnections();
    62     void prepareConsoleConnections();
    63     void prepareFullscreen();
    64 
    65     /* Cleanup routines: */
    66     void cleanupFullscreen();
    67     //void cleanupConsoleConnections() {}
    68     //void cleanupConnections() {}
    69     //void cleanupFilters() {}
    70     //void cleanupCommon() {}
    71 
    72     /* Private setters: */
    73     void setGuestAutoresizeEnabled(bool bEnabled);
    74 
    75     /* Private helpers: */
    76     void normalizeGeometry(bool /* fAdjustPosition */) {}
    77     QRect workingArea();
    78     void calculateDesktopGeometry();
    79     void maybeRestrictMinimumSize();
    80 
    81     /* Private variables: */
    82     bool m_bIsGuestAutoresizeEnabled : 1;
    83     bool m_fShouldWeDoResize : 1;
    84     UIMachineViewBlocker *m_pSyncBlocker;
    85 
    8640    /* Friend classes: */
    87     friend class UIMachineView;
     41    friend class UIKeyboardHandler;
    8842};
    8943
    90 #endif // !___UIMachineViewFullscreen_h___
     44#endif // !___UIKeyboardHandlerFullscreen_h___
    9145
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp

    r30544 r30637  
    8383    cleanupFullscreen();
    8484
    85     /* Cleanup common things: */
    86     cleanupCommon();
    87 
    8885    /* Cleanup frame buffer: */
    8986    cleanupFrameBuffer();
     
    216213
    217214            return true;
    218         }
    219 
    220         case QEvent::KeyPress:
    221         case QEvent::KeyRelease:
    222         {
    223             /* Get key-event: */
    224             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    225 
    226             /* Process Host+Home for menu popup: */
    227             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    228             {
    229                 if (pKeyEvent->key() == Qt::Key_Home)
    230                     QTimer::singleShot(0, machineWindowWrapper()->machineWindow(), SLOT(sltPopupMainMenu()));
    231                 else
    232                     pEvent->ignore();
    233             }
    234 
    235             break;
    236215        }
    237216
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIKeyboardHandlerNormal.cpp

    r30551 r30637  
    33 *
    44 * VBox frontends: Qt GUI ("VirtualBox"):
    5  * UIMachineViewNormal class implementation
     5 * UIKeyboardHandlerNormal class implementation
    66 */
    77
     
    1919
    2020/* Global includes */
    21 #include <QApplication>
    22 #include <QDesktopWidget>
    2321#include <QMainWindow>
    2422#include <QMenuBar>
    25 #include <QScrollBar>
    26 #include <QTimer>
     23#include <QKeyEvent>
    2724
    2825/* Local includes */
    29 #include "VBoxGlobal.h"
    30 #include "UISession.h"
    31 #include "UIActionsPool.h"
    32 #include "UIMachineLogic.h"
     26#include "UIKeyboardHandlerNormal.h"
    3327#include "UIMachineWindow.h"
    34 #include "UIFrameBuffer.h"
    35 #include "UIMachineViewNormal.h"
    3628
    37 UIMachineViewNormal::UIMachineViewNormal(  UIMachineWindow *pMachineWindow
    38                                          , ulong uScreenId
    39 #ifdef VBOX_WITH_VIDEOHWACCEL
    40                                          , bool bAccelerate2DVideo
    41 #endif
    42                                          )
    43     : UIMachineView(  pMachineWindow
    44                     , uScreenId
    45 #ifdef VBOX_WITH_VIDEOHWACCEL
    46                     , bAccelerate2DVideo
    47 #endif
    48                     )
    49     , m_bIsGuestAutoresizeEnabled(pMachineWindow->machineLogic()->actionsPool()->action(UIActionIndex_Toggle_GuestAutoresize)->isChecked())
    50     , m_fShouldWeDoResize(false)
     29/* Fullscreen keyboard-handler constructor: */
     30UIKeyboardHandlerNormal::UIKeyboardHandlerNormal(UIMachineLogic* pMachineLogic)
     31    : UIKeyboardHandler(pMachineLogic)
    5132{
    52     /* Load machine view settings: */
    53     loadMachineViewSettings();
    54 
    55     /* Prepare frame buffer: */
    56     prepareFrameBuffer();
    57 
    58     /* Prepare common things: */
    59     prepareCommon();
    60 
    61     /* Prepare event-filters: */
    62     prepareFilters();
    63 
    64     /* Prepare connections: */
    65     prepareConnections();
    66 
    67     /* Prepare console connections: */
    68     prepareConsoleConnections();
    69 
    70     /* Initialization: */
    71     sltMachineStateChanged();
    72     sltAdditionsStateChanged();
    7333}
    7434
    75 UIMachineViewNormal::~UIMachineViewNormal()
     35/* Fullscreen keyboard-handler destructor: */
     36UIKeyboardHandlerNormal::~UIKeyboardHandlerNormal()
    7637{
    77     /* Save machine view settings: */
    78     saveMachineViewSettings();
    79 
    80     /* Cleanup common things: */
    81     cleanupCommon();
    82 
    83     /* Cleanup frame buffer: */
    84     cleanupFrameBuffer();
    8538}
    8639
    87 void UIMachineViewNormal::sltPerformGuestResize(const QSize &toSize)
     40/* Event handler for prepared listener(s): */
     41bool UIKeyboardHandlerNormal::eventFilter(QObject *pWatchedObject, QEvent *pEvent)
    8842{
    89     if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
     43    /* Check if pWatchedObject object is view: */
     44    if (UIMachineView *pWatchedView = isItListenedView(pWatchedObject))
    9045    {
    91         /* Get machine window: */
    92         QMainWindow *pMachineWindow = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    93                                       qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    94 
    95         /* If this slot is invoked directly then use the passed size otherwise get
    96          * the available size for the guest display. We assume here that centralWidget()
    97          * contains this view only and gives it all available space: */
    98         QSize newSize(toSize.isValid() ? toSize : pMachineWindow ? pMachineWindow->centralWidget()->size() : QSize());
    99         AssertMsg(newSize.isValid(), ("Size should be valid!\n"));
    100 
    101         /* Do not send the same hints as we already have: */
    102         if ((newSize.width() == storedConsoleSize().width()) && (newSize.height() == storedConsoleSize().height()))
    103             return;
    104 
    105         /* We only actually send the hint if either an explicit new size was given
    106          * (e.g. if the request was triggered directly by a console resize event) or
    107          * if no explicit size was specified but a resize is flagged as being needed
    108          * (e.g. the autoresize was just enabled and the console was resized while it was disabled). */
    109         if (toSize.isValid() || m_fShouldWeDoResize)
     46        /* Get corresponding screen index: */
     47        ulong uScreenId = m_views.key(pWatchedView);
     48        NOREF(uScreenId);
     49        /* Handle view events: */
     50        switch (pEvent->type())
    11051        {
    111             /* Remember the new size: */
    112             storeConsoleSize(newSize.width(), newSize.height());
    113 
    114             /* Send new size-hint to the guest: */
    115             session().GetConsole().GetDisplay().SetVideoModeHint(newSize.width(), newSize.height(), 0, screenId());
    116         }
    117 
    118         /* We had requested resize now, rejecting other accident requests: */
    119         m_fShouldWeDoResize = false;
    120     }
    121 }
    122 
    123 void UIMachineViewNormal::sltAdditionsStateChanged()
    124 {
    125     /* Check if we should restrict minimum size: */
    126     maybeRestrictMinimumSize();
    127 }
    128 
    129 void UIMachineViewNormal::sltDesktopResized()
    130 {
    131     /* If the desktop geometry is set automatically, this will update it: */
    132     calculateDesktopGeometry();
    133 }
    134 
    135 bool UIMachineViewNormal::event(QEvent *pEvent)
    136 {
    137     switch (pEvent->type())
    138     {
    139         case VBoxDefs::ResizeEventType:
    140         {
    141             /* Some situations require framebuffer resize events to be ignored at all,
    142              * leaving machine-window, machine-view and framebuffer sizes preserved: */
    143             if (uisession()->isGuestResizeIgnored())
    144                 return true;
    145 
    146             /* We are starting to perform machine-view resize: */
    147             bool oldIgnoreMainwndResize = isMachineWindowResizeIgnored();
    148             setMachineWindowResizeIgnored(true);
    149 
    150             /* Get guest resize-event: */
    151             UIResizeEvent *pResizeEvent = static_cast<UIResizeEvent*>(pEvent);
    152 
    153             /* Perform framebuffer resize: */
    154             frameBuffer()->resizeEvent(pResizeEvent);
    155 
    156             /* Reapply maximum size restriction for machine-view: */
    157             setMaximumSize(sizeHint());
    158 
    159             /* Store the new size to prevent unwanted resize hints being sent back: */
    160             storeConsoleSize(pResizeEvent->width(), pResizeEvent->height());
    161 
    162             /* Perform machine-view resize: */
    163             resize(pResizeEvent->width(), pResizeEvent->height());
    164 
    165             /* Let our toplevel widget calculate its sizeHint properly. */
    166 #ifdef Q_WS_X11
    167             /* We use processEvents rather than sendPostedEvents & set the time out value to max cause on X11 otherwise
    168              * the layout isn't calculated correctly. Dosn't find the bug in Qt, but this could be triggered through
    169              * the async nature of the X11 window event system. */
    170             QCoreApplication::processEvents(QEventLoop::AllEvents, INT_MAX);
    171 #else /* Q_WS_X11 */
    172             QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest);
    173 #endif /* Q_WS_X11 */
    174 
    175 #ifdef Q_WS_MAC
    176             machineLogic()->updateDockIconSize(screenId(), pResizeEvent->width(), pResizeEvent->height());
    177 #endif /* Q_WS_MAC */
    178 
    179             /* May be we have to restrict minimum size? */
    180             maybeRestrictMinimumSize();
    181 
    182             /* Update machine-view sliders: */
    183             updateSliders();
    184 
    185             /* Normalize geometry: */
    186             normalizeGeometry(true /* adjustPosition */);
    187 
    188             /* Report to the VM thread that we finished resizing */
    189             session().GetConsole().GetDisplay().ResizeCompleted(screenId());
    190 
    191             /* We are finishing to perform machine-view resize: */
    192             setMachineWindowResizeIgnored(oldIgnoreMainwndResize);
    193 
    194             /* Make sure that all posted signals are processed: */
    195             qApp->processEvents();
    196 
    197             /* We also recalculate the desktop geometry if this is determined
    198              * automatically.  In fact, we only need this on the first resize,
    199              * but it is done every time to keep the code simpler. */
    200             calculateDesktopGeometry();
    201 
    202             /* Emit a signal about guest was resized: */
    203             emit resizeHintDone();
    204 
    205             return true;
    206         }
    207 
    20852#ifndef Q_WS_MAC
    209         /* We don't want this on the Mac, cause there the menu bar isn't within the
    210          * window and popping up a menu there looks really ugly. */
    211         case QEvent::KeyPress:
    212         case QEvent::KeyRelease:
    213         {
    214             /* Get key-event: */
    215             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    216 
    217             /* Process Host+Home as menu-bar activator: */
    218             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
     53            /* We don't want this on the Mac, cause there the menu-bar isn't within the
     54             * window and popping up a menu there looks really ugly. */
     55            case QEvent::KeyPress:
    21956            {
    220                 if (pKeyEvent->key() == Qt::Key_Home)
     57                /* Get key-event: */
     58                QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
     59                /* Process Host+Home as menu-bar activator: */
     60                if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    22161                {
    222                     /* Trying to get menu-bar: */
    223                     QMenuBar *pMenuBar = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    224                                          qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->menuBar() : 0;
    225 
    226                     /* If menu-bar is present and have actions: */
    227                     if (pMenuBar && !pMenuBar->actions().isEmpty())
     62                    if (pKeyEvent->key() == Qt::Key_Home)
    22863                    {
    229                         /* If 'active' action is NOT chosen: */
    230                         if (!pMenuBar->activeAction())
    231                             /* Set first menu-bar action as 'active': */
    232                             pMenuBar->setActiveAction(pMenuBar->actions()[0]);
    233 
    234                         /* If 'active' action is chosen: */
    235                         if (pMenuBar->activeAction())
     64                        /* Trying to get menu-bar: */
     65                        QMenuBar *pMenuBar = qobject_cast<QMainWindow*>(m_windows[uScreenId]->machineWindow())->menuBar();
     66                        /* If menu-bar is present and have actions: */
     67                        if (pMenuBar && !pMenuBar->actions().isEmpty())
    23668                        {
    237                             /* Activate 'active' menu-bar action: */
    238                             pMenuBar->activeAction()->activate(QAction::Trigger);
    239 
     69                            /* If 'active' action is NOT chosen: */
     70                            if (!pMenuBar->activeAction())
     71                                /* Set first menu-bar action as 'active': */
     72                                pMenuBar->setActiveAction(pMenuBar->actions()[0]);
     73                            /* If 'active' action is chosen: */
     74                            if (pMenuBar->activeAction())
     75                            {
     76                                /* Activate 'active' menu-bar action: */
     77                                pMenuBar->activeAction()->activate(QAction::Trigger);
    24078#ifdef Q_WS_WIN
    241                             /* Windows host needs separate 'focus set'
    242                              * to let menubar operate while popped up: */
    243                             pMenuBar->setFocus();
     79                                /* Windows host needs separate 'focus set'
     80                                 * to let menubar operate while popped up: */
     81                                pMenuBar->setFocus();
    24482#endif /* Q_WS_WIN */
    245 
    246                             /* Accept this event: */
    247                             pEvent->accept();
    248                             return true;
     83                                /* Filter-out this event: */
     84                                return true;
     85                            }
    24986                        }
    25087                    }
    25188                }
    252                 else
    253                     pEvent->ignore();
    254             }
    255 
    256             break;
    257         }
    258 #endif /* !Q_WS_MAC */
    259 
    260         default:
    261             break;
    262     }
    263     return UIMachineView::event(pEvent);
    264 }
    265 
    266 bool UIMachineViewNormal::eventFilter(QObject *pWatched, QEvent *pEvent)
    267 {
    268     /* Who are we watching? */
    269     QMainWindow *pMainDialog = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    270                                qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    271 #ifdef Q_WS_WIN
    272     QMenuBar *pMenuBar = pMainDialog ? pMainDialog->menuBar() : 0;
    273 #endif /* Q_WS_WIN */
    274 
    275     if (pWatched != 0 && pWatched == pMainDialog)
    276     {
    277         switch (pEvent->type())
    278         {
    279             case QEvent::Resize:
    280             {
    281                 /* Set the "guest needs to resize" hint.
    282                  * This hint is acted upon when (and only when) the autoresize property is "true": */
    283                 m_fShouldWeDoResize = uisession()->isGuestSupportsGraphics();
    284                 if (!isMachineWindowResizeIgnored() && m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
    285                     QTimer::singleShot(300, this, SLOT(sltPerformGuestResize()));
    28689                break;
    28790            }
    288 #if defined (Q_WS_WIN32)
    289 # if defined (VBOX_GUI_USE_DDRAW)
    290             case QEvent::Move:
    291             {
    292                 /* Notification from our parent that it has moved. We need this in order
    293                  * to possibly adjust the direct screen blitting: */
    294                 if (frameBuffer())
    295                     frameBuffer()->moveEvent(static_cast<QMoveEvent*>(pEvent));
    296                 break;
    297             }
    298 # endif /* defined (VBOX_GUI_USE_DDRAW) */
    299 #endif /* defined (Q_WS_WIN32) */
     91#endif /* !Q_WS_MAC */
    30092            default:
    30193                break;
     
    30395    }
    30496
    305 #ifdef Q_WS_WIN
    306     else if (pWatched != 0 && pWatched == pMenuBar)
    307     {
    308         /* Due to windows host uses separate 'focus set' to let menubar to
    309          * operate while popped up (see UIMachineViewNormal::event() for details),
    310          * it also requires backward processing: */
    311         switch (pEvent->type())
    312         {
    313             /* If menubar gets the focus while not popped up => give it back: */
    314             case QEvent::FocusIn:
    315             {
    316                 if (!QApplication::activePopupWidget())
    317                     setFocus();
    318             }
    319             default:
    320                 break;
    321         }
    322     }
    323 #endif /* Q_WS_WIN */
    324 
    325     return UIMachineView::eventFilter(pWatched, pEvent);
     97    /* Else just propagate to base-class: */
     98    return UIKeyboardHandler::eventFilter(pWatchedObject, pEvent);
    32699}
    327100
    328 void UIMachineViewNormal::prepareCommon()
    329 {
    330     /* Base class common settings: */
    331     UIMachineView::prepareCommon();
    332 
    333     /* Setup size-policy: */
    334     setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
    335     /* Maximum size to sizehint: */
    336     setMaximumSize(sizeHint());
    337 }
    338 
    339 void UIMachineViewNormal::prepareFilters()
    340 {
    341     /* Base class filters: */
    342     UIMachineView::prepareFilters();
    343 
    344     /* Menu bar filters: */
    345     qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->menuBar()->installEventFilter(this);
    346 }
    347 
    348 void UIMachineViewNormal::prepareConnections()
    349 {
    350     connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(sltDesktopResized()));
    351 }
    352 
    353 void UIMachineViewNormal::prepareConsoleConnections()
    354 {
    355     /* Base class connections: */
    356     UIMachineView::prepareConsoleConnections();
    357 
    358     /* Guest additions state-change updater: */
    359     connect(uisession(), SIGNAL(sigAdditionsStateChange()), this, SLOT(sltAdditionsStateChanged()));
    360 }
    361 
    362 void UIMachineViewNormal::saveMachineViewSettings()
    363 {
    364     /* Store guest size hint: */
    365     storeGuestSizeHint(QSize(frameBuffer()->width(), frameBuffer()->height()));
    366 }
    367 
    368 void UIMachineViewNormal::setGuestAutoresizeEnabled(bool fEnabled)
    369 {
    370     if (m_bIsGuestAutoresizeEnabled != fEnabled)
    371     {
    372         m_bIsGuestAutoresizeEnabled = fEnabled;
    373 
    374         maybeRestrictMinimumSize();
    375 
    376         if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
    377             sltPerformGuestResize();
    378     }
    379 }
    380 
    381 void UIMachineViewNormal::normalizeGeometry(bool bAdjustPosition)
    382 {
    383     QWidget *pTopLevelWidget = window();
    384 
    385     /* Make no normalizeGeometry in case we are in manual resize mode or main window is maximized: */
    386     if (pTopLevelWidget->isMaximized())
    387         return;
    388 
    389     /* Calculate client window offsets: */
    390     QRect frameGeo = pTopLevelWidget->frameGeometry();
    391     QRect geo = pTopLevelWidget->geometry();
    392     int dl = geo.left() - frameGeo.left();
    393     int dt = geo.top() - frameGeo.top();
    394     int dr = frameGeo.right() - geo.right();
    395     int db = frameGeo.bottom() - geo.bottom();
    396 
    397     /* Get the best size w/o scroll bars: */
    398     QSize s = pTopLevelWidget->sizeHint();
    399 
    400     /* Resize the frame to fit the contents: */
    401     s -= pTopLevelWidget->size();
    402     frameGeo.setRight(frameGeo.right() + s.width());
    403     frameGeo.setBottom(frameGeo.bottom() + s.height());
    404 
    405     if (bAdjustPosition)
    406     {
    407         QRegion availableGeo;
    408         QDesktopWidget *dwt = QApplication::desktop();
    409         if (dwt->isVirtualDesktop())
    410             /* Compose complex available region */
    411             for (int i = 0; i < dwt->numScreens(); ++ i)
    412                 availableGeo += dwt->availableGeometry(i);
    413         else
    414             /* Get just a simple available rectangle */
    415             availableGeo = dwt->availableGeometry(pTopLevelWidget->pos());
    416 
    417         frameGeo = VBoxGlobal::normalizeGeometry(frameGeo, availableGeo, vboxGlobal().vmRenderMode() != VBoxDefs::SDLMode /* can resize? */);
    418     }
    419 
    420 #if 0
    421     /* Center the frame on the desktop: */
    422     frameGeo.moveCenter(availableGeo.center());
    423 #endif
    424 
    425     /* Finally, set the frame geometry */
    426     pTopLevelWidget->setGeometry(frameGeo.left() + dl, frameGeo.top() + dt, frameGeo.width() - dl - dr, frameGeo.height() - dt - db);
    427 }
    428 
    429 QRect UIMachineViewNormal::workingArea()
    430 {
    431     return QApplication::desktop()->availableGeometry(this);
    432 }
    433 
    434 void UIMachineViewNormal::calculateDesktopGeometry()
    435 {
    436     /* This method should not get called until we have initially set up the desktop geometry type: */
    437     Assert((desktopGeometryType() != DesktopGeo_Invalid));
    438     /* If we are not doing automatic geometry calculation then there is nothing to do: */
    439     if (desktopGeometryType() == DesktopGeo_Automatic)
    440     {
    441         /* The area taken up by the machine window on the desktop,
    442          * including window frame, title, menu bar and status bar: */
    443         QRect windowGeo = machineWindowWrapper()->machineWindow()->frameGeometry();
    444         /* The area taken up by the machine central widget, so excluding all decorations: */
    445         QRect centralWidgetGeo = static_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->centralWidget()->geometry();
    446         /* To work out how big we can make the console window while still fitting on the desktop,
    447          * we calculate workingArea() - (windowGeo - centralWidgetGeo).
    448          * This works because the difference between machine window and machine central widget
    449          * (or at least its width and height) is a constant. */
    450         m_desktopGeometry = QSize(workingArea().width() - (windowGeo.width() - centralWidgetGeo.width()),
    451                                   workingArea().height() - (windowGeo.height() - centralWidgetGeo.height()));
    452     }
    453 }
    454 
    455 void UIMachineViewNormal::maybeRestrictMinimumSize()
    456 {
    457     /* Sets the minimum size restriction depending on the auto-resize feature state and the current rendering mode.
    458      * Currently, the restriction is set only in SDL mode and only when the auto-resize feature is inactive.
    459      * We need to do that because we cannot correctly draw in a scrolled window in SDL mode.
    460      * In all other modes, or when auto-resize is in force, this function does nothing. */
    461     if (vboxGlobal().vmRenderMode() == VBoxDefs::SDLMode)
    462     {
    463         if (!uisession()->isGuestSupportsGraphics() || !m_bIsGuestAutoresizeEnabled)
    464             setMinimumSize(sizeHint());
    465         else
    466             setMinimumSize(0, 0);
    467     }
    468 }
    469 
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIKeyboardHandlerNormal.h

    r30551 r30637  
    22 *
    33 * VBox frontends: Qt GUI ("VirtualBox"):
    4  * UIMachineViewNormal class declaration
     4 * UIKeyboardHandlerNormal class declaration
    55 */
    66
     
    1717 */
    1818
    19 #ifndef ___UIMachineViewNormal_h___
    20 #define ___UIMachineViewNormal_h___
     19#ifndef ___UIKeyboardHandlerNormal_h___
     20#define ___UIKeyboardHandlerNormal_h___
    2121
    2222/* Local includes */
    23 #include "UIMachineView.h"
     23#include "UIKeyboardHandler.h"
    2424
    25 class UIMachineViewNormal : public UIMachineView
     25class UIKeyboardHandlerNormal : public UIKeyboardHandler
    2626{
    2727    Q_OBJECT;
     
    2929protected:
    3030
    31     /* Normal machine-view constructor: */
    32     UIMachineViewNormal(  UIMachineWindow *pMachineWindow
    33                         , ulong uScreenId
    34 #ifdef VBOX_WITH_VIDEOHWACCEL
    35                         , bool bAccelerate2DVideo
    36 #endif
    37     );
    38     /* Normal machine-view destructor: */
    39     virtual ~UIMachineViewNormal();
    40 
    41 private slots:
    42 
    43     /* Slot to perform guest resize: */
    44     void sltPerformGuestResize(const QSize &size = QSize());
    45 
    46     /* Console callback handlers: */
    47     void sltAdditionsStateChanged();
    48 
    49     /* Watch dog for desktop resizes: */
    50     void sltDesktopResized();
    51 
    52 #ifdef Q_WS_X11
    53     /* Slot to perform synchronized geometry normalization.
    54      * Currently its only required under X11 as of its async nature: */
    55     virtual void sltNormalizeGeometry() { normalizeGeometry(true); }
    56 #endif /* Q_WS_X11 */
     31    /* Fullscreen keyboard-handler constructor/destructor: */
     32    UIKeyboardHandlerNormal(UIMachineLogic *pMachineLogic);
     33    virtual ~UIKeyboardHandlerNormal();
    5734
    5835private:
    5936
    6037    /* Event handlers: */
    61     bool event(QEvent *pEvent);
    6238    bool eventFilter(QObject *pWatched, QEvent *pEvent);
    6339
    64     /* Prepare helpers: */
    65     void prepareCommon();
    66     void prepareFilters();
    67     void prepareConnections();
    68     void prepareConsoleConnections();
    69     //void loadMachineViewSettings();
    70 
    71     /* Cleanup helpers: */
    72     void saveMachineViewSettings();
    73     //void cleanupConsoleConnections() {}
    74     //void prepareConnections() {}
    75     //void cleanupFilters() {}
    76     //void cleanupCommon() {}
    77 
    78     /* Hidden setters: */
    79     void setGuestAutoresizeEnabled(bool bEnabled);
    80 
    81     /* Private helpers: */
    82     void normalizeGeometry(bool fAdjustPosition);
    83     QRect workingArea();
    84     void calculateDesktopGeometry();
    85     void maybeRestrictMinimumSize();
    86 
    87     /* Private members: */
    88     bool m_bIsGuestAutoresizeEnabled : 1;
    89     bool m_fShouldWeDoResize : 1;
    90 
    9140    /* Friend classes: */
    92     friend class UIMachineView;
     41    friend class UIKeyboardHandler;
    9342};
    9443
    95 #endif // !___UIMachineViewNormal_h___
     44#endif // !___UIKeyboardHandlerNormal_h___
    9645
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp

    r30544 r30637  
    7878    saveMachineViewSettings();
    7979
    80     /* Cleanup common things: */
    81     cleanupCommon();
    82 
    8380    /* Cleanup frame buffer: */
    8481    cleanupFrameBuffer();
     
    205202            return true;
    206203        }
    207 
    208 #ifndef Q_WS_MAC
    209         /* We don't want this on the Mac, cause there the menu bar isn't within the
    210          * window and popping up a menu there looks really ugly. */
    211         case QEvent::KeyPress:
    212         case QEvent::KeyRelease:
    213         {
    214             /* Get key-event: */
    215             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    216 
    217             /* Process Host+Home as menu-bar activator: */
    218             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    219             {
    220                 if (pKeyEvent->key() == Qt::Key_Home)
    221                 {
    222                     /* Trying to get menu-bar: */
    223                     QMenuBar *pMenuBar = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    224                                          qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->menuBar() : 0;
    225 
    226                     /* If menu-bar is present and have actions: */
    227                     if (pMenuBar && !pMenuBar->actions().isEmpty())
    228                     {
    229                         /* If 'active' action is NOT chosen: */
    230                         if (!pMenuBar->activeAction())
    231                             /* Set first menu-bar action as 'active': */
    232                             pMenuBar->setActiveAction(pMenuBar->actions()[0]);
    233 
    234                         /* If 'active' action is chosen: */
    235                         if (pMenuBar->activeAction())
    236                         {
    237                             /* Activate 'active' menu-bar action: */
    238                             pMenuBar->activeAction()->activate(QAction::Trigger);
    239 
    240 #ifdef Q_WS_WIN
    241                             /* Windows host needs separate 'focus set'
    242                              * to let menubar operate while popped up: */
    243                             pMenuBar->setFocus();
    244 #endif /* Q_WS_WIN */
    245 
    246                             /* Accept this event: */
    247                             pEvent->accept();
    248                             return true;
    249                         }
    250                     }
    251                 }
    252                 else
    253                     pEvent->ignore();
    254             }
    255 
    256             break;
    257         }
    258 #endif /* !Q_WS_MAC */
    259204
    260205        default:
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineWindowNormal.cpp

    r30546 r30637  
    3232#include "UIActionsPool.h"
    3333#include "UIIndicatorsPool.h"
     34#include "UIKeyboardHandler.h"
    3435#include "UIMouseHandler.h"
    3536#include "UIMachineLogic.h"
     
    494495    {
    495496        /* Keyboard state-change updater: */
    496         connect(machineView(), SIGNAL(keyboardStateChanged(int)), indicatorsPool()->indicator(UIIndicatorIndex_Hostkey), SLOT(setState(int)));
     497        connect(machineLogic()->keyboardHandler(), SIGNAL(keyboardStateChanged(int)), indicatorsPool()->indicator(UIIndicatorIndex_Hostkey), SLOT(setState(int)));
    497498
    498499        /* Mouse state-change updater: */
     
    500501
    501502        /* Early initialize required connections: */
    502         indicatorsPool()->indicator(UIIndicatorIndex_Hostkey)->setState(machineView()->keyboardState());
     503        indicatorsPool()->indicator(UIIndicatorIndex_Hostkey)->setState(machineLogic()->keyboardHandler()->keyboardState());
    503504        indicatorsPool()->indicator(UIIndicatorIndex_Mouse)->setState(machineLogic()->mouseHandler()->mouseState());
    504505    }
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIKeyboardHandlerSeamless.cpp

    r30551 r30637  
    33 *
    44 * VBox frontends: Qt GUI ("VirtualBox"):
    5  * UIMachineViewSeamless class implementation
     5 * UIKeyboardHandlerSeamless class implementation
    66 */
    77
     
    1919
    2020/* Global includes */
    21 #include <QApplication>
    22 #include <QDesktopWidget>
    23 #include <QMainWindow>
     21#include <QKeyEvent>
    2422#include <QTimer>
    25 #ifdef Q_WS_MAC
    26 #include <QMenuBar>
    27 #endif
    28 #ifdef Q_WS_X11
    29 #include <limits.h>
    30 #endif
     23#include <QWidget>
    3124
    3225/* Local includes */
    33 #include "VBoxGlobal.h"
    34 #include "UISession.h"
     26#include "UIKeyboardHandlerSeamless.h"
    3527#include "UIMachineWindow.h"
    36 #include "UIMachineLogic.h"
    37 #include "UIFrameBuffer.h"
    38 #include "UIMachineLogicSeamless.h"
    39 #include "UIMachineViewSeamless.h"
    4028
    41 UIMachineViewSeamless::UIMachineViewSeamless(  UIMachineWindow *pMachineWindow
    42                                              , ulong uScreenId
    43 #ifdef VBOX_WITH_VIDEOHWACCEL
    44                                              , bool bAccelerate2DVideo
    45 #endif
    46                                              )
    47     : UIMachineView(  pMachineWindow
    48                     , uScreenId
    49 #ifdef VBOX_WITH_VIDEOHWACCEL
    50                     , bAccelerate2DVideo
    51 #endif
    52                     )
    53     , m_fShouldWeDoResize(false)
    54     , m_pSyncBlocker(0)
     29/* Fullscreen keyboard-handler constructor: */
     30UIKeyboardHandlerSeamless::UIKeyboardHandlerSeamless(UIMachineLogic* pMachineLogic)
     31    : UIKeyboardHandler(pMachineLogic)
    5532{
    56     /* Load machine view settings: */
    57     loadMachineViewSettings();
    58 
    59     /* Prepare frame buffer: */
    60     prepareFrameBuffer();
    61 
    62     /* Prepare common things: */
    63     prepareCommon();
    64 
    65     /* Prepare event-filters: */
    66     prepareFilters();
    67 
    68     /* Prepare connections: */
    69     prepareConnections();
    70 
    71     /* Prepare console connections: */
    72     prepareConsoleConnections();
    73 
    74     /* Prepare seamless view: */
    75     prepareSeamless();
    76 
    77     /* Initialization: */
    78     sltMachineStateChanged();
    79     sltAdditionsStateChanged();
    8033}
    8134
    82 UIMachineViewSeamless::~UIMachineViewSeamless()
     35/* Fullscreen keyboard-handler destructor: */
     36UIKeyboardHandlerSeamless::~UIKeyboardHandlerSeamless()
    8337{
    84     /* Cleanup seamless mode: */
    85     cleanupSeamless();
    86 
    87     /* Cleanup common things: */
    88     cleanupCommon();
    89 
    90     /* Cleanup frame buffer: */
    91     cleanupFrameBuffer();
    9238}
    9339
    94 void UIMachineViewSeamless::sltPerformGuestResize(const QSize &toSize)
     40/* Event handler for prepared listener(s): */
     41bool UIKeyboardHandlerSeamless::eventFilter(QObject *pWatchedObject, QEvent *pEvent)
    9542{
    96     if (uisession()->isGuestSupportsGraphics())
     43    /* Check if pWatchedObject object is view: */
     44    if (UIMachineView *pWatchedView = isItListenedView(pWatchedObject))
    9745    {
    98         /* Get machine window: */
    99         QMainWindow *pMachineWindow = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    100                                       qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    101 
    102         /* If this slot is invoked directly then use the passed size otherwise get
    103          * the available size for the guest display. We assume here that centralWidget()
    104          * contains this view only and gives it all available space: */
    105         QSize newSize(toSize.isValid() ? toSize : pMachineWindow ? pMachineWindow->centralWidget()->size() : QSize());
    106         AssertMsg(newSize.isValid(), ("Size should be valid!\n"));
    107 
    108         /* Do not send the same hints as we already have: */
    109         if ((newSize.width() == storedConsoleSize().width()) && (newSize.height() == storedConsoleSize().height()))
    110             return;
    111 
    112         /* We only actually send the hint if either an explicit new size was given
    113          * (e.g. if the request was triggered directly by a console resize event) or
    114          * if no explicit size was specified but a resize is flagged as being needed
    115          * (e.g. the autoresize was just enabled and the console was resized while it was disabled). */
    116         if (toSize.isValid() || m_fShouldWeDoResize)
    117         {
    118             /* Remember the new size: */
    119             storeConsoleSize(newSize.width(), newSize.height());
    120 
    121             /* Send new size-hint to the guest: */
    122             session().GetConsole().GetDisplay().SetVideoModeHint(newSize.width(), newSize.height(), 0, screenId());
    123         }
    124 
    125         /* We had requested resize now, rejecting other accident requests: */
    126         m_fShouldWeDoResize = false;
    127     }
    128 }
    129 
    130 void UIMachineViewSeamless::sltAdditionsStateChanged()
    131 {
    132     // TODO: Exit seamless if additions doesn't support it!
    133 }
    134 
    135 void UIMachineViewSeamless::sltDesktopResized()
    136 {
    137     // TODO: Try to resize framebuffer according new desktop size, exit seamless if resize is failed!
    138 
    139     /* If the desktop geometry is set automatically, this will update it: */
    140     calculateDesktopGeometry();
    141 }
    142 
    143 bool UIMachineViewSeamless::event(QEvent *pEvent)
    144 {
    145     switch (pEvent->type())
    146     {
    147         case VBoxDefs::SetRegionEventType:
    148         {
    149             /* Get region-update event: */
    150             UISetRegionEvent *pSetRegionEvent = static_cast<UISetRegionEvent*>(pEvent);
    151 
    152             /* Apply new region: */
    153             if (pSetRegionEvent->region() != m_lastVisibleRegion)
    154             {
    155                 m_lastVisibleRegion = pSetRegionEvent->region();
    156                 machineWindowWrapper()->setMask(m_lastVisibleRegion);
    157             }
    158             return true;
    159         }
    160 
    161         case VBoxDefs::ResizeEventType:
    162         {
    163             /* Some situations require framebuffer resize events to be ignored at all,
    164              * leaving machine-window, machine-view and framebuffer sizes preserved: */
    165             if (uisession()->isGuestResizeIgnored())
    166                 return true;
    167 
    168             /* We are starting to perform machine-view resize: */
    169             bool oldIgnoreMainwndResize = isMachineWindowResizeIgnored();
    170             setMachineWindowResizeIgnored(true);
    171 
    172             /* Get guest resize-event: */
    173             UIResizeEvent *pResizeEvent = static_cast<UIResizeEvent*>(pEvent);
    174 
    175             /* Perform framebuffer resize: */
    176             frameBuffer()->resizeEvent(pResizeEvent);
    177 
    178             /* Reapply maximum size restriction for machine-view: */
    179             setMaximumSize(sizeHint());
    180 
    181             /* Store the new size to prevent unwanted resize hints being sent back: */
    182             storeConsoleSize(pResizeEvent->width(), pResizeEvent->height());
    183 
    184             /* Perform machine-view resize: */
    185             resize(pResizeEvent->width(), pResizeEvent->height());
    186 
    187             /* Let our toplevel widget calculate its sizeHint properly. */
    188 #ifdef Q_WS_X11
    189             /* We use processEvents rather than sendPostedEvents & set the time out value to max cause on X11 otherwise
    190              * the layout isn't calculated correctly. Dosn't find the bug in Qt, but this could be triggered through
    191              * the async nature of the X11 window event system. */
    192             QCoreApplication::processEvents(QEventLoop::AllEvents, INT_MAX);
    193 #else /* Q_WS_X11 */
    194             QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest);
    195 #endif /* Q_WS_X11 */
    196 
    197 #ifdef Q_WS_MAC
    198             machineLogic()->updateDockIconSize(screenId(), pResizeEvent->width(), pResizeEvent->height());
    199 #endif /* Q_WS_MAC */
    200 
    201             /* Update machine-view sliders: */
    202             updateSliders();
    203 
    204             /* Report to the VM thread that we finished resizing */
    205             session().GetConsole().GetDisplay().ResizeCompleted(screenId());
    206 
    207             /* We are finishing to perform machine-view resize: */
    208             setMachineWindowResizeIgnored(oldIgnoreMainwndResize);
    209 
    210             /* Make sure that all posted signals are processed: */
    211             qApp->processEvents();
    212 
    213             /* We also recalculate the desktop geometry if this is determined
    214              * automatically.  In fact, we only need this on the first resize,
    215              * but it is done every time to keep the code simpler. */
    216             calculateDesktopGeometry();
    217 
    218             /* Emit a signal about guest was resized: */
    219             emit resizeHintDone();
    220 
    221             /* Unlock after processing guest resize event: */
    222             if (m_pSyncBlocker && m_pSyncBlocker->isRunning())
    223                 m_pSyncBlocker->quit();
    224 
    225             return true;
    226         }
    227 
    228         case QEvent::KeyPress:
    229         case QEvent::KeyRelease:
    230         {
    231             /* Get key-event: */
    232             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    233 
    234             /* Process Host+Home for menu popup: */
    235             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    236             {
    237                 if (pKeyEvent->key() == Qt::Key_Home)
    238                     QTimer::singleShot(0, machineWindowWrapper()->machineWindow(), SLOT(sltPopupMainMenu()));
    239                 else
    240                     pEvent->ignore();
    241             }
    242 
    243             break;
    244         }
    245 
    246         default:
    247             break;
    248     }
    249     return UIMachineView::event(pEvent);
    250 }
    251 
    252 bool UIMachineViewSeamless::eventFilter(QObject *pWatched, QEvent *pEvent)
    253 {
    254     /* Who are we watching? */
    255     QMainWindow *pMainDialog = machineWindowWrapper() && machineWindowWrapper()->machineWindow() ?
    256                                qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow()) : 0;
    257 
    258     if (pWatched != 0 && pWatched == pMainDialog)
    259     {
     46        /* Get corresponding screen index: */
     47        ulong uScreenId = m_views.key(pWatchedView);
     48        NOREF(uScreenId);
     49        /* Handle view events: */
    26050        switch (pEvent->type())
    26151        {
    262             case QEvent::Resize:
     52            case QEvent::KeyPress:
    26353            {
    264                 /* Send guest-resize hint only if top window resizing to required dimension: */
    265                 QResizeEvent *pResizeEvent = static_cast<QResizeEvent*>(pEvent);
    266                 if (pResizeEvent->size() != workingArea().size())
    267                     break;
    268 
    269                 /* Set the "guest needs to resize" hint.
    270                  * This hint is acted upon when (and only when) the autoresize property is "true": */
    271                 m_fShouldWeDoResize = uisession()->isGuestSupportsGraphics();
    272                 if (m_fShouldWeDoResize)
    273                     QTimer::singleShot(0, this, SLOT(sltPerformGuestResize()));
     54                /* Get key-event: */
     55                QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
     56                /* Process Host+Home for menu popup: */
     57                if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
     58                {
     59                    if (pKeyEvent->key() == Qt::Key_Home)
     60                    {
     61                        /* Post request to show popup-menu: */
     62                        QTimer::singleShot(0, m_windows[uScreenId]->machineWindow(), SLOT(sltPopupMainMenu()));
     63                        /* Filter-out this event: */
     64                        return true;
     65                    }
     66                }
    27467                break;
    27568            }
     
    27972    }
    28073
    281     return UIMachineView::eventFilter(pWatched, pEvent);
     74    /* Else just propagate to base-class: */
     75    return UIKeyboardHandler::eventFilter(pWatchedObject, pEvent);
    28276}
    28377
    284 void UIMachineViewSeamless::prepareCommon()
    285 {
    286     /* Base class common settings: */
    287     UIMachineView::prepareCommon();
    288 
    289     /* Setup size-policy: */
    290     setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum));
    291     /* Maximum size to sizehint: */
    292     setMaximumSize(sizeHint());
    293     /* Minimum size is ignored: */
    294     setMinimumSize(0, 0);
    295     /* No scrollbars: */
    296     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    297     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    298 }
    299 
    300 void UIMachineViewSeamless::prepareFilters()
    301 {
    302     /* Base class filters: */
    303     UIMachineView::prepareFilters();
    304 
    305 #ifdef Q_WS_MAC // TODO: Is it really needed? See UIMachineViewSeamless::eventFilter(...);
    306     /* Menu bar filter: */
    307     qobject_cast<QMainWindow*>(machineWindowWrapper()->machineWindow())->menuBar()->installEventFilter(this);
    308 #endif
    309 }
    310 
    311 void UIMachineViewSeamless::prepareConnections()
    312 {
    313     connect(QApplication::desktop(), SIGNAL(resized(int)), this, SLOT(sltDesktopResized()));
    314 }
    315 
    316 void UIMachineViewSeamless::prepareConsoleConnections()
    317 {
    318     /* Base class connections: */
    319     UIMachineView::prepareConsoleConnections();
    320 
    321     /* Guest additions state-change updater: */
    322     connect(uisession(), SIGNAL(sigAdditionsStateChange()), this, SLOT(sltAdditionsStateChanged()));
    323 }
    324 
    325 void UIMachineViewSeamless::prepareSeamless()
    326 {
    327     /* Set seamless feature flag to the guest: */
    328     session().GetConsole().GetDisplay().SetSeamlessMode(true);
    329     /* Create sync-blocker: */
    330     m_pSyncBlocker = new UIMachineViewBlocker;
    331 }
    332 
    333 void UIMachineViewSeamless::cleanupSeamless()
    334 {
    335     /* If machine still running: */
    336     if (uisession()->isRunning())
    337     {
    338         /* Reset seamless feature flag of the guest: */
    339         session().GetConsole().GetDisplay().SetSeamlessMode(false);
    340 
    341         /* Rollback seamless frame-buffer size to normal: */
    342         machineWindowWrapper()->machineWindow()->hide();
    343         sltPerformGuestResize(guestSizeHint());
    344         m_pSyncBlocker->exec();
    345 
    346         /* Delete sync-blocker: */
    347         m_pSyncBlocker->deleteLater();
    348     }
    349 }
    350 
    351 QRect UIMachineViewSeamless::workingArea()
    352 {
    353     /* Get corresponding screen: */
    354     int iScreen = static_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(screenId());
    355     /* Return available geometry for that screen: */
    356     return vboxGlobal().availableGeometry(iScreen);
    357 }
    358 
    359 void UIMachineViewSeamless::calculateDesktopGeometry()
    360 {
    361     /* This method should not get called until we have initially set up the desktop geometry type: */
    362     Assert((desktopGeometryType() != DesktopGeo_Invalid));
    363     /* If we are not doing automatic geometry calculation then there is nothing to do: */
    364     if (desktopGeometryType() == DesktopGeo_Automatic)
    365         m_desktopGeometry = workingArea().size();
    366 }
    367 
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIKeyboardHandlerSeamless.h

    r30551 r30637  
    22 *
    33 * VBox frontends: Qt GUI ("VirtualBox"):
    4  * UIMachineViewSeamless class declaration
     4 * UIKeyboardHandlerSeamless class declaration
    55 */
    66
     
    1717 */
    1818
    19 #ifndef ___UIMachineViewSeamless_h___
    20 #define ___UIMachineViewSeamless_h___
     19#ifndef ___UIKeyboardHandlerSeamless_h___
     20#define ___UIKeyboardHandlerSeamless_h___
    2121
    2222/* Local includes */
    23 #include "UIMachineView.h"
     23#include "UIKeyboardHandler.h"
    2424
    25 class UIMachineViewSeamless : public UIMachineView
     25class UIKeyboardHandlerSeamless : public UIKeyboardHandler
    2626{
    2727    Q_OBJECT;
    2828
    29 public:
    30 
    31     /* Public getters: */
    32     QRegion lastVisibleRegion() const { return m_lastVisibleRegion; }
    33 
    3429protected:
    3530
    36     /* Seamless machine-view constructor: */
    37     UIMachineViewSeamless(  UIMachineWindow *pMachineWindow
    38                           , ulong uScreenId
    39 #ifdef VBOX_WITH_VIDEOHWACCEL
    40                           , bool bAccelerate2DVideo
    41 #endif
    42     );
    43     /* Seamless machine-view destructor: */
    44     virtual ~UIMachineViewSeamless();
    45 
    46 private slots:
    47 
    48     /* Slot to perform guest resize: */
    49     void sltPerformGuestResize(const QSize &aSize = QSize());
    50 
    51     /* Console callback handlers: */
    52     void sltAdditionsStateChanged();
    53 
    54     /* Watch dog for desktop resizes: */
    55     void sltDesktopResized();
     31    /* Fullscreen keyboard-handler constructor/destructor: */
     32    UIKeyboardHandlerSeamless(UIMachineLogic *pMachineLogic);
     33    virtual ~UIKeyboardHandlerSeamless();
    5634
    5735private:
    5836
    5937    /* Event handlers: */
    60     bool event(QEvent *pEvent);
    6138    bool eventFilter(QObject *pWatched, QEvent *pEvent);
    6239
    63     /* Prepare helpers: */
    64     void prepareCommon();
    65     void prepareFilters();
    66     void prepareConnections();
    67     void prepareConsoleConnections();
    68     void prepareSeamless();
    69 
    70     /* Cleanup helpers: */
    71     void cleanupSeamless();
    72     //void cleanupConsoleConnections() {}
    73     //void prepareConnections() {}
    74     //void cleanupFilters() {}
    75     //void cleanupCommon() {}
    76 
    77     /* Private helpers: */
    78     void normalizeGeometry(bool /* fAdjustPosition */) {}
    79     QRect workingArea();
    80     void calculateDesktopGeometry();
    81     void maybeRestrictMinimumSize() {}
    82 
    83     /* Private variables: */
    84     bool m_fShouldWeDoResize : 1;
    85     QRegion m_lastVisibleRegion;
    86     UIMachineViewBlocker *m_pSyncBlocker;
    87 
    8840    /* Friend classes: */
    89     friend class UIMachineView;
     41    friend class UIKeyboardHandler;
    9042};
    9143
    92 #endif // !___UIMachineViewSeamless_h___
     44#endif // !___UIKeyboardHandlerSeamless_h___
    9345
  • trunk/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp

    r30544 r30637  
    8585    cleanupSeamless();
    8686
    87     /* Cleanup common things: */
    88     cleanupCommon();
    89 
    9087    /* Cleanup frame buffer: */
    9188    cleanupFrameBuffer();
     
    224221
    225222            return true;
    226         }
    227 
    228         case QEvent::KeyPress:
    229         case QEvent::KeyRelease:
    230         {
    231             /* Get key-event: */
    232             QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
    233 
    234             /* Process Host+Home for menu popup: */
    235             if (isHostKeyPressed() && pEvent->type() == QEvent::KeyPress)
    236             {
    237                 if (pKeyEvent->key() == Qt::Key_Home)
    238                     QTimer::singleShot(0, machineWindowWrapper()->machineWindow(), SLOT(sltPopupMainMenu()));
    239                 else
    240                     pEvent->ignore();
    241             }
    242 
    243             break;
    244223        }
    245224
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette