VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/runtime/UIKeyboardHandler.cpp

Last change on this file was 107156, checked in by vboxsync, 7 weeks ago

FE/Qt: bugref:10407. Some formatting.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 84.1 KB
Line 
1/* $Id: UIKeyboardHandler.cpp 107156 2024-11-27 10:34:23Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIKeyboardHandler class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/*
29 * Things worth testing when changing this code:
30 * - That automatic keyboard capture works.
31 * - That the keyboard is captured when the mouse is.
32 * - That the host key releases the keyboard when
33 * the keyboard is captured but the mouse not, and both when both are.
34 * - That the host key captures both keyboard and mouse.
35 * - That the keyboard is captured when the mouse capture notification is
36 * displayed.
37 * - That keyboard capture works on X11 hosts when windows are dragged with
38 * various window managers.
39 * - That multiple machine windows do not fight for the focus on X11 hosts
40 * (noticeable through strange modifier key and capitals behaviour).
41 */
42
43/* Qt includes: */
44#include <QApplication>
45#include <QKeyEvent>
46#include <QTimer>
47
48/* GUI includes: */
49#include "UIActionPool.h"
50#include "UICommon.h"
51#include "UIExtraDataManager.h"
52#include "UIHostComboEditor.h"
53#include "UIKeyboardHandlerFullscreen.h"
54#include "UIKeyboardHandlerNormal.h"
55#include "UIKeyboardHandlerScale.h"
56#include "UIKeyboardHandlerSeamless.h"
57#include "UIMachine.h"
58#include "UIMachineLogic.h"
59#include "UIMachineView.h"
60#include "UIMachineWindow.h"
61#include "UIMessageCenter.h"
62#include "UIMouseHandler.h"
63#include "UINotificationCenter.h"
64#ifdef VBOX_WS_MAC
65# include "UICocoaApplication.h"
66# include "VBoxUtils-darwin.h"
67# include "DarwinKeyboard.h"
68#endif
69#ifdef VBOX_WS_WIN
70# include "WinKeyboard.h"
71#endif
72#ifdef VBOX_WS_NIX
73# include "XKeyboard.h"
74# include "VBoxUtils-nix.h"
75#endif
76
77/* Other VBox includes: */
78#ifdef VBOX_WS_MAC
79# include "iprt/cpp/utils.h"
80#endif
81
82/* External includes: */
83#ifdef VBOX_WS_MAC
84# include <Carbon/Carbon.h>
85#endif
86#ifdef VBOX_WS_NIX
87# include <X11/XKBlib.h>
88# include <X11/keysym.h>
89# ifdef KeyPress
90const int XFocusIn = FocusIn;
91const int XFocusOut = FocusOut;
92const int XKeyPress = KeyPress;
93const int XKeyRelease = KeyRelease;
94# undef KeyRelease
95# undef KeyPress
96# undef FocusOut
97# undef FocusIn
98# endif /* KeyPress */
99# include <xcb/xcb.h>
100#endif /* VBOX_WS_NIX */
101
102/* Enums representing different keyboard-states: */
103enum { KeyExtended = 0x01, KeyPressed = 0x02, KeyPause = 0x04, KeyPrint = 0x08 };
104enum { IsKeyPressed = 0x01, IsExtKeyPressed = 0x02, IsKbdCaptured = 0x80 };
105
106
107#ifdef VBOX_WS_WIN
108UIKeyboardHandler *UIKeyboardHandler::m_spKeyboardHandler = 0;
109#endif /* VBOX_WS_WIN */
110
111#ifdef VBOX_WS_NIX
112/* A lookup table to convert evdev codes to HID usage page/codes: */
113#define CODE_ARRAY_LENGTH 255
114LONG evcode_hid[CODE_ARRAY_LENGTH][2] = {
115 {0x7, 0x0}, /* NULL */
116 {0x7, 0x29}, /* Escape */
117 {0x7, 0x1e}, /* Digit1 */
118 {0x7, 0x1f}, /* Digit2 */
119 {0x7, 0x20}, /* Digit3 */
120 {0x7, 0x21}, /* Digit4 */
121 {0x7, 0x22}, /* Digit5 */
122 {0x7, 0x23}, /* Digit6 */
123 {0x7, 0x24}, /* Digit7 */
124 {0x7, 0x25}, /* Digit8 */
125 {0x7, 0x26}, /* Digit9 */
126 {0x7, 0x27}, /* Digit0 */
127 {0x7, 0x2d}, /* Minus */
128 {0x7, 0x2e}, /* Equal */
129 {0x7, 0x2a}, /* Backspace */
130 {0x7, 0x2b}, /* Tab */
131 {0x7, 0x14}, /* KeyQ */
132 {0x7, 0x1a}, /* KeyW */
133 {0x7, 0x8}, /* KeyE */
134 {0x7, 0x15}, /* KeyR */
135 {0x7, 0x17}, /* KeyT */
136 {0x7, 0x1c}, /* KeyY */
137 {0x7, 0x18}, /* KeyU */
138 {0x7, 0xc}, /* KeyI */
139 {0x7, 0x12}, /* KeyO */
140 {0x7, 0x13}, /* KeyP */
141 {0x7, 0x2f}, /* BracketLeft */
142 {0x7, 0x30}, /* BracketRight */
143 {0x7, 0x28}, /* Enter */
144 {0x7, 0xe0}, /* ControlLeft */
145 {0x7, 0x4}, /* KeyA */
146 {0x7, 0x16}, /* KeyS */
147 {0x7, 0x7}, /* KeyD */
148 {0x7, 0x9}, /* KeyF */
149 {0x7, 0xa}, /* KeyG */
150 {0x7, 0xb}, /* KeyH */
151 {0x7, 0xd}, /* KeyJ */
152 {0x7, 0xe}, /* KeyK */
153 {0x7, 0xf}, /* KeyL */
154 {0x7, 0x33}, /* Semicolon */
155 {0x7, 0x34}, /* Quote */
156 {0x7, 0x35}, /* Backquote */
157 {0x7, 0xe1}, /* ShiftLeft */
158 {0x7, 0x31}, /* Backslash */
159 {0x7, 0x1d}, /* KeyZ */
160 {0x7, 0x1b}, /* KeyX */
161 {0x7, 0x6}, /* KeyC */
162 {0x7, 0x19}, /* KeyV */
163 {0x7, 0x5}, /* KeyB */
164 {0x7, 0x11}, /* KeyN */
165 {0x7, 0x10}, /* KeyM */
166 {0x7, 0x36}, /* Comma */
167 {0x7, 0x37}, /* Period */
168 {0x7, 0x38}, /* Slash */
169 {0x7, 0xe5}, /* ShiftRight */
170 {0x7, 0x55}, /* NumpadMultiply */
171 {0x7, 0xe2}, /* AltLeft */
172 {0x7, 0x2c}, /* Space */
173 {0x7, 0x39}, /* CapsLock */
174 {0x7, 0x3a}, /* F1 */
175 {0x7, 0x3b}, /* F2 */
176 {0x7, 0x3c}, /* F3 */
177 {0x7, 0x3d}, /* F4 */
178 {0x7, 0x3e}, /* F5 */
179 {0x7, 0x3f}, /* F6 */
180 {0x7, 0x40}, /* F7 */
181 {0x7, 0x41}, /* F8 */
182 {0x7, 0x42}, /* F9 */
183 {0x7, 0x43}, /* F10 */
184 {0x7, 0x53}, /* NumLock */
185 {0x7, 0x47}, /* ScrollLock */
186 {0x7, 0x5f}, /* Numpad7 */
187 {0x7, 0x60}, /* Numpad8 */
188 {0x7, 0x61}, /* Numpad9 */
189 {0x7, 0x56}, /* NumpadSubtract */
190 {0x7, 0x5c}, /* Numpad4 */
191 {0x7, 0x5d}, /* Numpad5 */
192 {0x7, 0x5e}, /* Numpad6 */
193 {0x7, 0x57}, /* NumpadAdd */
194 {0x7, 0x59}, /* Numpad1 */
195 {0x7, 0x5a}, /* Numpad2 */
196 {0x7, 0x5b}, /* Numpad3 */
197 {0x7, 0x62}, /* Numpad0 */
198 {0x7, 0x63}, /* NumpadDecimal */
199 {0x0, 0x0}, /* NULL */
200 {0x7, 0x94}, /* Lang5 */
201 {0x7, 0x64}, /* IntlBackslash */
202 {0x7, 0x44}, /* F11 */
203 {0x7, 0x45}, /* F12 */
204 {0x7, 0x87}, /* IntlRo */
205 {0x7, 0x92}, /* Lang3 */
206 {0x7, 0x93}, /* Lang4 */
207 {0x7, 0x8a}, /* Convert */
208 {0x7, 0x88}, /* KanaMode */
209 {0x7, 0x8b}, /* NonConvert */
210 {0x0, 0x0}, /* NULL */
211 {0x7, 0x58}, /* NumpadEnter */
212 {0x7, 0xe4}, /* ControlRight */
213 {0x7, 0x54}, /* NumpadDivide */
214 {0x7, 0x46}, /* PrintScreen */
215 {0x7, 0xe6}, /* AltRight */
216 {0x0, 0x0}, /* NULL */
217 {0x7, 0x4a}, /* Home */
218 {0x7, 0x52}, /* ArrowUp */
219 {0x7, 0x4b}, /* PageUp */
220 {0x7, 0x50}, /* ArrowLeft */
221 {0x7, 0x4f}, /* ArrowRight */
222 {0x7, 0x4d}, /* End */
223 {0x7, 0x51}, /* ArrowDown */
224 {0x7, 0x4e}, /* PageDown */
225 {0x7, 0x49}, /* Insert */
226 {0x7, 0x4c}, /* Delete */
227 {0x0, 0x0}, /* NULL */
228 {0x7, 0x7f}, /* AudioVolumeMute */
229 {0x7, 0x81}, /* AudioVolumeDown */
230 {0x7, 0x80}, /* AudioVolumeUp */
231 {0x7, 0x66}, /* Power */
232 {0x7, 0x67}, /* NumpadEqual */
233 {0x7, 0xd7}, /* NULL */
234 {0x7, 0x48}, /* Pause */
235 {0xc, 0x29f}, /* ShowAllWindows */
236 {0x7, 0x85}, /* NumpadComma */
237 {0x7, 0x90}, /* Lang1 */
238 {0x7, 0x91}, /* Lang2 */
239 {0x7, 0x89}, /* IntlYen */
240 {0x7, 0xe3}, /* MetaLeft */
241 {0x7, 0xe7}, /* MetaRight */
242 {0x7, 0x65}, /* ContextMenu */
243 {0xc, 0x226}, /* BrowserStop */
244 {0x7, 0x79}, /* Again */
245 {0x0, 0x0}, /* NULL */
246 {0x7, 0x7a}, /* Undo */
247 {0x7, 0x77}, /* Select */
248 {0x7, 0x7c}, /* Copy */
249 {0x7, 0x74}, /* Open */
250 {0x7, 0x7d}, /* Paste */
251 {0x7, 0x7e}, /* Find */
252 {0x7, 0x7b}, /* Cut */
253 {0x7, 0x75}, /* Help */
254 {0x0, 0x0}, /* NULL */
255 {0xc, 0x192}, /* LaunchApp2 */
256 {0x0, 0x0}, /* NULL */
257 {0x0, 0x0}, /* NULL */
258 {0x0, 0x0}, /* NULL */
259 {0xc, 0x194}, /* LaunchApp1 */
260 {0x0, 0x0}, /* NULL */
261 {0x0, 0x0}, /* NULL */
262 {0x0, 0x0}, /* NULL */
263 {0x0, 0x0}, /* NULL */
264 {0x0, 0x0}, /* NULL */
265 {0xc, 0x196}, /* NULL */
266 {0x0, 0x0}, /* NULL */
267 {0xc, 0x19e}, /* NULL */
268 {0x0, 0x0}, /* NULL */
269 {0x0, 0x0}, /* NULL */
270 {0xc, 0x18a}, /* LaunchMail */
271 {0xc, 0x22a}, /* BrowserFavorites */
272 {0x0, 0x0}, /* NULL */
273 {0xc, 0x224}, /* BrowserBack */
274 {0xc, 0x225}, /* BrowserForward */
275 {0x0, 0x0}, /* NULL */
276 {0xc, 0xb8}, /* Eject */
277 {0x0, 0x0}, /* NULL */
278 {0xc, 0xb5}, /* MediaTrackNext */
279 {0xc, 0xcd}, /* MediaPlayPause */
280 {0xc, 0xb6}, /* MediaTrackPrevious */
281 {0xc, 0xb7}, /* MediaStop */
282 {0xc, 0xb2}, /* MediaRecord */
283 {0xc, 0xb4}, /* MediaRewind */
284 {0xc, 0x8c}, /* NULL */
285 {0x0, 0x0}, /* NULL */
286 {0xc, 0x183}, /* MediaSelect */
287 {0xc, 0x223}, /* BrowserHome */
288 {0xc, 0x227}, /* BrowserRefresh */
289 {0xc, 0x94}, /* NULL */
290 {0x0, 0x0}, /* NULL */
291 {0x0, 0x0}, /* NULL */
292 {0x0, 0x0}, /* NULL */
293 {0x0, 0x0}, /* NULL */
294 {0x7, 0xb6}, /* NumpadParenLeft */
295 {0x7, 0xb7}, /* NumpadParenRight */
296 {0xc, 0x201}, /* NULL */
297 {0xc, 0x279}, /* NULL */
298 {0x7, 0x68}, /* F13 */
299 {0x7, 0x69}, /* F14 */
300 {0x7, 0x6a}, /* F15 */
301 {0x7, 0x6b}, /* F16 */
302 {0x7, 0x6c}, /* F17 */
303 {0x7, 0x6d}, /* F18 */
304 {0x7, 0x6e}, /* F19 */
305 {0x7, 0x6f}, /* F20 */
306 {0x7, 0x70}, /* F21 */
307 {0x7, 0x71}, /* F22 */
308 {0x7, 0x72}, /* F23 */
309 {0x7, 0x73}, /* F24 */
310 {0x0, 0x0}, /* NULL */
311 {0x0, 0x0}, /* NULL */
312 {0x0, 0x0}, /* NULL */
313 {0x0, 0x0}, /* NULL */
314 {0x0, 0x0}, /* NULL */
315 {0x0, 0x0}, /* NULL */
316 {0xc, 0xb1}, /* MediaPause */
317 {0x0, 0x0}, /* NULL */
318 {0x0, 0x0}, /* NULL */
319 {0xc, 0x2a2}, /* NULL */
320 {0x0, 0x0}, /* NULL */
321 {0xc, 0x203}, /* NULL */
322 {0xc, 0xb0}, /* MediaPlay */
323 {0xc, 0xb3}, /* MediaFastForward */
324 {0xc, 0xe5}, /* NULL */
325 {0xc, 0x208}, /* NULL */
326 {0x0, 0x0}, /* NULL */
327 {0x0, 0x0}, /* NULL */
328 {0x0, 0x0}, /* NULL */
329 {0x0, 0x0}, /* NULL */
330 {0x0, 0x0}, /* NULL */
331 {0x0, 0x0}, /* NULL */
332 {0xc, 0x221}, /* BrowserSearch */
333 {0x0, 0x0}, /* NULL */
334 {0x0, 0x0}, /* NULL */
335 {0x0, 0x0}, /* NULL */
336 {0x0, 0x0}, /* NULL */
337 {0x0, 0x0}, /* NULL */
338 {0x0, 0x0}, /* NULL */
339 {0xc, 0x70}, /* BrightnessDown */
340 {0xc, 0x6f}, /* BrightnessUp */
341 {0x0, 0x0}, /* NULL */
342 {0x0, 0x0}, /* NULL */
343 {0xc, 0x7c}, /* NULL */
344 {0xc, 0x7a}, /* NULL */
345 {0xc, 0x79}, /* NULL */
346 {0xc, 0x28c}, /* MailSend */
347 {0xc, 0x289}, /* MailReply */
348 {0xc, 0x28b}, /* MailForward */
349 {0xc, 0x207}, /* NULL */
350 {0xc, 0x1a7}, /* NULL */
351 {0x0, 0x0}, /* NULL */
352 {0x0, 0x0}, /* NULL */
353 {0x0, 0x0}, /* NULL */
354 {0x0, 0x0}, /* NULL */
355 {0x0, 0x0}, /* NULL */
356 {0x0, 0x0}, /* NULL */
357 {0x0, 0x0}, /* NULL */
358 {0x0, 0x0}, /* NULL */
359 {0xc, 0x75}, /* NULL */
360 {0x0, 0x0}, /* NULL */
361 {0x0, 0x0}, /* NULL */
362 {0x0, 0x0}, /* NULL */
363 {0x0, 0x0}, /* NULL */
364 {0x0, 0x0}, /* NULL */
365 {0x0, 0x0}, /* NULL */
366 {0x0, 0x0}, /* NULL */
367 {0x0, 0x0}, /* NULL */
368 {0x0, 0x0}, /* NULL */
369 {0x0, 0x0} /* NULL */
370};
371#endif /* VBOX_WS_NIX */
372
373/* Factory function to create keyboard-handler: */
374UIKeyboardHandler* UIKeyboardHandler::create(UIMachineLogic *pMachineLogic,
375 UIVisualStateType visualStateType)
376{
377 /* Prepare keyboard-handler: */
378 UIKeyboardHandler *pKeyboardHandler = 0;
379
380 /* Depending on visual-state type: */
381 switch (visualStateType)
382 {
383 case UIVisualStateType_Normal:
384 pKeyboardHandler = new UIKeyboardHandlerNormal(pMachineLogic);
385 break;
386 case UIVisualStateType_Fullscreen:
387 pKeyboardHandler = new UIKeyboardHandlerFullscreen(pMachineLogic);
388 break;
389 case UIVisualStateType_Seamless:
390 pKeyboardHandler = new UIKeyboardHandlerSeamless(pMachineLogic);
391 break;
392 case UIVisualStateType_Scale:
393 pKeyboardHandler = new UIKeyboardHandlerScale(pMachineLogic);
394 break;
395 default:
396 break;
397 }
398
399#ifdef VBOX_WS_WIN
400 /* It is necessary to have static pointer to created handler
401 * because windows keyboard-hook works only with static members: */
402 m_spKeyboardHandler = pKeyboardHandler;
403#endif /* VBOX_WS_WIN */
404
405 /* Return prepared keyboard-handler: */
406 return pKeyboardHandler;
407}
408
409/* Factory function to destroy keyboard-handler: */
410void UIKeyboardHandler::destroy(UIKeyboardHandler *pKeyboardHandler)
411{
412#ifdef VBOX_WS_WIN
413 /* It was necessary to have static pointer to created handler
414 * because windows keyboard-hook works only with static members: */
415 m_spKeyboardHandler = 0;
416#endif /* VBOX_WS_WIN */
417
418 /* Delete keyboard-handler: */
419 delete pKeyboardHandler;
420}
421
422/* Prepare listened objects: */
423void UIKeyboardHandler::prepareListener(ulong uScreenId, UIMachineWindow *pMachineWindow)
424{
425 /* If that window is NOT registered yet: */
426 if (!m_windows.contains(uScreenId))
427 {
428 /* Add window: */
429 m_windows.insert(uScreenId, pMachineWindow);
430 /* Install event-filter for window: */
431 m_windows[uScreenId]->installEventFilter(this);
432 }
433
434 /* If that view is NOT registered yet: */
435 if (!m_views.contains(uScreenId))
436 {
437 /* Add view: */
438 m_views.insert(uScreenId, pMachineWindow->machineView());
439 /* Install event-filter for view: */
440 m_views[uScreenId]->installEventFilter(this);
441 }
442}
443
444/* Cleanup listened objects: */
445void UIKeyboardHandler::cleanupListener(ulong uScreenId)
446{
447 /* Check if we should release keyboard first: */
448 if ((int)uScreenId == m_iKeyboardCaptureViewIndex)
449 releaseKeyboard();
450
451 /* If window still registered: */
452 if (m_windows.contains(uScreenId))
453 {
454 /* Remove window: */
455 m_windows.remove(uScreenId);
456 }
457
458 /* If view still registered: */
459 if (m_views.contains(uScreenId))
460 {
461 /* Remove view: */
462 m_views.remove(uScreenId);
463 }
464}
465
466void UIKeyboardHandler::captureKeyboard(ulong uScreenId)
467{
468 /* Do NOT capture the keyboard if it is already captured: */
469 if (m_fKeyboardCaptured)
470 {
471 /* Make sure the right screen had captured the keyboard: */
472 Assert((int)uScreenId == m_iKeyboardCaptureViewIndex);
473 return;
474 }
475
476 /* If the view exists: */
477 if (m_views.contains(uScreenId))
478 {
479 /* Remember which screen wishes to capture the keyboard: */
480 m_iKeyboardCaptureViewIndex = uScreenId;
481
482 /* On X11, we do not grab the keyboard as soon as it is captured, but delay it
483 * for 300 milliseconds after the formal capture. We do this for several reasons:
484 * - First, when several windows are created they all try to capture the keyboard when
485 * they get the focus. Due to the asynchronous nature of X11 the first window may only
486 * gets notified after the last is created, and there is a dance if they respond to
487 * the notifications by grabbing the keyboard and trigger new focus changes in the process.
488 * - Second, grabbing the keyboard immediately on focus change upsets some window managers,
489 * they give us the focus then try to grab the keyboard themselves, and sulk if they fail
490 * by refusing to e.g. drag a window using its title bar.
491 *
492 * IMPORTANT! We do the same under all other hosts as well mainly to have the
493 * common behavior everywhere while X11 is forced to behave that way. */
494 QTimer::singleShot(300, this, SLOT(sltFinaliseCaptureKeyboard()));
495 }
496}
497
498bool UIKeyboardHandler::finaliseCaptureKeyboard()
499{
500 /* Do NOT capture the keyboard if it is already captured: */
501 if (m_fKeyboardCaptured)
502 return true;
503
504 /* Make sure capture was really requested: */
505 if (m_iKeyboardCaptureViewIndex == -1)
506 return true;
507
508 /* If the view exists: */
509 if (m_views.contains(m_iKeyboardCaptureViewIndex))
510 {
511#if defined(VBOX_WS_MAC)
512
513 /* On Mac, keyboard grabbing is ineffective, a low-level keyboard-hook is used instead.
514 * It is being installed on focus-in event and uninstalled on focus-out.
515 * S.a. UIKeyboardHandler::eventFilter for more information. */
516
517 /* Besides that, we are not just using the Qt stuff to grab the keyboard,
518 * we also disable global hot keys and enable watching
519 * modifiers (for right/left separation). */
520 /// @todo Is that really needed?
521 ::DarwinDisableGlobalHotKeys(true);
522 m_views[m_iKeyboardCaptureViewIndex]->grabKeyboard();
523
524#elif defined(VBOX_WS_WIN)
525
526 /* On Win, keyboard grabbing is ineffective, a low-level keyboard-hook is used instead.
527 * It is being installed on focus-in event and uninstalled on focus-out.
528 * S.a. UIKeyboardHandler::eventFilter for more information. */
529
530#elif defined(VBOX_WS_NIX)
531 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
532 {
533 /* On X11, we are using XCB stuff to grab the keyboard.
534 * This stuff is a part of the active keyboard grabbing functionality.
535 * Active keyboard grabbing causes a problems on many window managers - a window cannot
536 * be moved using the mouse. So we additionally grab the mouse buttons as well to detect
537 * that the user is trying to click outside of the internal window geometry and release
538 * the keyboard before the target window sees the click. (GNOME Shell's hot corner has
539 * the same problem. At present we just let that problem be.) */
540
541 /* Make sure we really do still have the focus. Qt as of version 5.13 started
542 * reporting it with delay, so ask the X server directly. We could remove the
543 * version check some time in the future. If we do, remove the comment above
544 * about the focus notification dance, as it will no longer be relevant. */
545 xcb_get_input_focus_cookie_t xcbFocusCookie = xcb_get_input_focus(NativeWindowSubsystem::X11GetConnection());
546 xcb_get_input_focus_reply_t *pFocusReply = xcb_get_input_focus_reply(NativeWindowSubsystem::X11GetConnection(),
547 xcbFocusCookie, 0);
548 xcb_window_t xcbFocusWindow = pFocusReply->focus;
549 free(pFocusReply);
550 if (xcbFocusWindow != m_windows[m_iKeyboardCaptureViewIndex]->winId())
551 return true;
552
553 /* Grab the mouse button.
554 * We do not check for failure as we do not currently implement a back-up plan. */
555 /* If any previous grab is still in process, release it. */
556 if (m_hButtonGrabWindow != 0)
557 xcb_ungrab_button_checked(NativeWindowSubsystem::X11GetConnection(), XCB_BUTTON_INDEX_ANY,
558 m_hButtonGrabWindow, XCB_MOD_MASK_ANY);
559 m_hButtonGrabWindow = NativeWindowSubsystem::X11GetAppRootWindow();
560 xcb_grab_button_checked(NativeWindowSubsystem::X11GetConnection(), 0, m_hButtonGrabWindow,
561 XCB_EVENT_MASK_BUTTON_PRESS, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC,
562 XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, XCB_MOD_MASK_ANY);
563 /* And grab the keyboard, using XCB directly, as Qt does not report failure. */
564 xcb_grab_keyboard_cookie_t xcbGrabCookie = xcb_grab_keyboard(NativeWindowSubsystem::X11GetConnection(), false,
565 m_views[m_iKeyboardCaptureViewIndex]->winId(),
566 XCB_TIME_CURRENT_TIME, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
567 xcb_grab_keyboard_reply_t *pGrabReply = xcb_grab_keyboard_reply(NativeWindowSubsystem::X11GetConnection(),
568 xcbGrabCookie, NULL);
569 if (pGrabReply == NULL || pGrabReply->status != XCB_GRAB_STATUS_SUCCESS)
570 {
571 /* Release the mouse button grab.
572 * We do not check for failure as we do not currently implement a back-up plan. */
573 xcb_ungrab_button_checked(NativeWindowSubsystem::X11GetConnection(), XCB_BUTTON_INDEX_ANY,
574 m_hButtonGrabWindow, XCB_MOD_MASK_ANY);
575 m_hButtonGrabWindow = 0;
576 /* Try again later: */
577 free(pGrabReply);
578 return false;
579 }
580 free(pGrabReply);
581 }
582#else
583
584 /* On other platforms we are just praying Qt method to work: */
585 m_views[m_iKeyboardCaptureViewIndex]->grabKeyboard();
586
587#endif
588
589 /* Store new keyboard-captured state value: */
590 m_fKeyboardCaptured = true;
591
592 /* Notify all the listeners: */
593 emit sigStateChange(state());
594
595 return true;
596 }
597
598 return false;
599}
600
601void UIKeyboardHandler::releaseKeyboard()
602{
603 /* Do NOT release the keyboard if it is already released: */
604 if (!m_fKeyboardCaptured)
605 {
606 /* If a delayed capture is scheduled then cancel it: */
607 m_iKeyboardCaptureViewIndex = -1;
608 return;
609 }
610
611 /* If the view exists: */
612 if (m_views.contains(m_iKeyboardCaptureViewIndex))
613 {
614#if defined(VBOX_WS_MAC)
615
616 /* On Mac, keyboard grabbing is ineffective, a low-level keyboard-hook is used instead.
617 * It is being installed on focus-in event and uninstalled on focus-out.
618 * S.a. UIKeyboardHandler::eventFilter for more information. */
619
620 /* Besides that, we are not just using the Qt stuff to ungrab the keyboard,
621 * we also enable global hot keys and disable watching
622 * modifiers (for right/left separation). */
623 /// @todo Is that really needed?
624 ::DarwinDisableGlobalHotKeys(false);
625 m_views[m_iKeyboardCaptureViewIndex]->releaseKeyboard();
626
627#elif defined(VBOX_WS_WIN)
628
629 /* On Win, keyboard grabbing is ineffective, a low-level keyboard-hook is used instead.
630 * It is being installed on focus-in event and uninstalled on focus-out.
631 * S.a. UIKeyboardHandler::eventFilter for more information. */
632
633#elif defined(VBOX_WS_NIX)
634 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
635 {
636 /* On X11, we are using XCB stuff to grab the keyboard.
637 * This stuff is a part of the active keyboard grabbing functionality.
638 * Active keyboard grabbing causes a problems on many window managers - a window cannot
639 * be moved using the mouse. So we finally releasing additionally grabbed mouse as well
640 * to allow further user interactions. */
641
642 /* Ungrab using XCB: */
643 xcb_ungrab_keyboard(NativeWindowSubsystem::X11GetConnection(), XCB_TIME_CURRENT_TIME);
644 /* Release the mouse button grab.
645 * We do not check for failure as we do not currently implement a back-up plan. */
646 xcb_ungrab_button_checked(NativeWindowSubsystem::X11GetConnection(), XCB_BUTTON_INDEX_ANY,
647 m_hButtonGrabWindow, XCB_MOD_MASK_ANY);
648 m_hButtonGrabWindow = 0;
649 }
650#else
651
652 /* On other platforms we are just praying Qt method to work: */
653 m_views[m_iKeyboardCaptureViewIndex]->releaseKeyboard();
654
655#endif
656
657 /* Forget which screen had captured the keyboard: */
658 m_iKeyboardCaptureViewIndex = -1;
659
660 /* Store new keyboard-captured state value: */
661 m_fKeyboardCaptured = false;
662
663 /* Notify all the listeners: */
664 emit sigStateChange(state());
665 }
666}
667
668void UIKeyboardHandler::releaseAllPressedKeys(bool aReleaseHostKey /* = true */)
669{
670 bool fSentRESEND = false;
671
672 /* Send a dummy modifier sequence to prevent the guest OS from recognizing
673 * a single key click (for ex., Alt) and performing an unwanted action
674 * (for ex., activating the menu) when we release all pressed keys below.
675 * This is just a work-around and is likely to fail in some cases. We are
676 * not aware of any ideal solution. Historically we sent an 0xFE scan code,
677 * but this is a real key release code on Brazilian keyboards. Now we send
678 * a sequence of all modifier keys contained in the host sequence, hoping
679 * that the user will choose something which the guest does not interpret. */
680 for (uint i = 0; i < RT_ELEMENTS(m_pressedKeys); i++)
681 {
682 if ((m_pressedKeys[i] & IsKeyPressed) || (m_pressedKeys[i] & IsExtKeyPressed))
683 {
684 if (!fSentRESEND)
685 {
686 QList <unsigned> shortCodes = UIHostCombo::modifiersToScanCodes(gEDataManager->hostKeyCombination());
687 QVector <LONG> codes;
688 foreach (unsigned idxCode, shortCodes)
689 {
690 if (idxCode & 0x100)
691 codes << 0xE0;
692 codes << (idxCode & 0x7F);
693 m_pressedKeys[idxCode & 0x7F] &= idxCode & 0x100 ? ~IsExtKeyPressed : ~IsKeyPressed;
694 }
695 foreach (unsigned idxCode, shortCodes)
696 {
697 if (idxCode & 0x100)
698 codes << 0xE0;
699 codes << ((idxCode & 0x7F) | 0x80);
700 }
701 uimachine()->putScancodes(codes);
702 fSentRESEND = true;
703 }
704 if (m_pressedKeys[i] & IsKeyPressed)
705 uimachine()->putScancode(i | 0x80);
706 else
707 {
708 QVector <LONG> codes(2);
709 codes[0] = 0xE0;
710 codes[1] = i | 0x80;
711 uimachine()->putScancodes(codes);
712 }
713 }
714 m_pressedKeys[i] = 0;
715 }
716
717 if (aReleaseHostKey)
718 {
719 m_fHostComboPressed = false;
720 m_pressedHostComboKeys.clear();
721 }
722
723#ifdef VBOX_WS_MAC
724 unsigned int hostComboModifierMask = 0;
725 QList<int> hostCombo = UIHostCombo::toKeyCodeList(gEDataManager->hostKeyCombination());
726 for (int i = 0; i < hostCombo.size(); ++i)
727 hostComboModifierMask |= ::DarwinKeyCodeToDarwinModifierMask(hostCombo.at(i));
728 /* Clear most of the modifiers: */
729 m_uDarwinKeyModifiers &=
730 alphaLock | kEventKeyModifierNumLockMask |
731 (aReleaseHostKey ? 0 : hostComboModifierMask);
732#endif /* VBOX_WS_MAC */
733
734 /* Notify all the listeners: */
735 emit sigStateChange(state());
736}
737
738/* Current keyboard state: */
739int UIKeyboardHandler::state() const
740{
741 return uimachine()->machineState() == KMachineState_Null ? UIKeyboardStateType_KeyboardUnavailable :
742 UIKeyboardStateType_KeyboardAvailable |
743 (m_fKeyboardCaptured ? UIKeyboardStateType_KeyboardCaptured : 0) |
744 (m_fHostComboPressed ? UIKeyboardStateType_HostKeyPressed : 0) |
745 (m_fHostKeyComboPressInserted ? UIKeyboardStateType_HostKeyPressedInsertion : 0);
746}
747
748#ifdef VBOX_WITH_DEBUGGER_GUI
749void UIKeyboardHandler::setDebuggerActive(bool aActive /* = true*/)
750{
751 if (aActive)
752 {
753 m_fDebuggerActive = true;
754 releaseKeyboard();
755 }
756 else
757 m_fDebuggerActive = false;
758}
759
760#endif /* VBOX_WITH_DEBUGGER_GUI */
761
762#ifdef VBOX_WS_WIN
763void UIKeyboardHandler::winSkipKeyboardEvents(bool fSkip)
764{
765 m_fSkipKeyboardEvents = fSkip;
766}
767#endif /* VBOX_WS_WIN */
768
769bool UIKeyboardHandler::nativeEventFilter(void *pMessage, ulong uScreenId)
770{
771 /* Make sure view with passed index exists: */
772 if (!m_views.contains(uScreenId))
773 return false;
774
775 /* Check if some system event should be filtered out.
776 * Returning @c true means filtering-out,
777 * Returning @c false means passing event to Qt. */
778 bool fResult = false; /* Pass to Qt by default. */
779
780# if defined(VBOX_WS_MAC)
781
782 /* Acquire carbon event reference from the cocoa one: */
783 EventRef event = static_cast<EventRef>(darwinCocoaToCarbonEvent(pMessage));
784
785 /* Depending on event kind: */
786 const UInt32 uEventKind = ::GetEventKind(event);
787 switch (uEventKind)
788 {
789 /* Watch for simple key-events: */
790 case kEventRawKeyDown:
791 case kEventRawKeyRepeat:
792 case kEventRawKeyUp:
793 {
794 /* Acquire keycode: */
795 UInt32 uKeyCode = ~0U;
796 ::GetEventParameter(event, kEventParamKeyCode, typeUInt32,
797 NULL, sizeof(uKeyCode), NULL, &uKeyCode);
798
799 /* The usb keyboard driver translates these codes to different virtual
800 * keycodes depending of the keyboard type. There are ANSI, ISO, JIS
801 * and unknown. For European keyboards (ISO) the key 0xa and 0x32 have
802 * to be switched. Here we are doing this at runtime, cause the user
803 * can have more than one keyboard (of different type), where he may
804 * switch at will all the time. Default is the ANSI standard as defined
805 * in g_aDarwinToSet1. Please note that the "~" on some English ISO
806 * keyboards will be wrongly swapped. This can maybe fixed by
807 * using a Apple keyboard layout in the guest. */
808 if ( (uKeyCode == 0xa || uKeyCode == 0x32)
809 && KBGetLayoutType(LMGetKbdType()) == kKeyboardISO)
810 uKeyCode = 0x3c - uKeyCode;
811
812 /* Translate keycode to set 1 scan code: */
813 unsigned uScanCode = ::DarwinKeycodeToSet1Scancode(uKeyCode);
814
815 /* If scan code is valid: */
816 if (uScanCode)
817 {
818 /* Calculate flags: */
819 int iFlags = 0;
820 if (uEventKind != kEventRawKeyUp)
821 iFlags |= KeyPressed;
822 if (uScanCode & VBOXKEY_EXTENDED)
823 iFlags |= KeyExtended;
824 /** @todo KeyPause, KeyPrint. */
825 uScanCode &= VBOXKEY_SCANCODE_MASK;
826
827 /* Get the unicode string (if present): */
828 AssertCompileSize(wchar_t, 2);
829 AssertCompileSize(UniChar, 2);
830 ByteCount cbWritten = 0;
831 wchar_t ucs[8];
832 if (::GetEventParameter(event, kEventParamKeyUnicodes, typeUnicodeText,
833 NULL, sizeof(ucs), &cbWritten, &ucs[0]) != 0)
834 cbWritten = 0;
835 ucs[cbWritten / sizeof(wchar_t)] = 0; /* The api doesn't terminate it. */
836
837 /* Finally, handle parsed key-event: */
838 fResult = keyEvent(uKeyCode, uScanCode, iFlags, uScreenId, ucs[0] ? ucs : NULL);
839 }
840
841 break;
842 }
843 /* Watch for modifier key-events: */
844 case kEventRawKeyModifiersChanged:
845 {
846 /* Acquire new modifier mask, it may contain
847 * multiple modifier changes, kind of annoying: */
848 UInt32 uNewMask = 0;
849 ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32,
850 NULL, sizeof(uNewMask), NULL, &uNewMask);
851
852 /* Adjust new modifier mask to distinguish left/right modifiers: */
853 uNewMask = ::DarwinAdjustModifierMask(uNewMask, pMessage);
854
855 /* Determine what is really changed: */
856 const UInt32 changed = uNewMask ^ m_uDarwinKeyModifiers;
857 if (changed)
858 {
859 for (UInt32 bit = 0; bit < 32; ++bit)
860 {
861 /* Skip unchanged bits: */
862 if (!(changed & (1 << bit)))
863 continue;
864 /* Acquire set 1 scan code from new mask: */
865 unsigned uScanCode = ::DarwinModifierMaskToSet1Scancode(1 << bit);
866 /* Skip invalid scan codes: */
867 if (!uScanCode)
868 continue;
869 /* Acquire darwin keycode from new mask: */
870 unsigned uKeyCode = ::DarwinModifierMaskToDarwinKeycode(1 << bit);
871 /* Assert invalid keycodes: */
872 Assert(uKeyCode);
873
874 /* For non-lockable modifier: */
875 if (!(uScanCode & VBOXKEY_LOCK))
876 {
877 /* Calculate flags: */
878 unsigned uFlags = (uNewMask & (1 << bit)) ? KeyPressed : 0;
879 if (uScanCode & VBOXKEY_EXTENDED)
880 uFlags |= KeyExtended;
881 uScanCode &= VBOXKEY_SCANCODE_MASK;
882
883 /* Finally, handle parsed key-event: */
884 keyEvent(uKeyCode, uScanCode & 0xff, uFlags, uScreenId);
885 }
886 /* For lockable modifier: */
887 else
888 {
889 /* Calculate flags: */
890 unsigned uFlags = 0;
891 if (uScanCode & VBOXKEY_EXTENDED)
892 uFlags |= KeyExtended;
893 uScanCode &= VBOXKEY_SCANCODE_MASK;
894
895 /* Finally, handle parsed press/release pair: */
896 keyEvent(uKeyCode, uScanCode, uFlags | KeyPressed, uScreenId);
897 keyEvent(uKeyCode, uScanCode, uFlags, uScreenId);
898 }
899 }
900 }
901
902 /* Remember new modifier mask: */
903 m_uDarwinKeyModifiers = uNewMask;
904
905 /* Always return true here because we'll otherwise getting a Qt event
906 * we don't want and that will only cause the Pause warning to pop up: */
907 fResult = true;
908
909 break;
910 }
911 default:
912 break;
913 }
914
915# elif defined(VBOX_WS_WIN)
916
917 /* Ignore this event if m_fSkipKeyboardEvents is set by winSkipKeyboardEvents(). */
918 if (m_fSkipKeyboardEvents)
919 return false;
920
921 /* Cast to MSG event: */
922 MSG *pMsg = static_cast<MSG*>(pMessage);
923
924 /* Depending on message type: */
925 switch (pMsg->message)
926 {
927 /* Watch for key-events: */
928 case WM_KEYDOWN:
929 case WM_KEYUP:
930 case WM_SYSKEYDOWN:
931 case WM_SYSKEYUP:
932 {
933 // WORKAROUND:
934 // Can't do COM inter-process calls from a SendMessage handler,
935 // see http://support.microsoft.com/kb/131056.
936 if (uiCommon().isSeparateProcess() && InSendMessage())
937 {
938 PostMessage(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
939 fResult = true;
940 break;
941 }
942
943 /* Check for our own special flag to ignore this event.
944 * That flag could only be set later in this function
945 * so having it here means this event came here
946 * for the second time already. */
947 if (pMsg->lParam & (0x1 << 25))
948 {
949 /* Remove that flag as well: */
950 pMsg->lParam &= ~(0x1 << 25);
951 fResult = false;
952 break;
953 }
954
955 /* Scan codes 0x80 and 0x00 should be filtered out: */
956 unsigned uScan = (pMsg->lParam >> 16) & 0x7F;
957 if (!uScan)
958 {
959 fResult = true;
960 break;
961 }
962
963 /* Get the virtual key: */
964 int iVKey = pMsg->wParam;
965
966 /* Calculate flags: */
967 int iFlags = 0;
968 if (pMsg->lParam & 0x1000000)
969 iFlags |= KeyExtended;
970 if (!(pMsg->lParam & 0x80000000))
971 iFlags |= KeyPressed;
972
973 /* Make sure AltGr monitor exists: */
974 AssertPtrReturn(m_pAltGrMonitor, false);
975 {
976 /* Filter event out if we are sure that this is a fake left control event: */
977 if (m_pAltGrMonitor->isCurrentEventDefinitelyFake(uScan, iFlags & KeyPressed, iFlags & KeyExtended))
978 {
979 fResult = true;
980 break;
981 }
982 /* Update AltGR monitor state from key-event: */
983 m_pAltGrMonitor->updateStateFromKeyEvent(uScan, iFlags & KeyPressed, iFlags & KeyExtended);
984 /* And release left Ctrl key early (if required): */
985 if (m_pAltGrMonitor->isLeftControlReleaseNeeded())
986 uimachine()->putScancode(0x1D | 0x80);
987 }
988
989 /* Check for special Korean keys. Based on the keyboard layout selected
990 * on the host, the scan code in lParam might be 0x71/0x72 or 0xF1/0xF2.
991 * In either case, we must deliver 0xF1/0xF2 scan code to the guest when
992 * the key is pressed and nothing when it's released. */
993 if (uScan == 0x71 || uScan == 0x72)
994 {
995 uScan |= 0x80;
996 iFlags = KeyPressed; /* Because a release would be ignored. */
997 iVKey = VK_PROCESSKEY; /* In case it was 0xFF. */
998 }
999
1000 /* When one of the SHIFT keys is held and one of the cursor movement
1001 * keys is pressed, Windows duplicates SHIFT press/release messages,
1002 * but with the virtual keycode set to 0xFF. These virtual keys are also
1003 * sent in some other situations (Pause, PrtScn, etc.). Filter out such messages. */
1004 if (iVKey == 0xFF)
1005 {
1006 fResult = true;
1007 break;
1008 }
1009
1010 /* Handle special virtual keys: */
1011 switch (iVKey)
1012 {
1013 case VK_SHIFT:
1014 case VK_CONTROL:
1015 case VK_MENU:
1016 {
1017 /* Overcome Win32 modifier key generalization: */
1018 int iKeyscan = uScan;
1019 if (iFlags & KeyExtended)
1020 iKeyscan |= 0xE000;
1021 switch (iKeyscan)
1022 {
1023 case 0x002A: iVKey = VK_LSHIFT; break;
1024 case 0x0036: iVKey = VK_RSHIFT; break;
1025 case 0x001D: iVKey = VK_LCONTROL; break;
1026 case 0xE01D: iVKey = VK_RCONTROL; break;
1027 case 0x0038: iVKey = VK_LMENU; break;
1028 case 0xE038: iVKey = VK_RMENU; break;
1029 }
1030 break;
1031 }
1032 case VK_NUMLOCK:
1033 /* Win32 sets the extended bit for the NumLock key. Reset it: */
1034 iFlags &= ~KeyExtended;
1035 break;
1036 case VK_SNAPSHOT:
1037 iFlags |= KeyPrint;
1038 break;
1039 case VK_PAUSE:
1040 iFlags |= KeyPause;
1041 break;
1042 }
1043
1044 /* Finally, handle parsed key-event: */
1045 fResult = keyEvent(iVKey, uScan, iFlags, uScreenId);
1046
1047 /* Always let Windows see key releases to prevent stuck keys.
1048 * Hopefully this won't cause any other issues. */
1049 if (pMsg->message == WM_KEYUP || pMsg->message == WM_SYSKEYUP)
1050 {
1051 fResult = false;
1052 break;
1053 }
1054
1055 /* Above keyEvent() returned that it didn't processed the event, but since the
1056 * keyboard is captured, we don't want to pass it to Windows. We just want
1057 * to let Qt process the message (to handle non-alphanumeric <HOST>+key
1058 * shortcuts for example). So send it directly to the window with the
1059 * special flag in the reserved area of lParam (to avoid recursion). */
1060 if (!fResult && m_fKeyboardCaptured)
1061 {
1062 ::SendMessage(pMsg->hwnd, pMsg->message,
1063 pMsg->wParam, pMsg->lParam | (0x1 << 25));
1064 fResult = true;
1065 break;
1066 }
1067
1068 /* These special keys have to be handled by Windows as well to update the
1069 * internal modifier state and to enable/disable the keyboard LED: */
1070 if (iVKey == VK_NUMLOCK || iVKey == VK_CAPITAL || iVKey == VK_LSHIFT || iVKey == VK_RSHIFT)
1071 {
1072 fResult = false;
1073 break;
1074 }
1075
1076 break;
1077 }
1078 default:
1079 break;
1080 }
1081
1082# elif defined(VBOX_WS_NIX)
1083 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
1084 {
1085 /* Cast to XCB event: */
1086 xcb_generic_event_t *pEvent = static_cast<xcb_generic_event_t*>(pMessage);
1087
1088 /* Depending on event type: */
1089 switch (pEvent->response_type & ~0x80)
1090 {
1091 /* Watch for key-events: */
1092 case XCB_KEY_PRESS:
1093 case XCB_KEY_RELEASE:
1094 {
1095 /* Cast to XCB key-event: */
1096 xcb_key_press_event_t *pKeyEvent = static_cast<xcb_key_press_event_t*>(pMessage);
1097
1098 /* Translate the keycode to a PC scan code: */
1099 unsigned uScan = handleXKeyEvent(NativeWindowSubsystem::X11GetDisplay(), pKeyEvent->detail);
1100
1101 /* Scan codes 0x00 (no valid translation) and 0x80 (extended flag) are ignored: */
1102 if (!(uScan & 0x7F))
1103 {
1104 fResult = true;
1105 break;
1106 }
1107
1108 /* Calculate flags: */
1109 int iflags = 0;
1110 if (uScan >> 8)
1111 iflags |= KeyExtended;
1112 if ((pEvent->response_type & ~0x80) == XCB_KEY_PRESS)
1113 iflags |= KeyPressed;
1114
1115 /* Remove the extended flag: */
1116 uScan &= 0x7F;
1117
1118 /* Special Korean keys must send scan code 0xF1/0xF2
1119 * when pressed and nothing when released. */
1120 if (uScan == 0x71 || uScan == 0x72)
1121 {
1122 if ((pEvent->response_type & ~0x80) == XCB_KEY_RELEASE)
1123 {
1124 fResult = true;
1125 break;
1126 }
1127 /* Re-create the bizarre scan code: */
1128 uScan |= 0x80;
1129 }
1130
1131 /* Translate the keycode to a keysym: */
1132 KeySym ks = ::wrapXkbKeycodeToKeysym(NativeWindowSubsystem::X11GetDisplay(), pKeyEvent->detail, 0, 0);
1133
1134 /* Update special flags: */
1135 switch (ks)
1136 {
1137 case XK_Print:
1138 iflags |= KeyPrint;
1139 break;
1140 case XK_Pause:
1141 if (pKeyEvent->state & ControlMask) /* Break */
1142 {
1143 ks = XK_Break;
1144 iflags |= KeyExtended;
1145 uScan = 0x46;
1146 }
1147 else
1148 iflags |= KeyPause;
1149 break;
1150 }
1151
1152 /* Finally, handle parsed key-event: */
1153 fResult = keyEvent(ks, uScan, iflags, uScreenId);
1154
1155 break;
1156 }
1157 default:
1158 break;
1159 }
1160 }
1161
1162# else
1163
1164# warning "port me!"
1165
1166# endif
1167
1168 /* Return result: */
1169 return fResult;
1170}
1171
1172/* Machine state-change handler: */
1173void UIKeyboardHandler::sltMachineStateChanged()
1174{
1175 /* Get cached machine states: */
1176 const KMachineState enmState = uimachine()->machineState();
1177
1178 /* Notify all the listeners that machine state was [de]initialized: */
1179 if ( enmState == KMachineState_Null
1180 || enmState == KMachineState_Starting)
1181 emit sigStateChange(state());
1182
1183 /* Handle particular machine states: */
1184 switch (enmState)
1185 {
1186 case KMachineState_Paused:
1187 case KMachineState_TeleportingPausedVM:
1188 case KMachineState_Stuck:
1189 {
1190 /* Release the keyboard: */
1191 releaseKeyboard();
1192 /* And all pressed keys except the host-one : */
1193 releaseAllPressedKeys(false /* release host-key? */);
1194 break;
1195 }
1196 case KMachineState_Running:
1197 {
1198 /* Capture the keyboard by the first focused view: */
1199 QList<ulong> theListOfViewIds = m_views.keys();
1200 for (int i = 0; i < theListOfViewIds.size(); ++i)
1201 {
1202 if (viewHasFocus(theListOfViewIds[i]))
1203 {
1204 /* Capture keyboard: */
1205#ifdef VBOX_WS_WIN
1206 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally() &&
1207 GetAncestor((HWND)m_views[theListOfViewIds[i]]->winId(), GA_ROOT) == GetForegroundWindow())
1208#else /* !VBOX_WS_WIN */
1209 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally())
1210#endif /* !VBOX_WS_WIN */
1211 captureKeyboard(theListOfViewIds[i]);
1212 /* Reset the single-time disable capture flag: */
1213 if (isAutoCaptureDisabled())
1214 setAutoCaptureDisabled(false);
1215 break;
1216 }
1217 }
1218 break;
1219 }
1220 default:
1221 break;
1222 }
1223
1224 /* Recall reminder about paused VM input
1225 * if we are not in paused VM state already: */
1226 if (machineLogic()->activeMachineWindow() &&
1227 enmState != KMachineState_Paused &&
1228 enmState != KMachineState_TeleportingPausedVM)
1229 UINotificationMessage::forgetAboutPausedVMInput();
1230}
1231
1232void UIKeyboardHandler::sltFinaliseCaptureKeyboard()
1233{
1234 /* Try to finalise keyboard capture: */
1235 if (!finaliseCaptureKeyboard())
1236 {
1237 /* Try again in another 300 milliseconds in case of failure: */
1238 QTimer::singleShot(300, this, SLOT(sltFinaliseCaptureKeyboard()));
1239 }
1240}
1241
1242/* Keyboard-handler constructor: */
1243UIKeyboardHandler::UIKeyboardHandler(UIMachineLogic *pMachineLogic)
1244 : QObject(pMachineLogic)
1245 , m_pMachineLogic(pMachineLogic)
1246 , m_iKeyboardCaptureViewIndex(-1)
1247 , m_fKeyboardCaptured(false)
1248 , m_fHostComboPressed(false)
1249 , m_bIsHostComboAlone(false)
1250 , m_bIsHostComboProcessed(false)
1251 , m_fPassCADtoGuest(false)
1252 , m_fHostKeyComboPressInserted(false)
1253 , m_fDebuggerActive(false)
1254 , m_iKeyboardHookViewIndex(-1)
1255#if defined(VBOX_WS_MAC)
1256 , m_uDarwinKeyModifiers(0)
1257#elif defined(VBOX_WS_WIN)
1258 , m_fIsHostkeyInCapture(false)
1259 , m_fSkipKeyboardEvents(false)
1260 , m_keyboardHook(NULL)
1261 , m_pAltGrMonitor(0)
1262#elif defined(VBOX_WS_NIX)
1263 , m_hButtonGrabWindow(0)
1264#endif /* VBOX_WS_NIX */
1265{
1266 /* Prepare: */
1267 prepareCommon();
1268
1269 /* Load settings: */
1270 loadSettings();
1271
1272 /* Initialize: */
1273 sltMachineStateChanged();
1274}
1275
1276/* Keyboard-handler destructor: */
1277UIKeyboardHandler::~UIKeyboardHandler()
1278{
1279 /* Cleanup: */
1280 cleanupCommon();
1281}
1282
1283void UIKeyboardHandler::prepareCommon()
1284{
1285#ifdef VBOX_WS_WIN
1286 /* Prepare AltGR monitor: */
1287 m_pAltGrMonitor = new WinAltGrMonitor;
1288#endif /* VBOX_WS_WIN */
1289
1290 /* Machine state-change updater: */
1291 connect(uimachine(), &UIMachine::sigMachineStateChange, this, &UIKeyboardHandler::sltMachineStateChanged);
1292
1293 /* Pressed keys: */
1294 ::memset(m_pressedKeys, 0, sizeof(m_pressedKeys));
1295 ::memset(m_pressedKeysCopy, 0, sizeof(m_pressedKeysCopy));
1296}
1297
1298void UIKeyboardHandler::loadSettings()
1299{
1300 /* Global settings: */
1301#ifdef VBOX_WS_NIX
1302 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
1303 {
1304 /* Initialize the X keyboard subsystem: */
1305 initMappedX11Keyboard(NativeWindowSubsystem::X11GetDisplay(), gEDataManager->remappedScanCodes());
1306 /* Fix for http://www.virtualbox.org/ticket/1296:
1307 * when X11 sends events for repeated keys, it always inserts an XKeyRelease
1308 * before the XKeyPress. */
1309 /* Disable key release events during key auto-repeat: */
1310 XkbSetDetectableAutoRepeat(NativeWindowSubsystem::X11GetDisplay(), True, NULL);
1311 }
1312#endif /* VBOX_WS_NIX */
1313
1314 /* Extra data settings: */
1315 {
1316 /* CAD setting: */
1317 m_fPassCADtoGuest = gEDataManager->passCADtoGuest(uiCommon().managedVMUuid());
1318 }
1319}
1320
1321void UIKeyboardHandler::cleanupCommon()
1322{
1323#if defined(VBOX_WS_MAC)
1324
1325 /* Cleanup keyboard-hook: */
1326 if (m_iKeyboardHookViewIndex != -1)
1327 {
1328 /* Ungrab the keyboard and unregister the event callback/hook: */
1329 ::DarwinReleaseKeyboard();
1330 UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */,
1331 UIKeyboardHandler::macKeyboardProc, this);
1332 }
1333
1334#elif defined(VBOX_WS_WIN)
1335
1336 /* Cleanup AltGR monitor: */
1337 delete m_pAltGrMonitor;
1338 m_pAltGrMonitor = 0;
1339
1340 /* If keyboard-hook is installed: */
1341 if (m_keyboardHook)
1342 {
1343 /* Uninstall existing keyboard-hook: */
1344 UnhookWindowsHookEx(m_keyboardHook);
1345 m_keyboardHook = 0;
1346 }
1347
1348#endif /* VBOX_WS_WIN */
1349
1350 /* Update keyboard hook view index: */
1351 m_iKeyboardHookViewIndex = -1;
1352}
1353
1354UIActionPool *UIKeyboardHandler::actionPool() const
1355{
1356 return machineLogic()->actionPool();
1357}
1358
1359UIMachine *UIKeyboardHandler::uimachine() const
1360{
1361 return machineLogic()->uimachine();
1362}
1363
1364/* Event handler for prepared listener(s): */
1365bool UIKeyboardHandler::eventFilter(QObject *pWatchedObject, QEvent *pEvent)
1366{
1367 /* Check if pWatchedObject object is view: */
1368 if (UIMachineView *pWatchedView = isItListenedView(pWatchedObject))
1369 {
1370 /* Get corresponding screen index: */
1371 ulong uScreenId = m_views.key(pWatchedView);
1372 NOREF(uScreenId);
1373 /* Handle view events: */
1374 switch (pEvent->type())
1375 {
1376 case QEvent::FocusIn:
1377 {
1378#if defined(VBOX_WS_MAC)
1379
1380 /* If keyboard-hook is NOT installed;
1381 * Or installed but NOT for that view: */
1382 if ((int)uScreenId != m_iKeyboardHookViewIndex)
1383 {
1384 /* If keyboard-hook is NOT installed: */
1385 if (m_iKeyboardHookViewIndex == -1)
1386 {
1387 /* Disable mouse and keyboard event compression/delaying
1388 * to make sure we *really* get all of the events: */
1389 ::CGSetLocalEventsSuppressionInterval(0.0); /** @todo replace with CGEventSourceSetLocalEventsSuppressionInterval ? */
1390 ::darwinSetMouseCoalescingEnabled(false);
1391
1392 /* Bring the caps lock state up to date,
1393 * otherwise e.g. a later Shift key press will accidentally inject a CapsLock key press and release,
1394 * see UIKeyboardHandler::macKeyboardEvent for the code handling modifier key state changes. */
1395 m_uDarwinKeyModifiers ^= (m_uDarwinKeyModifiers ^ ::GetCurrentEventKeyModifiers()) & alphaLock;
1396
1397 /* Register the event callback/hook and grab the keyboard: */
1398 UICocoaApplication::instance()->registerForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */,
1399 UIKeyboardHandler::macKeyboardProc, this);
1400 ::DarwinGrabKeyboard(false);
1401 }
1402 }
1403
1404#elif defined(VBOX_WS_WIN)
1405
1406 /* If keyboard-hook is NOT installed;
1407 * Or installed but NOT for that view
1408 * AND no --no-keyboard-grabbing option: */
1409 if ( (!m_keyboardHook || (int)uScreenId != m_iKeyboardHookViewIndex)
1410 && !uiCommon().shouldNotGrabKeyboard())
1411 {
1412 /* If keyboard-hook is installed: */
1413 if (m_keyboardHook)
1414 {
1415 /* Uninstall existing keyboard-hook: */
1416 UnhookWindowsHookEx(m_keyboardHook);
1417 m_keyboardHook = 0;
1418 }
1419 /* Install new keyboard-hook: */
1420 m_keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, UIKeyboardHandler::winKeyboardProc, GetModuleHandle(NULL), 0);
1421 AssertMsg(m_keyboardHook, ("SetWindowsHookEx(): err=%d", GetLastError()));
1422 }
1423
1424#endif /* VBOX_WS_WIN */
1425
1426 /* Update keyboard hook view index: */
1427 m_iKeyboardHookViewIndex = uScreenId;
1428
1429 if (isSessionRunning())
1430 {
1431 /* Capture keyboard: */
1432#ifdef VBOX_WS_WIN
1433 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally() &&
1434 GetAncestor((HWND)pWatchedView->winId(), GA_ROOT) == GetForegroundWindow())
1435#else /* !VBOX_WS_WIN */
1436 if (!isAutoCaptureDisabled() && autoCaptureSetGlobally())
1437#endif /* !VBOX_WS_WIN */
1438 captureKeyboard(uScreenId);
1439 /* Reset the single-time disable capture flag: */
1440 if (isAutoCaptureDisabled())
1441 setAutoCaptureDisabled(false);
1442 }
1443
1444 break;
1445 }
1446 case QEvent::FocusOut:
1447 {
1448 /* If host key combo press has been inserted (with no release yet) insert a release now: */
1449 if (m_fHostKeyComboPressInserted)
1450 machineLogic()->typeHostKeyComboPressRelease(false);
1451
1452#if defined(VBOX_WS_MAC)
1453
1454 /* If keyboard-hook is installed: */
1455 if ((int)uScreenId == m_iKeyboardHookViewIndex)
1456 {
1457 /* Ungrab the keyboard and unregister the event callback/hook: */
1458 ::DarwinReleaseKeyboard();
1459 UICocoaApplication::instance()->unregisterForNativeEvents(RT_BIT_32(10) | RT_BIT_32(11) | RT_BIT_32(12) /* NSKeyDown | NSKeyUp | | NSFlagsChanged */,
1460 UIKeyboardHandler::macKeyboardProc, this);
1461 }
1462
1463#elif defined(VBOX_WS_WIN)
1464
1465 /* If keyboard-hook is installed: */
1466 if (m_keyboardHook)
1467 {
1468 /* Uninstall existing keyboard-hook: */
1469 UnhookWindowsHookEx(m_keyboardHook);
1470 m_keyboardHook = 0;
1471 }
1472
1473#endif /* VBOX_WS_WIN */
1474
1475 /* Update keyboard hook view index: */
1476 m_iKeyboardHookViewIndex = -1;
1477
1478 /* Release keyboard: */
1479 if (isSessionRunning() || isSessionStuck())
1480 releaseKeyboard();
1481 /* And all pressed keys: */
1482 releaseAllPressedKeys(true);
1483
1484 break;
1485 }
1486 case QEvent::KeyPress:
1487 case QEvent::KeyRelease:
1488 {
1489 QKeyEvent *pKeyEvent = static_cast<QKeyEvent*>(pEvent);
1490
1491 if (m_fHostComboPressed && pEvent->type() == QEvent::KeyPress)
1492 {
1493 /* Passing F1-F12 keys to the guest: */
1494 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F12)
1495 {
1496 QVector <LONG> combo(6);
1497 combo[0] = 0x1d; /* Ctrl down */
1498 combo[1] = 0x38; /* Alt down */
1499 combo[4] = 0xb8; /* Alt up */
1500 combo[5] = 0x9d; /* Ctrl up */
1501 if (pKeyEvent->key() >= Qt::Key_F1 && pKeyEvent->key() <= Qt::Key_F10)
1502 {
1503 combo[2] = 0x3b + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 down */
1504 combo[3] = 0xbb + (pKeyEvent->key() - Qt::Key_F1); /* F1-F10 up */
1505 }
1506 /* There is some scan slice between F10 and F11 keys, so its separated: */
1507 else if (pKeyEvent->key() >= Qt::Key_F11 && pKeyEvent->key() <= Qt::Key_F12)
1508 {
1509 combo[2] = 0x57 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 down */
1510 combo[3] = 0xd7 + (pKeyEvent->key() - Qt::Key_F11); /* F11-F12 up */
1511 }
1512 uimachine()->putScancodes(combo);
1513 }
1514 /* Process hot keys not processed in keyEvent() (as in case of non-alphanumeric keys): */
1515 actionPool()->processHotKey(QKeySequence(pKeyEvent->key()));
1516 }
1517 else if (!m_fHostComboPressed && pEvent->type() == QEvent::KeyRelease)
1518 {
1519 /* Show a possible warning on key release which seems to be more expected by the end user: */
1520 if (uimachine()->isPaused())
1521 UINotificationMessage::remindAboutPausedVMInput();
1522 }
1523
1524 break;
1525 }
1526 default:
1527 break;
1528 }
1529 }
1530
1531 /* Else just propagate to base-class: */
1532 return QObject::eventFilter(pWatchedObject, pEvent);
1533}
1534
1535#if defined(VBOX_WS_MAC)
1536
1537/* static */
1538bool UIKeyboardHandler::macKeyboardProc(const void *pvCocoaEvent, const void *pvCarbonEvent, void *pvUser)
1539{
1540 /* Determine the event class: */
1541 EventRef event = (EventRef)pvCarbonEvent;
1542 UInt32 uEventClass = ::GetEventClass(event);
1543
1544 /* Check if this is an application key combo. In that case we will not pass
1545 * the event to the guest, but let the host process it. */
1546 if (::darwinIsApplicationCommand(pvCocoaEvent))
1547 return false;
1548
1549 /* Get the keyboard handler from the user's void data: */
1550 UIKeyboardHandler *pKeyboardHandler = static_cast<UIKeyboardHandler*>(pvUser);
1551
1552 /* All keyboard class events needs to be handled: */
1553 if (uEventClass == kEventClassKeyboard && pKeyboardHandler && pKeyboardHandler->macKeyboardEvent(pvCocoaEvent, event))
1554 return true;
1555
1556 /* Pass the event along: */
1557 return false;
1558}
1559
1560bool UIKeyboardHandler::macKeyboardEvent(const void *pvCocoaEvent, EventRef event)
1561{
1562 /* Check what related machine-view was NOT unregistered yet: */
1563 if (!m_views.contains(m_iKeyboardHookViewIndex))
1564 return false;
1565
1566 /* Pass event to machine-view's event handler: */
1567 Q_UNUSED(event);
1568 return nativeEventFilter(unconst(pvCocoaEvent), m_iKeyboardHookViewIndex);
1569}
1570
1571#elif defined(VBOX_WS_WIN)
1572
1573/* static */
1574LRESULT CALLBACK UIKeyboardHandler::winKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) RT_NOTHROW_DEF
1575{
1576 /* All keyboard class events needs to be handled: */
1577 if (nCode == HC_ACTION && m_spKeyboardHandler && m_spKeyboardHandler->winKeyboardEvent(wParam, *(KBDLLHOOKSTRUCT*)lParam))
1578 return 1;
1579
1580 /* Pass the event along: */
1581 return CallNextHookEx(NULL, nCode, wParam, lParam);
1582}
1583
1584bool UIKeyboardHandler::winKeyboardEvent(UINT msg, const KBDLLHOOKSTRUCT &event)
1585{
1586 /* Check that related machine-view was NOT unregistered yet: */
1587 if (!m_views.contains(m_iKeyboardHookViewIndex))
1588 return false;
1589
1590 /* HACK ALERT! Check that we're not in cleanup, as we're using gEDataManger
1591 to get host key combinations and it as probably been cleaned up already.
1592 We don't want to cause it to re-instantiate, with all the COM traffic
1593 that might involve. Sample assertion stack (IPRT not windbg, sorry):
1594
1595 !!Assertion Failed!!
1596 Expression: mRC != RPC_E_CANTCALLOUT_ININPUTSYNCCALL
1597 Location : E:\vbox\svn\trunk\out\win.amd64\debug\obj\UICommon\include\COMWrappers.cpp(3857) class QVector<class QString> __cdecl CVirtualBox::GetExtraDataKeys(void)
1598 Stack :
1599 00007fff39aa6634 VBoxRT.dll!RTAssertMsg1+0x274 (rva:0x246634)
1600 [E:\vbox\svn\trunk\src\VBox\Runtime\common\misc\assert.cpp:159]
1601 00007fff39aa542f VBoxRT.dll!RTAssertMsg1Weak+0x2f (rva:0x24542f)
1602 [E:\vbox\svn\trunk\src\VBox\Runtime\common\misc\RTAssertMsg1Weak.cpp:40 (+0x0)]
1603 00007fff36e5c00f UICommon.dll!CVirtualBox::GetExtraDataKeys+0x23f (rva:0x3fc00f)
1604 [E:\vbox\svn\trunk\out\win.amd64\debug\obj\UICommon\include\COMWrappers.cpp:3857]
1605 00007fff36ac2cc9 UICommon.dll!UIExtraDataManager::prepareGlobalExtraDataMap+0xb9 (rva:0x62cc9)
1606 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp:4845]
1607 00007fff36ac2bf8 UICommon.dll!UIExtraDataManager::prepare+0x28 (rva:0x62bf8)
1608 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp:4833 (+0x0)]
1609 00007fff36ab1896 UICommon.dll!UIExtraDataManager::instance+0x66 (rva:0x51896)
1610 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\extradata\UIExtraDataManager.cpp:2011 (+0x0)]
1611 00007ff771b05b06 VirtualBoxVM.exe!UIKeyboardHandler::winKeyboardEvent+0xe6 (rva:0x35b06)
1612 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\runtime\UIKeyboardHandler.cpp:1324]
1613 00007ff771b059ec VirtualBoxVM.exe!UIKeyboardHandler::winKeyboardProc+0x4c (rva:0x359ec)
1614 [E:\vbox\svn\trunk\src\VBox\Frontends\VirtualBox\src\runtime\UIKeyboardHandler.cpp:1304]
1615 00007fff763311f2 USER32.dll!GetDlgCtrlID+0x232 (rva:0x211f2)
1616 00007fff7639ac89 USER32.dll!CreateSystemThreads+0xa29 (rva:0x8ac89)
1617 00007fff76b30ba4 ntdll.dll!KiUserCallbackDispatcher+0x24 (rva:0xa0ba4)
1618 00007fff749b1064 win32u.dll!NtUserPeekMessage+0x14 (rva:0x1064)
1619 00007fff7631a553 USER32.dll!PeekMessageW+0x1e3 (rva:0xa553)
1620 00007fff7631a4b3 USER32.dll!PeekMessageW+0x143 (rva:0xa4b3)
1621 00007e11000270dc ConEmuHk64.dll!SetLoadLibraryCallback+0xc3ac (rva:0x270dc)
1622 00007fff759be71b combase.dll!CoRegisterPSClsid+0x82b (rva:0x6e71b)
1623 00007fff759be685 combase.dll!CoRegisterPSClsid+0x795 (rva:0x6e685)
1624 00007fff759bcec1 combase.dll!Ordinal87+0x2851 (rva:0x6cec1)
1625 00007fff759bcbbb combase.dll!Ordinal87+0x254b (rva:0x6cbbb)
1626 00007fff75994956 combase.dll!RoGetApartmentIdentifier+0x55f6 (rva:0x44956)
1627 cccccccccccccccc */
1628 if (UICommon::instance()->isCleaningUp())
1629 return false;
1630
1631 if (!m_fKeyboardCaptured)
1632 return false;
1633
1634 /* It's possible that a key has been pressed while the keyboard was not
1635 * captured, but is being released under the capture. Detect this situation
1636 * and do not pass on the key press to the virtual machine. */
1637 uint8_t what_pressed = (event.flags & 0x01)
1638 && (event.vkCode != VK_RSHIFT)
1639 ? IsExtKeyPressed : IsKeyPressed;
1640 if ( (event.flags & 0x80) /* released */
1641 && ( ( UIHostCombo::toKeyCodeList(gEDataManager->hostKeyCombination()).contains((int)event.vkCode)
1642 && !m_fIsHostkeyInCapture)
1643 || ( m_pressedKeys[event.scanCode & 0x7F]
1644 & (IsKbdCaptured | what_pressed))
1645 == what_pressed))
1646 return false;
1647
1648 /* For normal user applications, Windows defines AltGr to be the same as
1649 * LControl + RAlt. Without a low-level hook it is hard to recognise the
1650 * additional LControl event inserted, but in a hook we recognise it by
1651 * its special 0x21D scan code. */
1652 if ( m_views[m_iKeyboardHookViewIndex]->hasFocus()
1653 && ((event.scanCode & ~0x80) == 0x21D))
1654 return true;
1655
1656 /* Compose the MSG: */
1657 MSG message;
1658 message.hwnd = (HWND)m_views[m_iKeyboardHookViewIndex]->winId();
1659 message.message = msg;
1660 message.wParam = event.vkCode;
1661 message.lParam = 1 | (event.scanCode & 0xFF) << 16 | (event.flags & 0xFF) << 24;
1662
1663 /* Windows sets here the extended bit when the Right Shift key is pressed,
1664 * which is totally wrong. Undo it. */
1665 if (event.vkCode == VK_RSHIFT)
1666 message.lParam &= ~0x1000000;
1667
1668 /* Pass event to view's event handler: */
1669 return nativeEventFilter(&message, m_iKeyboardHookViewIndex);
1670}
1671
1672#endif /* VBOX_WS_WIN */
1673
1674/**
1675 * If the user has just completed a control-alt-del combination then handle
1676 * that.
1677 * @returns true if handling should stop here, false otherwise
1678 */
1679bool UIKeyboardHandler::keyEventCADHandled(uint8_t uScan)
1680{
1681 /* Check if it's C-A-D and GUI/PassCAD is not set/allowed: */
1682 if (!m_fPassCADtoGuest &&
1683 uScan == 0x53 /* Del */ &&
1684 ((m_pressedKeys[0x38] & IsKeyPressed) /* Alt */ ||
1685 (m_pressedKeys[0x38] & IsExtKeyPressed)) &&
1686 ((m_pressedKeys[0x1d] & IsKeyPressed) /* Ctrl */ ||
1687 (m_pressedKeys[0x1d] & IsExtKeyPressed)))
1688 {
1689 /* Use the C-A-D combination as a last resort to get the keyboard and mouse back
1690 * to the host when the user forgets the Host Key. Note that it's always possible
1691 * to send C-A-D to the guest using the Host+Del combination: */
1692 if (isSessionRunning() && m_fKeyboardCaptured)
1693 {
1694 releaseKeyboard();
1695 if (!uimachine()->isMouseSupportsAbsolute() || !uimachine()->isMouseIntegrated())
1696 machineLogic()->mouseHandler()->releaseMouse();
1697 }
1698 return true;
1699 }
1700 return false;
1701}
1702
1703/**
1704 * Handle a non-special (C-A-D, pause, print) key press or release
1705 * @returns true if handling should stop here, false otherwise
1706 */
1707bool UIKeyboardHandler::keyEventHandleNormal(int iKey, uint8_t uScan, int fFlags, LONG *pCodes, uint *puCodesCount)
1708{
1709 /* Get the type of key - simple or extended: */
1710 uint8_t uWhatPressed = fFlags & KeyExtended ? IsExtKeyPressed : IsKeyPressed;
1711
1712 /* If some key was pressed or some previously pressed key was released =>
1713 * we are updating the list of pressed keys and preparing scan codes: */
1714 if ((fFlags & KeyPressed) || (m_pressedKeys[uScan] & uWhatPressed))
1715 {
1716 /* If HID LEDs sync is disabled or not supported, check if the guest has the
1717 * same view on the modifier keys (NumLock, CapsLock, ScrollLock) as the host. */
1718 if (!uimachine()->isHidLedsSyncEnabled())
1719 if (fFlags & KeyPressed)
1720 fixModifierState(pCodes, puCodesCount);
1721
1722 /* Prepend 'extended' scan code if needed: */
1723 if (fFlags & KeyExtended)
1724 pCodes[(*puCodesCount)++] = 0xE0;
1725
1726 /* Process key-press: */
1727 if (fFlags & KeyPressed)
1728 {
1729 /* Append scan code: */
1730 pCodes[(*puCodesCount)++] = uScan;
1731 m_pressedKeys[uScan] |= uWhatPressed;
1732 }
1733 /* Process key-release if that key was pressed before: */
1734 else if (m_pressedKeys[uScan] & uWhatPressed)
1735 {
1736 /* Append scan code: */
1737 pCodes[(*puCodesCount)++] = uScan | 0x80;
1738 m_pressedKeys[uScan] &= ~uWhatPressed;
1739 }
1740
1741 /* Update keyboard-captured flag: */
1742 if (m_fKeyboardCaptured)
1743 m_pressedKeys[uScan] |= IsKbdCaptured;
1744 else
1745 m_pressedKeys[uScan] &= ~IsKbdCaptured;
1746 }
1747 /* Ignore key-release if that key was NOT pressed before,
1748 * but only if thats not one of the host-combination keys: */
1749 else
1750 {
1751 /* Get host-combo key list: */
1752 QList<int> lstAllHostComboKey = UIHostCombo::toKeyCodeList(gEDataManager->hostKeyCombination());
1753 if (!lstAllHostComboKey.contains(iKey))
1754 return true;
1755 }
1756 return false;
1757}
1758
1759/**
1760 * Check whether the key pressed results in a host key combination being
1761 * handled.
1762 * @returns true if a combination was handled, false otherwise
1763 * @param pfResult where to store the result of the handling
1764 */
1765bool UIKeyboardHandler::keyEventHostComboHandled(int iKey, wchar_t *pUniKey, bool isHostComboStateChanged, bool *pfResult)
1766{
1767 if (isHostComboStateChanged)
1768 {
1769 if (!m_fHostComboPressed)
1770 {
1771 m_fHostComboPressed = true;
1772 m_bIsHostComboAlone = true;
1773 m_bIsHostComboProcessed = false;
1774 if (isSessionRunning())
1775 saveKeyStates();
1776 }
1777 }
1778 else
1779 {
1780 if (m_fHostComboPressed)
1781 {
1782 if (m_bIsHostComboAlone)
1783 {
1784 m_bIsHostComboAlone = false;
1785 m_bIsHostComboProcessed = true;
1786 /* Process Host+<key> shortcuts.
1787 * Currently, <key> is limited to alphanumeric chars.
1788 * Other Host+<key> combinations are handled in Qt event(): */
1789 *pfResult = processHotKey(iKey, pUniKey);
1790 return true;
1791 }
1792 }
1793 }
1794 return false;
1795}
1796
1797/**
1798 * Handle a key event that releases the host key combination
1799 */
1800void UIKeyboardHandler::keyEventHandleHostComboRelease(ulong uScreenId)
1801{
1802 if (m_fHostComboPressed)
1803 {
1804 m_fHostComboPressed = false;
1805 /* Capturing/releasing keyboard/mouse if necessary: */
1806 if (m_bIsHostComboAlone && !m_bIsHostComboProcessed)
1807 {
1808 if (isSessionRunning())
1809 {
1810 bool ok = true;
1811 if (!m_fKeyboardCaptured)
1812 {
1813 /* Temporarily disable auto-capture that will take place after
1814 * this dialog is dismissed because the capture state is to be
1815 * defined by the dialog result itself: */
1816 setAutoCaptureDisabled(true);
1817 bool fIsAutoConfirmed = false;
1818 ok = msgCenter().confirmInputCapture(fIsAutoConfirmed);
1819 if (fIsAutoConfirmed)
1820 setAutoCaptureDisabled(false);
1821 /* Otherwise, the disable flag will be reset in the next
1822 * machine-view's focus-in event (since may happen asynchronously
1823 * on some platforms, after we return from this code): */
1824 }
1825 if (ok)
1826 {
1827 /* Determine whether the mouse can be captured: */
1828 bool fCaptureMouse = !uimachine()->isMouseSupportsAbsolute()
1829 || !uimachine()->isMouseIntegrated();
1830
1831 if (m_fKeyboardCaptured)
1832 {
1833 releaseKeyboard();
1834 if (fCaptureMouse)
1835 machineLogic()->mouseHandler()->releaseMouse();
1836 }
1837 else
1838 {
1839 captureKeyboard(uScreenId);
1840#ifdef VBOX_WS_NIX
1841 /* Make sure that pending FocusOut events from the
1842 * previous message box are handled, otherwise the
1843 * mouse is immediately ungrabbed: */
1844 /// @todo Is that really needed?
1845 qApp->processEvents();
1846#endif /* VBOX_WS_NIX */
1847 finaliseCaptureKeyboard();
1848 if (fCaptureMouse)
1849 {
1850 const MouseCapturePolicy mcp = gEDataManager->mouseCapturePolicy(uiCommon().managedVMUuid());
1851 if (mcp == MouseCapturePolicy_Default || mcp == MouseCapturePolicy_HostComboOnly)
1852 machineLogic()->mouseHandler()->captureMouse(uScreenId);
1853 }
1854 }
1855 }
1856 }
1857 }
1858 if (isSessionRunning())
1859 sendChangedKeyStates();
1860 }
1861}
1862
1863bool UIKeyboardHandler::keyEvent(int iKey, uint8_t uScan, int fFlags, ulong uScreenId, wchar_t *pUniKey /* = 0 */)
1864{
1865 /* Get host-combo key list: */
1866 QList<int> allHostComboKeys = UIHostCombo::toKeyCodeList(gEDataManager->hostKeyCombination());
1867
1868 /* Update the map of pressed host-combo keys: */
1869 if (allHostComboKeys.contains(iKey))
1870 {
1871 if (fFlags & KeyPressed)
1872 {
1873 if (!m_pressedHostComboKeys.contains(iKey))
1874 m_pressedHostComboKeys.insert(iKey, uScan);
1875 else if (m_fHostComboPressed)
1876 return true;
1877 }
1878 else
1879 {
1880 if (m_pressedHostComboKeys.contains(iKey))
1881 m_pressedHostComboKeys.remove(iKey);
1882 }
1883 }
1884
1885 /* Check if we are currently holding FULL host-combo: */
1886 bool fIsFullHostComboPresent = false;
1887 if (!allHostComboKeys.isEmpty())
1888 {
1889 const QList<int> pressedKeyList = m_pressedHostComboKeys.keys();
1890 fIsFullHostComboPresent = QSet<int>(allHostComboKeys.begin(), allHostComboKeys.end())
1891 == QSet<int>(pressedKeyList.begin(), pressedKeyList.end());
1892 }
1893
1894 /* Check if currently pressed/released key had changed host-combo state: */
1895 const bool isHostComboStateChanged = (!m_fHostComboPressed && fIsFullHostComboPresent) ||
1896 ( m_fHostComboPressed && !fIsFullHostComboPresent);
1897
1898#ifdef VBOX_WS_WIN
1899 if (m_fHostComboPressed || isHostComboStateChanged)
1900 {
1901 /* Currently this is used in winKeyboardEvent() only: */
1902 m_fIsHostkeyInCapture = m_fKeyboardCaptured;
1903 }
1904#endif /* VBOX_WS_WIN */
1905
1906 if (keyEventCADHandled(uScan))
1907 return true;
1908
1909 /* Preparing the press/release scan-codes array for sending to the guest:
1910 * 1. if host-combo is NOT pressed, taking into account currently pressed key too,
1911 * 2. if currently released key releases host-combo too.
1912 * Using that rule, we are NOT sending to the guest:
1913 * 1. the last key-press of host-combo,
1914 * 2. all keys pressed while the host-combo being held (but we still send releases). */
1915 LONG aCodesBuffer[16];
1916 LONG *pCodes = aCodesBuffer;
1917 uint uCodesCount = 0;
1918 uint8_t uWhatPressed = fFlags & KeyExtended ? IsExtKeyPressed : IsKeyPressed;
1919 if ((!m_fHostComboPressed && !isHostComboStateChanged) ||
1920 ( m_fHostComboPressed && isHostComboStateChanged) ||
1921 (!(fFlags & KeyPressed) && (m_pressedKeys[uScan] & uWhatPressed)))
1922 {
1923 /* Special flags handling (KeyPrint): */
1924 if (fFlags & KeyPrint)
1925 {
1926 if (fFlags & KeyPressed)
1927 {
1928 static LONG PrintMake[] = { 0xE0, 0x37 };
1929 pCodes = PrintMake;
1930 uCodesCount = RT_ELEMENTS(PrintMake);
1931 }
1932 else
1933 {
1934 static LONG PrintBreak[] = { 0xE0, 0xB7 };
1935 pCodes = PrintBreak;
1936 uCodesCount = RT_ELEMENTS(PrintBreak);
1937 }
1938 }
1939 /* Special flags handling (KeyPause): */
1940 else if (fFlags & KeyPause)
1941 {
1942 if (fFlags & KeyPressed)
1943 {
1944 static LONG Pause[] = { 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5 };
1945 pCodes = Pause;
1946 uCodesCount = RT_ELEMENTS(Pause);
1947 }
1948 else
1949 {
1950 /* Pause shall not produce a break code: */
1951 return true;
1952 }
1953 }
1954 /* Common flags handling: */
1955 else
1956 if (keyEventHandleNormal(iKey, uScan, fFlags, pCodes, &uCodesCount))
1957 return true;
1958 }
1959
1960 /* Process the host-combo funtionality: */
1961 if (fFlags & KeyPressed)
1962 {
1963 bool fResult;
1964 if (keyEventHostComboHandled(iKey, pUniKey, isHostComboStateChanged, &fResult))
1965 return fResult;
1966 }
1967 else
1968 {
1969 if (isHostComboStateChanged)
1970 keyEventHandleHostComboRelease(uScreenId);
1971 else
1972 {
1973 if (m_fHostComboPressed)
1974 m_bIsHostComboAlone = true;
1975 }
1976 }
1977
1978 /* Notify all the listeners: */
1979 emit sigStateChange(state());
1980
1981 /* If the VM is NOT paused: */
1982 if (!uimachine()->isPaused())
1983 {
1984 /* If there are scan-codes to send: */
1985 if (uCodesCount)
1986 {
1987 /* Send prepared scan-codes to the guest: */
1988 QVector<LONG> scancodes;
1989 for (uint i = 0; i < uCodesCount; ++i)
1990 scancodes.append(pCodes[i]);
1991 uimachine()->putScancodes(scancodes);
1992 }
1993
1994 /* If full host-key sequence was just finalized: */
1995 if (isHostComboStateChanged && m_fHostComboPressed)
1996 {
1997 /* We have to make guest to release pressed keys from the host-combination: */
1998 foreach (const uint8_t &uCurrentScan, m_pressedHostComboKeys.values())
1999 {
2000 if (m_pressedKeys[uCurrentScan] & IsKeyPressed)
2001 {
2002 uimachine()->putScancode(uCurrentScan | 0x80);
2003 }
2004 else if (m_pressedKeys[uCurrentScan] & IsExtKeyPressed)
2005 {
2006 QVector<LONG> scancodes(2);
2007 scancodes[0] = 0xE0;
2008 scancodes[1] = uCurrentScan | 0x80;
2009 uimachine()->putScancodes(scancodes);
2010 }
2011 m_pressedKeys[uCurrentScan] = 0;
2012 }
2013 }
2014 }
2015
2016 /* Prevent the key from going to Qt: */
2017 return true;
2018}
2019
2020bool UIKeyboardHandler::processHotKey(int iHotKey, wchar_t *pHotKey)
2021{
2022 /* Prepare processing result: */
2023 bool fWasProcessed = false;
2024
2025#if defined(VBOX_WS_MAC)
2026
2027 Q_UNUSED(iHotKey);
2028 if (pHotKey && pHotKey[0] && !pHotKey[1])
2029 fWasProcessed = actionPool()->processHotKey(QKeySequence(QChar(pHotKey[0]).toUpper().unicode()));
2030
2031#elif defined(VBOX_WS_WIN)
2032
2033 Q_UNUSED(pHotKey);
2034 int iKeyboardLayout = GetKeyboardLayoutList(0, NULL);
2035 Assert(iKeyboardLayout);
2036 HKL *pList = new HKL[iKeyboardLayout];
2037 GetKeyboardLayoutList(iKeyboardLayout, pList);
2038 for (int i = 0; i < iKeyboardLayout && !fWasProcessed; ++i)
2039 {
2040 wchar_t symbol;
2041 static BYTE keys[256] = {0};
2042 if (!ToUnicodeEx(iHotKey, 0, keys, &symbol, 1, 0, pList[i]) == 1)
2043 symbol = 0;
2044 if (symbol)
2045 fWasProcessed = actionPool()->processHotKey(QKeySequence(QChar(symbol).toUpper().unicode()));
2046 }
2047 delete[] pList;
2048
2049#elif defined(VBOX_WS_NIX)
2050 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
2051 {
2052 Q_UNUSED(pHotKey);
2053 Display *pDisplay = NativeWindowSubsystem::X11GetDisplay();
2054 KeyCode keyCode = XKeysymToKeycode(pDisplay, iHotKey);
2055 for (int i = 0; i < 4 && !fWasProcessed; ++i) /* Up to four groups. */
2056 {
2057 KeySym ks = wrapXkbKeycodeToKeysym(pDisplay, keyCode, i, 0);
2058 char symbol = 0;
2059 if (XkbTranslateKeySym(pDisplay, &ks, 0, &symbol, 1, NULL) == 0)
2060 symbol = 0;
2061 if (symbol)
2062 {
2063 QChar qtSymbol = QString::fromLocal8Bit(&symbol, 1)[0];
2064 fWasProcessed = actionPool()->processHotKey(QKeySequence(qtSymbol.toUpper().unicode()));
2065 }
2066 }
2067 }
2068
2069#else
2070
2071# warning "port me!"
2072
2073#endif
2074
2075 /* Grab the key from the Qt if it was processed, or pass it to the Qt otherwise
2076 * in order to process non-alphanumeric keys in event(), after they are converted to Qt virtual keys: */
2077 return fWasProcessed;
2078}
2079
2080void UIKeyboardHandler::fixModifierState(LONG *piCodes, uint *puCount)
2081{
2082 /* Synchronize the views of the host and the guest to the modifier keys.
2083 * This function will add up to 6 additional keycodes to codes. */
2084
2085#if defined(VBOX_WS_MAC)
2086
2087 /* if (uimachine()->numLockAdaptionCnt()) ... - NumLock isn't implemented by Mac OS X so ignore it. */
2088 if (uimachine()->capsLockAdaptionCnt() && (uimachine()->isCapsLock() ^ !!(::GetCurrentEventKeyModifiers() & alphaLock)))
2089 {
2090 uimachine()->setCapsLockAdaptionCnt(uimachine()->capsLockAdaptionCnt() - 1);
2091 piCodes[(*puCount)++] = 0x3a;
2092 piCodes[(*puCount)++] = 0x3a | 0x80;
2093 /* Some keyboard layouts require shift to be pressed to break
2094 * capslock. For simplicity, only do this if shift is not
2095 * already held down. */
2096 if (uimachine()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
2097 {
2098 piCodes[(*puCount)++] = 0x2a;
2099 piCodes[(*puCount)++] = 0x2a | 0x80;
2100 }
2101 }
2102
2103#elif defined(VBOX_WS_WIN)
2104
2105 if (uimachine()->numLockAdaptionCnt() && (uimachine()->isNumLock() ^ !!(GetKeyState(VK_NUMLOCK))))
2106 {
2107 uimachine()->setNumLockAdaptionCnt(uimachine()->numLockAdaptionCnt() - 1);
2108 piCodes[(*puCount)++] = 0x45;
2109 piCodes[(*puCount)++] = 0x45 | 0x80;
2110 }
2111 if (uimachine()->capsLockAdaptionCnt() && (uimachine()->isCapsLock() ^ !!(GetKeyState(VK_CAPITAL))))
2112 {
2113 uimachine()->setCapsLockAdaptionCnt(uimachine()->capsLockAdaptionCnt() - 1);
2114 piCodes[(*puCount)++] = 0x3a;
2115 piCodes[(*puCount)++] = 0x3a | 0x80;
2116 /* Some keyboard layouts require shift to be pressed to break
2117 * capslock. For simplicity, only do this if shift is not
2118 * already held down. */
2119 if (uimachine()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
2120 {
2121 piCodes[(*puCount)++] = 0x2a;
2122 piCodes[(*puCount)++] = 0x2a | 0x80;
2123 }
2124 }
2125
2126#elif defined(VBOX_WS_NIX)
2127 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_X11)
2128 {
2129 Window wDummy1, wDummy2;
2130 int iDummy3, iDummy4, iDummy5, iDummy6;
2131 unsigned uMask;
2132 unsigned uKeyMaskNum = 0, uKeyMaskCaps = 0;
2133 Display * const pDisplay = NativeWindowSubsystem::X11GetDisplay();
2134
2135 uKeyMaskCaps = LockMask;
2136 XModifierKeymap* map = XGetModifierMapping(pDisplay);
2137 KeyCode keyCodeNum = XKeysymToKeycode(pDisplay, XK_Num_Lock);
2138
2139 for (int i = 0; i < 8; ++ i)
2140 if (keyCodeNum != NoSymbol && map->modifiermap[map->max_keypermod * i] == keyCodeNum)
2141 uKeyMaskNum = 1 << i;
2142 XQueryPointer(pDisplay, DefaultRootWindow(pDisplay), &wDummy1, &wDummy2,
2143 &iDummy3, &iDummy4, &iDummy5, &iDummy6, &uMask);
2144 XFreeModifiermap(map);
2145
2146 if (uimachine()->numLockAdaptionCnt() && (uimachine()->isNumLock() ^ !!(uMask & uKeyMaskNum)))
2147 {
2148 uimachine()->setNumLockAdaptionCnt(uimachine()->numLockAdaptionCnt() - 1);
2149 piCodes[(*puCount)++] = 0x45;
2150 piCodes[(*puCount)++] = 0x45 | 0x80;
2151 }
2152 if (uimachine()->capsLockAdaptionCnt() && (uimachine()->isCapsLock() ^ !!(uMask & uKeyMaskCaps)))
2153 {
2154 uimachine()->setCapsLockAdaptionCnt(uimachine()->capsLockAdaptionCnt() - 1);
2155 piCodes[(*puCount)++] = 0x3a;
2156 piCodes[(*puCount)++] = 0x3a | 0x80;
2157 /* Some keyboard layouts require shift to be pressed to break
2158 * capslock. For simplicity, only do this if shift is not
2159 * already held down. */
2160 if (uimachine()->isCapsLock() && !(m_pressedKeys[0x2a] & IsKeyPressed))
2161 {
2162 piCodes[(*puCount)++] = 0x2a;
2163 piCodes[(*puCount)++] = 0x2a | 0x80;
2164 }
2165 }
2166 }
2167#else
2168
2169# warning "port me!"
2170
2171#endif
2172}
2173
2174void UIKeyboardHandler::saveKeyStates()
2175{
2176 ::memcpy(m_pressedKeysCopy, m_pressedKeys, sizeof(m_pressedKeys));
2177}
2178
2179void UIKeyboardHandler::sendChangedKeyStates()
2180{
2181 QVector <LONG> codes(2);
2182 for (uint i = 0; i < RT_ELEMENTS(m_pressedKeys); ++ i)
2183 {
2184 uint8_t os = m_pressedKeysCopy[i];
2185 uint8_t ns = m_pressedKeys[i];
2186 if ((os & IsKeyPressed) != (ns & IsKeyPressed))
2187 {
2188 codes[0] = i;
2189 if (!(ns & IsKeyPressed))
2190 codes[0] |= 0x80;
2191 uimachine()->putScancode(codes[0]);
2192 }
2193 else if ((os & IsExtKeyPressed) != (ns & IsExtKeyPressed))
2194 {
2195 codes[0] = 0xE0;
2196 codes[1] = i;
2197 if (!(ns & IsExtKeyPressed))
2198 codes[1] |= 0x80;
2199 uimachine()->putScancodes(codes);
2200 }
2201 }
2202}
2203
2204bool UIKeyboardHandler::isAutoCaptureDisabled()
2205{
2206 return uimachine()->isAutoCaptureDisabled();
2207}
2208
2209void UIKeyboardHandler::setAutoCaptureDisabled(bool fIsAutoCaptureDisabled)
2210{
2211 uimachine()->setAutoCaptureDisabled(fIsAutoCaptureDisabled);
2212}
2213
2214bool UIKeyboardHandler::autoCaptureSetGlobally()
2215{
2216 return gEDataManager->autoCaptureEnabled() && !m_fDebuggerActive;
2217}
2218
2219bool UIKeyboardHandler::viewHasFocus(ulong uScreenId)
2220{
2221 return m_views[uScreenId]->hasFocus();
2222}
2223
2224bool UIKeyboardHandler::isSessionRunning()
2225{
2226 return uimachine()->isRunning();
2227}
2228
2229bool UIKeyboardHandler::isSessionStuck()
2230{
2231 return uimachine()->isStuck();
2232}
2233
2234UIMachineWindow* UIKeyboardHandler::isItListenedWindow(QObject *pWatchedObject) const
2235{
2236 UIMachineWindow *pResultWindow = 0;
2237 QMap<ulong, UIMachineWindow*>::const_iterator i = m_windows.constBegin();
2238 while (!pResultWindow && i != m_windows.constEnd())
2239 {
2240 UIMachineWindow *pIteratedWindow = i.value();
2241 if (pIteratedWindow == pWatchedObject)
2242 {
2243 pResultWindow = pIteratedWindow;
2244 continue;
2245 }
2246 ++i;
2247 }
2248 return pResultWindow;
2249}
2250
2251UIMachineView* UIKeyboardHandler::isItListenedView(QObject *pWatchedObject) const
2252{
2253 UIMachineView *pResultView = 0;
2254 QMap<ulong, UIMachineView*>::const_iterator i = m_views.constBegin();
2255 while (!pResultView && i != m_views.constEnd())
2256 {
2257 UIMachineView *pIteratedView = i.value();
2258 if (pIteratedView == pWatchedObject)
2259 {
2260 pResultView = pIteratedView;
2261 continue;
2262 }
2263 ++i;
2264 }
2265 return pResultView;
2266}
2267
2268void UIKeyboardHandler::setHostKeyComboPressedFlag(bool bPressed)
2269{
2270 m_fHostKeyComboPressInserted = bPressed;
2271 emit sigStateChange(state());
2272}
2273
2274#ifdef VBOX_WS_NIX
2275void UIKeyboardHandler::handleKeyEvent(quint32 uEvDevCode, bool fRelease)
2276{
2277
2278 // printf("UIKeyboardHandler::handleKeyEvent %u %u\n", nativeScanCode, nativeScanCode >> 0xE0);
2279 if (NativeWindowSubsystem::displayServerType() == VBGHDISPLAYSERVERTYPE_PURE_WAYLAND)
2280 {
2281 AssertMsgReturnVoid(uEvDevCode < CODE_ARRAY_LENGTH, ("Received evdev code is not in conversation table"));
2282 uimachine()->putUsageCode(evcode_hid[uEvDevCode][1], evcode_hid[uEvDevCode][0], fRelease);
2283 //m_pMachine->putUsageCode(sequence[i].first, sequence[i].second, false);
2284 // /* On Linux xcb, wayland etc has an offset of 8 in scancodes (they start from 7 instead of 0): */
2285 // if (!fRelease)
2286 // uimachine()->putScancode(nativeScanCode - 8);
2287 // else
2288 // uimachine()->putScancode((nativeScanCode - 8) | 0x80);
2289 }
2290}
2291#endif
Note: See TracBrowser for help on using the repository browser.

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