Changeset 63587 in vbox
- Timestamp:
- Aug 18, 2016 2:44:00 PM (8 years ago)
- Location:
- trunk/src/VBox/Frontends/VirtualBox/src/runtime
- Files:
-
- 2 edited
-
UIKeyboardHandler.cpp (modified) (14 diffs)
-
UIKeyboardHandler.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp
r63579 r63587 14 14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 */ 17 18 /* 19 * Things worth testing when changing this code: 20 * - That automatic keyboard capture works. 21 * - That the keyboard is captured when the mouse is. 22 * - That the host key releases the keyboard when 23 * the keyboard is captured but the mouse not, and both when both are. 24 * - That the host key captures both keyboard and mouse. 25 * - That the keyboard is captured when the mouse capture notification is 26 * displayed. 27 * - That keyboard capture works on X11 hosts when windows are dragged with 28 * various window managers. 29 * - That multiple machine windows do not fight for the focus on X11 hosts 30 * (noticeable through strange modifier key and capitals behaviour). 16 31 */ 17 32 … … 234 249 /* Do NOT capture the keyboard if it is already captured: */ 235 250 if (m_fIsKeyboardCaptured) 251 { 252 /* Make sure the right screen had captured the keyboard: */ 253 Assert((int)uScreenId == m_iKeyboardCaptureViewIndex); 236 254 return; 237 238 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000 239 /* Due to X11 async nature we may have lost the focus already by the time we get the focus 240 * notification, so we do a sanity check that we still have it. If we don't have the focus 241 * and grab the keyboard now that will cause focus change which we want to avoid. This change 242 * potentially leads to a loop where two windows are continually responding to outdated focus events. */ 243 const xcb_get_input_focus_cookie_t xcbFocusCookie = xcb_get_input_focus(QX11Info::connection()); 244 xcb_get_input_focus_reply_t *pFocusReply = xcb_get_input_focus_reply(QX11Info::connection(), xcbFocusCookie, NULL); 245 WId actualWinId = 0; 246 if (pFocusReply) 247 { 248 actualWinId = pFocusReply->focus; 249 free(pFocusReply); 250 } 251 else 252 LogRel(("GUI: UIKeyboardHandler::captureKeyboard: XCB error on acquiring focus information detected!\n")); 253 if (m_windows.value(uScreenId)->winId() != actualWinId) 254 return; 255 256 /* Delay capturing the keyboard if the mouse button is held down and the mouse is not 257 * captured to work around window managers which transfer the focus when the user 258 * clicks in the title bar and then try to grab the keyboard and sulk if they fail. 259 * If the click is inside of our views we will do the capture when it is released. */ 260 const xcb_query_pointer_cookie_t xcbPointerCookie = xcb_query_pointer(QX11Info::connection(), QX11Info::appRootWindow()); 261 xcb_query_pointer_reply_t *pPointerReply = xcb_query_pointer_reply(QX11Info::connection(), xcbPointerCookie, NULL); 262 if (!uisession()->isMouseCaptured() && pPointerReply && (pPointerReply->mask & XCB_KEY_BUT_MASK_BUTTON_1)) 263 { 264 free(pPointerReply); 265 return; 266 } 267 free(pPointerReply); 268 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */ 255 } 269 256 270 257 /* If such view exists: */ … … 338 325 # else /* QT_VERSION >= 0x050000 */ 339 326 327 /* On X11, we do not grab the keyboard as soon as it is captured, but delay it 328 * until the first keypress after the capture. We do this for several reasons: 329 * - First, when several windows are created they all try to capture the keyboard when 330 * they get the focus. Due to the asynchronous nature of X11 the first window may only 331 * gets notified after the last is created, and there is a dance if they respond to 332 * the notifications by grabbing the keyboard and trigger new focus changes in the process. 333 * - Second, grabbing the keyboard immediately on focus change upsets some window managers, 334 * they give us the focus then try to grab the keyboard themselves, and sulk if they fail 335 * by refusing to e.g. drag a window using its title bar. */ 336 337 # endif /* QT_VERSION >= 0x050000 */ 338 #else 339 340 /* On other platforms we are just praying Qt method to work: */ 341 m_views[uScreenId]->grabKeyboard(); 342 343 #endif 344 345 /* Remember which screen wish to capture the keyboard: */ 346 m_iKeyboardCaptureViewIndex = uScreenId; 347 348 #if !defined(VBOX_WS_X11) || QT_VERSION < 0x050000 349 /* Finalising keyboard capture: */ 350 finaliseCaptureKeyboard(); 351 #endif 352 } 353 } 354 355 void UIKeyboardHandler::finaliseCaptureKeyboard() 356 { 357 /* Do NOT capture the keyboard if it is already captured: */ 358 if (m_fIsKeyboardCaptured) 359 return; 360 361 /* Make sure capture was really requested: */ 362 if (m_iKeyboardCaptureViewIndex == -1) 363 return; 364 365 /* If such view exists: */ 366 if (m_views.contains(m_iKeyboardCaptureViewIndex)) 367 { 368 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000 369 340 370 /* On X11, we are using XCB stuff to grab the keyboard. 341 371 * This stuff is a part of the active keyboard grabbing functionality. 342 * Active keyboard grabbing causes a problems on certain old window managers - a window cannot 343 * be moved using the mouse. So we additionally grabbing the mouse as well to detect that user 344 * is trying to click outside of internal window geometry. */ 345 346 /* Grab the mouse button (if mouse is not captured), 347 * We do not check for failure as we do not currently implement a back-up plan. */ 348 if (!uisession()->isMouseCaptured()) 349 xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(), 350 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, 351 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY); 372 * Active keyboard grabbing causes a problems on many window managers - a window cannot 373 * be moved using the mouse. So we additionally grabbing the mouse as well to detect that 374 * user is trying to click outside of internal window geometry. */ 375 376 /* Grab the mouse button. We do not check for failure as we do not currently implement a back-up plan. */ 377 xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(), 378 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, 379 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY); 352 380 /* And grab the keyboard, using XCB directly, as Qt does not report failure. */ 353 xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(QX11Info::connection(), false, m_views[ uScreenId]->winId(),381 xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(QX11Info::connection(), false, m_views[m_iKeyboardCaptureViewIndex]->winId(), 354 382 XCB_TIME_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 355 383 xcb_grab_keyboard_reply_t *pGrabReply = xcb_grab_keyboard_reply(QX11Info::connection(), xcbGrabCookie, NULL); … … 357 385 { 358 386 /* Try again later: */ 359 m_idxDelayedKeyboardCaptureView = uScreenId;360 387 free(pGrabReply); 361 388 return; … … 363 390 free(pGrabReply); 364 391 365 /* Successfully captured, stop delayed capture attempts: */ 366 m_idxDelayedKeyboardCaptureView = -1; 367 368 # endif /* QT_VERSION >= 0x050000 */ 369 #else 370 371 /* On other platforms we are just praying Qt method to work: */ 372 m_views[uScreenId]->grabKeyboard(); 373 374 #endif 375 376 /* Remember which screen had captured keyboard: */ 377 m_iKeyboardCaptureViewIndex = uScreenId; 392 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */ 378 393 379 394 /* Store new keyboard-captured state value: */ … … 387 402 void UIKeyboardHandler::releaseKeyboard() 388 403 { 389 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000390 /* If we haven't captured the keyboard by now it is too late: */391 m_idxDelayedKeyboardCaptureView = -1;392 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */393 394 404 /* Do NOT release the keyboard if it is already released: */ 395 405 if (!m_fIsKeyboardCaptured) 406 { 407 /* If a delayed capture is scheduled then cancel it: */ 408 m_iKeyboardCaptureViewIndex = -1; 396 409 return; 410 } 397 411 398 412 /* If such view exists: */ … … 454 468 /* On X11, we are using XCB stuff to grab the keyboard. 455 469 * This stuff is a part of the active keyboard grabbing functionality. 456 * Active keyboard grabbing causes a problems on certain oldwindow managers - a window cannot457 * be moved using the mouse. So we finally releasing additionally grabbed mouse as well to458 * allow further user interactions. */470 * Active keyboard grabbing causes a problems on many window managers - a window cannot 471 * be moved using the mouse. So we finally releasing additionally grabbed mouse as well 472 * to allow further user interactions. */ 459 473 460 474 /* Ungrab using XCB: */ … … 472 486 #endif 473 487 474 /* Forget which screen had captured keyboard: */488 /* Forget which screen had captured the keyboard: */ 475 489 m_iKeyboardCaptureViewIndex = -1; 476 490 … … 1344 1358 /* If we were asked to grab the keyboard previously but had to delay it 1345 1359 * then try again on every key press and release event until we manage: */ 1346 if (m_idxDelayedKeyboardCaptureView != -1) 1347 captureKeyboard(m_idxDelayedKeyboardCaptureView); 1360 finaliseCaptureKeyboard(); 1348 1361 1349 1362 /* Cast to XCB key-event: */ … … 1449 1462 } 1450 1463 /* Else if the event happened outside of our view areas then release the keyboard, 1451 * but set the delayed capture index so that it will be captured again if we still1452 * have the focus after the event is handled: */1464 * but capture it again (delayed) immediately. If the event causes us to loose the 1465 * focus then the delayed capture will not happen: */ 1453 1466 releaseKeyboard(); 1454 m_idxDelayedKeyboardCaptureView = uScreenId;1467 captureKeyboard(uScreenId); 1455 1468 /* And re-send the event so that the window which it was meant for actually gets it: */ 1456 1469 xcb_allow_events_checked(QX11Info::connection(), XCB_ALLOW_REPLAY_POINTER, pButtonEvent->time); … … 1532 1545 , m_pMachineLogic(pMachineLogic) 1533 1546 , m_iKeyboardCaptureViewIndex(-1) 1534 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x0500001535 , m_idxDelayedKeyboardCaptureView(-1)1536 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */1537 1547 , m_globalSettings(vboxGlobal().settings()) 1538 1548 , m_fIsKeyboardCaptured(false) … … 1729 1739 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally()) 1730 1740 #endif /* !VBOX_WS_WIN */ 1731 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x0500001732 m_idxDelayedKeyboardCaptureView = uScreenId;1733 #else /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */1734 1741 captureKeyboard(uScreenId); 1735 #endif /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */1736 1742 /* Reset the single-time disable capture flag: */ 1737 1743 if (isAutoCaptureDisabled()) … … 2083 2089 if (ok) 2084 2090 { 2091 /* Determine whether the mouse can be captured: */ 2092 bool fCaptureMouse = !uisession()->isMouseSupportsAbsolute() 2093 || !uisession()->isMouseIntegrated(); 2094 2085 2095 if (m_fIsKeyboardCaptured) 2096 { 2086 2097 releaseKeyboard(); 2098 if (fCaptureMouse) 2099 machineLogic()->mouseHandler()->releaseMouse(); 2100 } 2087 2101 else 2102 { 2088 2103 captureKeyboard(uScreenId); 2089 if (!uisession()->isMouseSupportsAbsolute() || !uisession()->isMouseIntegrated()) 2090 { 2104 finaliseCaptureKeyboard(); 2091 2105 #ifdef VBOX_WS_X11 2092 2106 /* Make sure that pending FocusOut events from the 2093 2107 * previous message box are handled, otherwise the 2094 2108 * mouse is immediately ungrabbed: */ 2109 /// @todo Is that really needed? 2095 2110 qApp->processEvents(); 2096 2111 #endif /* VBOX_WS_X11 */ 2097 if ( m_fIsKeyboardCaptured)2112 if (fCaptureMouse) 2098 2113 { 2099 2114 const MouseCapturePolicy mcp = gEDataManager->mouseCapturePolicy(vboxGlobal().managedVMUuid()); … … 2101 2116 machineLogic()->mouseHandler()->captureMouse(uScreenId); 2102 2117 } 2103 else2104 machineLogic()->mouseHandler()->releaseMouse();2105 2118 } 2106 2119 } -
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.h
r63578 r63587 80 80 # endif /* QT_VERSION < 0x050000 */ 81 81 #endif /* VBOX_WS_X11 */ 82 83 /** Captures the keyboard for @a uScreenId. */ 82 84 void captureKeyboard(ulong uScreenId); 85 /** Finalises keyboard capturing. */ 86 void finaliseCaptureKeyboard(); 87 /** Releases the keyboard. */ 83 88 void releaseKeyboard(); 89 84 90 void releaseAllPressedKeys(bool aReleaseHostKey = true); 85 91 … … 196 202 /* Other keyboard variables: */ 197 203 int m_iKeyboardCaptureViewIndex; 198 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000199 /* Holds the index of the screen to capture keyboard when ready. */200 int m_idxDelayedKeyboardCaptureView;201 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */202 204 const VBoxGlobalSettings &m_globalSettings; 203 205
Note:
See TracChangeset
for help on using the changeset viewer.

