Changeset 63383 in vbox for trunk/src/VBox/Frontends/VirtualBox
- Timestamp:
- Aug 12, 2016 6:56:10 PM (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp
r62493 r63383 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 the keyboard is captured 23 * but the mouse not, and both when both are. 24 * * That the keyboard is captured when the mouse capture notification is 25 * displayed. 26 * * That keyboard capture works on X11 hosts when windows are dragged with 27 * various window managers. 28 * * That multiple machine windows do not fight for the focus on X11 hosts 29 * (noticeable through strange modifier key and capitals behaviour). 16 30 */ 17 31 … … 269 283 return; 270 284 285 /* On X11 we do not grab the keyboard as soon as it is captured, but delay it until the 286 * first keypress after the capture. We do this for several reasons. First, when several 287 * windows are created they all try to capture the keyboard when they get the focus. Due to 288 * the asynchronous nature of X11 the first window may only gets notified after the last is 289 * created, and there is a dance if they respond to the notifications by grabbing the keyboard 290 * and trigger new focus changes in the process. Second, it is sometimes inconvenient to 291 * grab the keyboard immediately on focus change: some window managers set the focus then 292 * try to grab the keyboard themselves, and sulk if they fail by refusing to e.g. drag a 293 * window using its title bar. This code uses a hack by taking (ulong)~0 as a parameter to 294 * finalise the capture. */ 295 296 /* If such view exists: */ 297 if (m_views.contains(uScreenId) 271 298 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000 272 /* Due to X11 async nature we may have lost the focus already by the time we get the focus 273 * notification, so we do a sanity check that we still have it. If we don't have the focus 274 * and grab the keyboard now that will cause focus change which we want to avoid. This change 275 * potentially leads to a loop where two windows are continually responding to outdated focus events. */ 276 const xcb_get_input_focus_cookie_t xcbFocusCookie = xcb_get_input_focus(QX11Info::connection()); 277 xcb_get_input_focus_reply_t *pFocusReply = xcb_get_input_focus_reply(QX11Info::connection(), xcbFocusCookie, NULL); 278 WId actualWinId = 0; 279 if (pFocusReply) 280 { 281 actualWinId = pFocusReply->focus; 282 free(pFocusReply); 283 } 284 else 285 LogRel(("GUI: UIKeyboardHandler::captureKeyboard: XCB error on acquiring focus information detected!\n")); 286 if (m_windows.value(uScreenId)->winId() != actualWinId) 287 return; 288 289 /* Delay capturing the keyboard if the mouse button is held down and the mouse is not 290 * captured to work around window managers which transfer the focus when the user 291 * clicks in the title bar and then try to grab the keyboard and sulk if they fail. 292 * If the click is inside of our views we will do the capture when it is released. */ 293 const xcb_query_pointer_cookie_t xcbPointerCookie = xcb_query_pointer(QX11Info::connection(), QX11Info::appRootWindow()); 294 xcb_query_pointer_reply_t *pPointerReply = xcb_query_pointer_reply(QX11Info::connection(), xcbPointerCookie, NULL); 295 if (!uisession()->isMouseCaptured() && pPointerReply && (pPointerReply->mask & XCB_KEY_BUT_MASK_BUTTON_1)) 296 { 297 free(pPointerReply); 298 return; 299 } 300 free(pPointerReply); 301 #endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */ 302 303 /* If such view exists: */ 304 if (m_views.contains(uScreenId)) 299 || ((uScreenId == (ulong)~0) && m_views.contains(m_idxDelayedKeyboardCaptureView)) 300 #endif 301 ) 305 302 { 306 303 #if defined(VBOX_WS_MAC) … … 371 368 # else /* QT_VERSION >= 0x050000 */ 372 369 370 if (uScreenId != (ulong)~0) 371 { 372 m_idxDelayedKeyboardCaptureView = uScreenId; 373 return; 374 } 375 uScreenId = m_idxDelayedKeyboardCaptureView; 373 376 /* On X11, we are using XCB stuff to grab the keyboard. 374 377 * This stuff is a part of the active keyboard grabbing functionality. 375 * Active keyboard grabbing causes a problems on certain oldwindow managers - a window cannot378 * Active keyboard grabbing causes a problems on many window managers - a window cannot 376 379 * be moved using the mouse. So we additionally grabbing the mouse as well to detect that user 377 380 * is trying to click outside of internal window geometry. */ 378 381 379 /* Grab the mouse button (if mouse is not captured), 380 * We do not check for failure as we do not currently implement a back-up plan. */ 381 if (!uisession()->isMouseCaptured()) 382 xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(), 383 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, 384 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY); 382 /* Grab the mouse button. We do not check for failure as we do not currently implement a 383 * back-up plan. */ 384 xcb_grab_button_checked(QX11Info::connection(), 0, QX11Info::appRootWindow(), 385 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, 386 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_1, XCB_MOD_MASK_ANY); 385 387 /* And grab the keyboard, using XCB directly, as Qt does not report failure. */ 386 388 xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(QX11Info::connection(), false, m_views[uScreenId]->winId(), … … 390 392 { 391 393 /* Try again later: */ 392 m_idxDelayedKeyboardCaptureView = uScreenId;393 394 free(pGrabReply); 394 395 return; … … 1379 1380 /* If we were asked to grab the keyboard previously but had to delay it 1380 1381 * then try again on every key press and release event until we manage: */ 1381 if (m_idxDelayedKeyboardCaptureView != -1) 1382 captureKeyboard(m_idxDelayedKeyboardCaptureView); 1382 captureKeyboard((ulong)~0); 1383 1383 1384 1384 /* Cast to XCB key-event: */ … … 1484 1484 } 1485 1485 /* Else if the event happened outside of our view areas then release the keyboard, 1486 * but set the delayed capture index so that it will be captured again if we still1487 * have the focus after the event is handled: */1486 * but capture it again (delayed) immediately. If the event causes us to loose the 1487 * focus then the delayed capture will not happen: */ 1488 1488 releaseKeyboard(); 1489 m_idxDelayedKeyboardCaptureView = uScreenId;1489 captureKeyboard(uScreenId); 1490 1490 /* And re-send the event so that the window which it was meant for actually gets it: */ 1491 1491 xcb_allow_events_checked(QX11Info::connection(), XCB_ALLOW_REPLAY_POINTER, pButtonEvent->time); … … 1799 1799 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally()) 1800 1800 #endif /* !VBOX_WS_WIN */ 1801 #if defined(VBOX_WS_X11) && QT_VERSION >= 0x0500001802 m_idxDelayedKeyboardCaptureView = uScreenId;1803 #else /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */1804 1801 captureKeyboard(uScreenId); 1805 #endif /* !VBOX_WS_X11 || QT_VERSION < 0x050000 */1806 1802 /* Reset the single-time disable capture flag: */ 1807 1803 if (isAutoCaptureDisabled())
Note:
See TracChangeset
for help on using the changeset viewer.