VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/SDLConsole.cpp@ 26951

Last change on this file since 26951 was 26853, checked in by vboxsync, 15 years ago

VBoxBFE: Attempt to fix burn caused by r58109.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.3 KB
Line 
1/** @file
2 *
3 * VBox frontends: Basic Frontend (BFE):
4 * Implementation of SDLConsole class
5 */
6
7/*
8 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_GUI
27#define __STDC_LIMIT_MACROS
28#define __STDC_CONSTANT_MACROS
29
30#ifdef RT_OS_DARWIN
31# include <Carbon/Carbon.h>
32# undef PAGE_SIZE
33# undef PAGE_SHIFT
34#endif
35
36#ifdef VBOXBFE_WITHOUT_COM
37# include "COMDefs.h"
38#else
39# include <VBox/com/defs.h>
40#endif
41#include <VBox/types.h>
42#include <VBox/err.h>
43#include <VBox/param.h>
44#include <VBox/pdm.h>
45#include <VBox/log.h>
46#include <iprt/path.h>
47#include <iprt/string.h>
48#include <iprt/initterm.h>
49#include <iprt/assert.h>
50#include <iprt/semaphore.h>
51#include <iprt/stream.h>
52#include <iprt/uuid.h>
53#include <iprt/alloca.h>
54
55#ifdef VBOXBFE_WITH_X11
56# include <X11/Xlib.h>
57# ifndef VBOXBFE_WITHOUT_XCURSOR
58# include <X11/Xcursor/Xcursor.h>
59# endif
60#endif
61
62#include "VBoxBFE.h"
63
64#include <vector>
65
66#include "DisplayImpl.h"
67#include "MouseImpl.h"
68#include "KeyboardImpl.h"
69#include "VMMDevInterface.h"
70#include "Framebuffer.h"
71#include "MachineDebuggerImpl.h"
72#include "VMControl.h"
73
74#include "ConsoleImpl.h"
75#include "SDLConsole.h"
76#include "Ico64x01.h"
77
78/*******************************************************************************
79* Internal Functions *
80*******************************************************************************/
81
82SDLConsole::SDLConsole() : Console()
83{
84 int rc;
85
86 mfInputGrab = false;
87 gpDefaultCursor = NULL;
88 gpCustomCursor = NULL;
89 /** Custom window manager cursor? */
90 gpCustomWMcursor = NULL;
91 mfInitialized = false;
92 mWMIcon = NULL;
93
94 memset(gaModifiersState, 0, sizeof(gaModifiersState));
95
96 rc = SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE);
97 if (rc != 0)
98 {
99 RTPrintf("SDL Error: '%s'\n", SDL_GetError());
100 return;
101 }
102
103 /* memorize the default cursor */
104 gpDefaultCursor = SDL_GetCursor();
105 /* create a fake empty cursor */
106 {
107 uint8_t cursorData[1] = {0};
108 gpCustomCursor = SDL_CreateCursor(cursorData, cursorData, 8, 1, 0, 0);
109 gpCustomWMcursor = gpCustomCursor->wm_cursor;
110 gpCustomCursor->wm_cursor = NULL;
111 }
112#ifdef VBOXBFE_WITH_X11
113 /* get Window Manager info */
114 SDL_VERSION(&gSdlInfo.version);
115 if (!SDL_GetWMInfo(&gSdlInfo))
116 {
117 /** @todo: Is this fatal? */
118 AssertMsgFailed(("Error: could not get SDL Window Manager info!\n"));
119 }
120#endif
121
122 if (12320 == g_cbIco64x01)
123 {
124 mWMIcon = SDL_AllocSurface(SDL_SWSURFACE, 64, 64, 24, 0xff, 0xff00, 0xff0000, 0);
125 /** @todo make it as simple as possible. No PNM interpreter here... */
126 if (mWMIcon)
127 {
128 memcpy(mWMIcon->pixels, g_abIco64x01+32, g_cbIco64x01-32);
129 SDL_WM_SetIcon(mWMIcon, NULL);
130 }
131 }
132
133 /*
134 * Enable keyboard repeats
135 */
136 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
137
138 /*
139 * Initialise "children" (so far only Mouse)
140 */
141 if (FAILED(gMouse->init(this)))
142 {
143 RTPrintf("VBoxBFE: failed to initialise the mouse device\n");
144 return;
145 }
146
147 mfInitialized = true;
148}
149
150SDLConsole::~SDLConsole()
151{
152 if (mfInputGrab)
153 inputGrabEnd();
154
155 /*
156 * Uninitialise "children" (so far only Mouse)
157 */
158 gMouse->uninit();
159
160 if (mWMIcon)
161 {
162 SDL_FreeSurface(mWMIcon);
163 mWMIcon = NULL;
164 }
165}
166
167CONEVENT SDLConsole::eventWait()
168{
169 SDL_Event *ev = &ev1;
170
171 if (SDL_WaitEvent(ev) != 1)
172 return CONEVENT_QUIT;
173
174 switch (ev->type)
175 {
176
177 /*
178 * The screen needs to be repainted.
179 */
180 case SDL_VIDEOEXPOSE:
181 {
182 return CONEVENT_SCREENUPDATE;
183 }
184
185 /*
186 * Keyboard events.
187 */
188 case SDL_KEYDOWN:
189 case SDL_KEYUP:
190 {
191 switch (enmHKeyState)
192 {
193 case HKEYSTATE_NORMAL:
194 {
195 if ( ev->type == SDL_KEYDOWN
196 && ev->key.keysym.sym == gHostKeySym
197 && (SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == gHostKey)
198 {
199 EvHKeyDown = *ev;
200 enmHKeyState = HKEYSTATE_DOWN;
201 break;
202 }
203 processKey(&ev->key);
204 break;
205 }
206
207 case HKEYSTATE_DOWN:
208 {
209
210 if (ev->type == SDL_KEYDOWN)
211 {
212 /* potential host key combination, try execute it */
213 int rc = handleHostKey(&ev->key);
214 if (rc == VINF_SUCCESS)
215 {
216 enmHKeyState = HKEYSTATE_USED;
217 break;
218 }
219 if (RT_SUCCESS(rc))
220 {
221 return CONEVENT_QUIT;
222 }
223 }
224 else /* SDL_KEYUP */
225 {
226 if (ev->key.keysym.sym == gHostKeySym)
227 {
228 /* toggle grabbing state */
229 if (!mfInputGrab)
230 inputGrabStart();
231 else
232 inputGrabEnd();
233
234 /* SDL doesn't always reset the keystates, correct it */
235 resetKeys();
236 enmHKeyState = HKEYSTATE_NORMAL;
237 break;
238 }
239 }
240
241 /* not host key */
242 enmHKeyState = HKEYSTATE_NOT_IT;
243 ev1 = *ev;
244 processKey(&EvHKeyDown.key);
245 processKey(&ev->key);
246 break;
247 }
248
249 case HKEYSTATE_USED:
250 {
251 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
252 {
253 enmHKeyState = HKEYSTATE_NORMAL;
254 }
255 if (ev->type == SDL_KEYDOWN)
256 {
257 int rc = handleHostKey(&ev->key);
258 if (RT_SUCCESS(rc) && rc != VINF_SUCCESS)
259 {
260 return CONEVENT_QUIT;
261 }
262 }
263 break;
264 }
265
266 default:
267 AssertMsgFailed(("enmHKeyState=%d\n", enmHKeyState));
268 /* fall thru */
269 case HKEYSTATE_NOT_IT:
270 {
271 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) == 0)
272 {
273 enmHKeyState = HKEYSTATE_NORMAL;
274 }
275 processKey(&ev->key);
276 break;
277 }
278 } /* state switch */
279 break;
280 }
281
282 /*
283 * The window was closed.
284 */
285 case SDL_QUIT:
286 {
287 return CONEVENT_QUIT;
288 }
289
290 /*
291 * The mouse has moved
292 */
293 case SDL_MOUSEMOTION:
294 {
295 BOOL fMouseAbsolute;
296 gMouse->COMGETTER(AbsoluteSupported)(&fMouseAbsolute);
297 if (mfInputGrab || fMouseAbsolute)
298 mouseSendEvent(0);
299 break;
300 }
301
302 /*
303 * A mouse button has been clicked or released.
304 */
305 case SDL_MOUSEBUTTONDOWN:
306 case SDL_MOUSEBUTTONUP:
307 {
308 BOOL fMouseAbsolute;
309 gMouse->COMGETTER(AbsoluteSupported)(&fMouseAbsolute);
310 SDL_MouseButtonEvent *bev = &ev->button;
311 if (!mfInputGrab && !fMouseAbsolute)
312 {
313 if (ev->type == SDL_MOUSEBUTTONDOWN && (bev->state & SDL_BUTTON_LMASK))
314 {
315 /* start grabbing all events */
316 inputGrabStart();
317 }
318 }
319 else
320 {
321 int dz = 0;
322 if (bev->button == SDL_BUTTON_WHEELUP)
323 {
324 dz = -1;
325 }
326 else if (bev->button == SDL_BUTTON_WHEELDOWN)
327 {
328 dz = 1;
329 }
330 mouseSendEvent(dz);
331 }
332 break;
333 }
334
335 /*
336 * The window has gained or lost focus.
337 */
338 case SDL_ACTIVEEVENT:
339 {
340 if (mfInputGrab && (SDL_GetAppState() & SDL_ACTIVEEVENTMASK) == 0)
341 {
342 inputGrabEnd();
343 }
344 break;
345 }
346
347
348 /*
349 * User specific update event.
350 */
351 /** @todo use a common user event handler so that SDL_PeepEvents() won't
352 * possibly remove other events in the queue!
353 */
354 case SDL_USER_EVENT_UPDATERECT:
355 {
356
357 /*
358 * Decode event parameters.
359 */
360 #define DECODEX(ev) ((intptr_t)(ev)->user.data1 >> 16)
361 #define DECODEY(ev) ((intptr_t)(ev)->user.data1 & 0xFFFF)
362 #define DECODEW(ev) ((intptr_t)(ev)->user.data2 >> 16)
363 #define DECODEH(ev) ((intptr_t)(ev)->user.data2 & 0xFFFF)
364 int x = DECODEX(ev);
365 int y = DECODEY(ev);
366 int w = DECODEW(ev);
367 int h = DECODEH(ev);
368 LogFlow(("SDL_USER_EVENT_UPDATERECT: x = %d, y = %d, w = %d, h = %d\n",
369 x, y, w, h));
370
371 Assert(gFramebuffer);
372 /*
373 * Lock the framebuffer, perform the update and lock again
374 */
375 gFramebuffer->Lock();
376 gFramebuffer->update(x, y, w, h);
377 gFramebuffer->Unlock();
378
379 #undef DECODEX
380 #undef DECODEY
381 #undef DECODEW
382 #undef DECODEH
383 break;
384 }
385
386 /*
387 * User specific resize event.
388 */
389 case SDL_USER_EVENT_RESIZE:
390 return CONEVENT_USR_SCREENRESIZE;
391
392 /*
393 * User specific update title bar notification event
394 */
395 case SDL_USER_EVENT_UPDATE_TITLEBAR:
396 return CONEVENT_USR_TITLEBARUPDATE;
397
398 /*
399 * User specific termination event
400 */
401 case SDL_USER_EVENT_TERMINATE:
402 {
403 if (ev->user.code != VBOXSDL_TERM_NORMAL)
404 RTPrintf("Error: VM terminated abnormally!\n");
405 return CONEVENT_USR_QUIT;
406 }
407
408#ifdef VBOX_SECURELABEL
409 /*
410 * User specific secure label update event
411 */
412 case SDL_USER_EVENT_SECURELABEL_UPDATE:
413 return CONEVENT_USR_SECURELABELUPDATE;
414
415#endif /* VBOX_SECURELABEL */
416
417 /*
418 * User specific pointer shape change event
419 */
420 case SDL_USER_EVENT_POINTER_CHANGE:
421 {
422 PointerShapeChangeData *data =
423 (PointerShapeChangeData *) ev->user.data1;
424 setPointerShape (data);
425 delete data;
426 break;
427 }
428
429 case SDL_VIDEORESIZE:
430 {
431 /* ignore this */
432 break;
433 }
434
435 default:
436 {
437 printf("%s:%d unknown SDL event %d\n",__FILE__,__LINE__,ev->type);
438 LogBird(("unknown SDL event %d\n", ev->type));
439 break;
440 }
441 }
442 return CONEVENT_NONE;
443}
444
445/**
446 * Push the exit event forcing the main event loop to terminate.
447 */
448void SDLConsole::doEventQuit()
449{
450 SDL_Event event;
451
452 event.type = SDL_USEREVENT;
453 event.user.type = SDL_USER_EVENT_TERMINATE;
454 event.user.code = VBOXSDL_TERM_NORMAL;
455 SDL_PushEvent(&event);
456}
457
458void SDLConsole::eventQuit()
459{
460 doEventQuit();
461}
462
463#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_OS2)
464/**
465 * Fallback keycode conversion using SDL symbols.
466 *
467 * This is used to catch keycodes that's missing from the translation table.
468 *
469 * @returns XT scancode
470 * @param ev SDL scancode
471 */
472static uint8_t Keyevent2KeycodeFallback(const SDL_KeyboardEvent *ev)
473{
474 const SDLKey sym = ev->keysym.sym;
475 Log(("SDL key event: sym=%d scancode=%#x unicode=%#x\n",
476 sym, ev->keysym.scancode, ev->keysym.unicode));
477 switch (sym)
478 { /* set 1 scan code */
479 case SDLK_ESCAPE: return 0x01;
480 case SDLK_EXCLAIM:
481 case SDLK_1: return 0x02;
482 case SDLK_AT:
483 case SDLK_2: return 0x03;
484 case SDLK_HASH:
485 case SDLK_3: return 0x04;
486 case SDLK_DOLLAR:
487 case SDLK_4: return 0x05;
488 /* % */
489 case SDLK_5: return 0x06;
490 case SDLK_CARET:
491 case SDLK_6: return 0x07;
492 case SDLK_AMPERSAND:
493 case SDLK_7: return 0x08;
494 case SDLK_ASTERISK:
495 case SDLK_8: return 0x09;
496 case SDLK_LEFTPAREN:
497 case SDLK_9: return 0x0a;
498 case SDLK_RIGHTPAREN:
499 case SDLK_0: return 0x0b;
500 case SDLK_UNDERSCORE:
501 case SDLK_MINUS: return 0x0c;
502 case SDLK_EQUALS:
503 case SDLK_PLUS: return 0x0d;
504 case SDLK_BACKSPACE: return 0x0e;
505 case SDLK_TAB: return 0x0f;
506 case SDLK_q: return 0x10;
507 case SDLK_w: return 0x11;
508 case SDLK_e: return 0x12;
509 case SDLK_r: return 0x13;
510 case SDLK_t: return 0x14;
511 case SDLK_y: return 0x15;
512 case SDLK_u: return 0x16;
513 case SDLK_i: return 0x17;
514 case SDLK_o: return 0x18;
515 case SDLK_p: return 0x19;
516 case SDLK_LEFTBRACKET: return 0x1a;
517 case SDLK_RIGHTBRACKET: return 0x1b;
518 case SDLK_RETURN: return 0x1c;
519 case SDLK_KP_ENTER: return 0x1c | 0x80;
520 case SDLK_LCTRL: return 0x1d;
521 case SDLK_RCTRL: return 0x1d | 0x80;
522 case SDLK_a: return 0x1e;
523 case SDLK_s: return 0x1f;
524 case SDLK_d: return 0x20;
525 case SDLK_f: return 0x21;
526 case SDLK_g: return 0x22;
527 case SDLK_h: return 0x23;
528 case SDLK_j: return 0x24;
529 case SDLK_k: return 0x25;
530 case SDLK_l: return 0x26;
531 case SDLK_COLON:
532 case SDLK_SEMICOLON: return 0x27;
533 case SDLK_QUOTEDBL:
534 case SDLK_QUOTE: return 0x28;
535 case SDLK_BACKQUOTE: return 0x29;
536 case SDLK_LSHIFT: return 0x2a;
537 case SDLK_BACKSLASH: return 0x2b;
538 case SDLK_z: return 0x2c;
539 case SDLK_x: return 0x2d;
540 case SDLK_c: return 0x2e;
541 case SDLK_v: return 0x2f;
542 case SDLK_b: return 0x30;
543 case SDLK_n: return 0x31;
544 case SDLK_m: return 0x32;
545 case SDLK_LESS:
546 case SDLK_COMMA: return 0x33;
547 case SDLK_GREATER:
548 case SDLK_PERIOD: return 0x34;
549 case SDLK_KP_DIVIDE: /*??*/
550 case SDLK_QUESTION:
551 case SDLK_SLASH: return 0x35;
552 case SDLK_RSHIFT: return 0x36;
553 case SDLK_KP_MULTIPLY:
554 case SDLK_PRINT: return 0x37; /* fixme */
555 case SDLK_LALT: return 0x38;
556 case SDLK_MODE: /* alt gr*/
557 case SDLK_RALT: return 0x38 | 0x80;
558 case SDLK_SPACE: return 0x39;
559 case SDLK_CAPSLOCK: return 0x3a;
560 case SDLK_F1: return 0x3b;
561 case SDLK_F2: return 0x3c;
562 case SDLK_F3: return 0x3d;
563 case SDLK_F4: return 0x3e;
564 case SDLK_F5: return 0x3f;
565 case SDLK_F6: return 0x40;
566 case SDLK_F7: return 0x41;
567 case SDLK_F8: return 0x42;
568 case SDLK_F9: return 0x43;
569 case SDLK_F10: return 0x44;
570 case SDLK_PAUSE: return 0x45; /* not right */
571 case SDLK_NUMLOCK: return 0x45;
572 case SDLK_SCROLLOCK: return 0x46;
573 case SDLK_KP7: return 0x47;
574 case SDLK_HOME: return 0x47 | 0x80;
575 case SDLK_KP8: return 0x48;
576 case SDLK_UP: return 0x48 | 0x80;
577 case SDLK_KP9: return 0x49;
578 case SDLK_PAGEUP: return 0x49 | 0x80;
579 case SDLK_KP_MINUS: return 0x4a;
580 case SDLK_KP4: return 0x4b;
581 case SDLK_LEFT: return 0x4b | 0x80;
582 case SDLK_KP5: return 0x4c;
583 case SDLK_KP6: return 0x4d;
584 case SDLK_RIGHT: return 0x4d | 0x80;
585 case SDLK_KP_PLUS: return 0x4e;
586 case SDLK_KP1: return 0x4f;
587 case SDLK_END: return 0x4f | 0x80;
588 case SDLK_KP2: return 0x50;
589 case SDLK_DOWN: return 0x50 | 0x80;
590 case SDLK_KP3: return 0x51;
591 case SDLK_PAGEDOWN: return 0x51 | 0x80;
592 case SDLK_KP0: return 0x52;
593 case SDLK_INSERT: return 0x52 | 0x80;
594 case SDLK_KP_PERIOD: return 0x53;
595 case SDLK_DELETE: return 0x53 | 0x80;
596 case SDLK_SYSREQ: return 0x54;
597 case SDLK_F11: return 0x57;
598 case SDLK_F12: return 0x58;
599 case SDLK_F13: return 0x5b;
600 case SDLK_LMETA:
601 case SDLK_LSUPER: return 0x5b | 0x80;
602 case SDLK_F14: return 0x5c;
603 case SDLK_RMETA:
604 case SDLK_RSUPER: return 0x5c | 0x80;
605 case SDLK_F15: return 0x5d;
606 case SDLK_MENU: return 0x5d | 0x80;
607#if 0
608 case SDLK_CLEAR: return 0x;
609 case SDLK_KP_EQUALS: return 0x;
610 case SDLK_COMPOSE: return 0x;
611 case SDLK_HELP: return 0x;
612 case SDLK_BREAK: return 0x;
613 case SDLK_POWER: return 0x;
614 case SDLK_EURO: return 0x;
615 case SDLK_UNDO: return 0x;
616#endif
617 default:
618 Log(("Unhandled sdl key event: sym=%d scancode=%#x unicode=%#x\n",
619 ev->keysym.sym, ev->keysym.scancode, ev->keysym.unicode));
620 return 0;
621 }
622}
623#endif /* RT_OS_DARWIN */
624
625/**
626 * Converts an SDL keyboard eventcode to a XT scancode.
627 *
628 * @returns XT scancode
629 * @param ev SDL scancode
630 */
631uint8_t SDLConsole::keyEventToKeyCode(const SDL_KeyboardEvent *ev)
632{
633 int keycode;
634
635 // start with the scancode determined by SDL
636 keycode = ev->keysym.scancode;
637
638#if defined(RT_OS_LINUX)
639 // workaround for SDL keyboard translation issues on Linux
640 // keycodes > 0x100 are sent as 0xe0 keycode
641 // Note that these are the keycodes used by XFree86/X.org
642 // servers on a Linux host, and will almost certainly not
643 // work on other hosts or on other servers on Linux hosts.
644 // For a more general approach, see the Wine code in the GUI.
645 static const uint8_t x_keycode_to_pc_keycode[61] =
646 {
647 0xc7, /* 97 Home */
648 0xc8, /* 98 Up */
649 0xc9, /* 99 PgUp */
650 0xcb, /* 100 Left */
651 0x4c, /* 101 KP-5 */
652 0xcd, /* 102 Right */
653 0xcf, /* 103 End */
654 0xd0, /* 104 Down */
655 0xd1, /* 105 PgDn */
656 0xd2, /* 106 Ins */
657 0xd3, /* 107 Del */
658 0x9c, /* 108 Enter */
659 0x9d, /* 109 Ctrl-R */
660 0x0, /* 110 Pause */
661 0xb7, /* 111 Print */
662 0xb5, /* 112 Divide */
663 0xb8, /* 113 Alt-R */
664 0xc6, /* 114 Break */
665 0x0, /* 115 */
666 0x0, /* 116 */
667 0x0, /* 117 */
668 0x0, /* 118 */
669 0x0, /* 119 */
670 0x70, /* 120 Hiragana_Katakana */
671 0x0, /* 121 */
672 0x0, /* 122 */
673 0x73, /* 123 backslash */
674 0x0, /* 124 */
675 0x0, /* 125 */
676 0x0, /* 126 */
677 0x0, /* 127 */
678 0x0, /* 128 */
679 0x79, /* 129 Henkan */
680 0x0, /* 130 */
681 0x7b, /* 131 Muhenkan */
682 0x0, /* 132 */
683 0x7d, /* 133 Yen */
684 0x0, /* 134 */
685 0x0, /* 135 */
686 0x47, /* 136 KP_7 */
687 0x48, /* 137 KP_8 */
688 0x49, /* 138 KP_9 */
689 0x4b, /* 139 KP_4 */
690 0x4c, /* 140 KP_5 */
691 0x4d, /* 141 KP_6 */
692 0x4f, /* 142 KP_1 */
693 0x50, /* 143 KP_2 */
694 0x51, /* 144 KP_3 */
695 0x52, /* 145 KP_0 */
696 0x53, /* 146 KP_. */
697 0x47, /* 147 KP_HOME */
698 0x48, /* 148 KP_UP */
699 0x49, /* 149 KP_PgUp */
700 0x4b, /* 150 KP_Left */
701 0x4c, /* 151 KP_ */
702 0x4d, /* 152 KP_Right */
703 0x4f, /* 153 KP_End */
704 0x50, /* 154 KP_Down */
705 0x51, /* 155 KP_PgDn */
706 0x52, /* 156 KP_Ins */
707 0x53, /* 157 KP_Del */
708 };
709
710 if (keycode < 9)
711 {
712 keycode = 0;
713 }
714 else if (keycode < 97)
715 {
716 // just an offset
717 keycode -= 8;
718 }
719 else if (keycode < 158)
720 {
721 // apply conversion table
722 keycode = x_keycode_to_pc_keycode[keycode - 97];
723 }
724 else
725 {
726 keycode = 0;
727 }
728
729#elif defined(RT_OS_DARWIN)
730 /* This is derived partially from SDL_QuartzKeys.h and partially from testing. */
731 static const uint8_t s_aMacToSet1[] =
732 {
733 /* set-1 SDL_QuartzKeys.h */
734 0x1e, /* QZ_a 0x00 */
735 0x1f, /* QZ_s 0x01 */
736 0x20, /* QZ_d 0x02 */
737 0x21, /* QZ_f 0x03 */
738 0x23, /* QZ_h 0x04 */
739 0x22, /* QZ_g 0x05 */
740 0x2c, /* QZ_z 0x06 */
741 0x2d, /* QZ_x 0x07 */
742 0x2e, /* QZ_c 0x08 */
743 0x2f, /* QZ_v 0x09 */
744 0x56, /* between lshift and z. 'INT 1'? */
745 0x30, /* QZ_b 0x0B */
746 0x10, /* QZ_q 0x0C */
747 0x11, /* QZ_w 0x0D */
748 0x12, /* QZ_e 0x0E */
749 0x13, /* QZ_r 0x0F */
750 0x15, /* QZ_y 0x10 */
751 0x14, /* QZ_t 0x11 */
752 0x02, /* QZ_1 0x12 */
753 0x03, /* QZ_2 0x13 */
754 0x04, /* QZ_3 0x14 */
755 0x05, /* QZ_4 0x15 */
756 0x07, /* QZ_6 0x16 */
757 0x06, /* QZ_5 0x17 */
758 0x0d, /* QZ_EQUALS 0x18 */
759 0x0a, /* QZ_9 0x19 */
760 0x08, /* QZ_7 0x1A */
761 0x0c, /* QZ_MINUS 0x1B */
762 0x09, /* QZ_8 0x1C */
763 0x0b, /* QZ_0 0x1D */
764 0x1b, /* QZ_RIGHTBRACKET 0x1E */
765 0x18, /* QZ_o 0x1F */
766 0x16, /* QZ_u 0x20 */
767 0x1a, /* QZ_LEFTBRACKET 0x21 */
768 0x17, /* QZ_i 0x22 */
769 0x19, /* QZ_p 0x23 */
770 0x1c, /* QZ_RETURN 0x24 */
771 0x26, /* QZ_l 0x25 */
772 0x24, /* QZ_j 0x26 */
773 0x28, /* QZ_QUOTE 0x27 */
774 0x25, /* QZ_k 0x28 */
775 0x27, /* QZ_SEMICOLON 0x29 */
776 0x2b, /* QZ_BACKSLASH 0x2A */
777 0x33, /* QZ_COMMA 0x2B */
778 0x35, /* QZ_SLASH 0x2C */
779 0x31, /* QZ_n 0x2D */
780 0x32, /* QZ_m 0x2E */
781 0x34, /* QZ_PERIOD 0x2F */
782 0x0f, /* QZ_TAB 0x30 */
783 0x39, /* QZ_SPACE 0x31 */
784 0x29, /* QZ_BACKQUOTE 0x32 */
785 0x0e, /* QZ_BACKSPACE 0x33 */
786 0x9c, /* QZ_IBOOK_ENTER 0x34 */
787 0x01, /* QZ_ESCAPE 0x35 */
788 0x5c|0x80, /* QZ_RMETA 0x36 */
789 0x5b|0x80, /* QZ_LMETA 0x37 */
790 0x2a, /* QZ_LSHIFT 0x38 */
791 0x3a, /* QZ_CAPSLOCK 0x39 */
792 0x38, /* QZ_LALT 0x3A */
793 0x1d, /* QZ_LCTRL 0x3B */
794 0x36, /* QZ_RSHIFT 0x3C */
795 0x38|0x80, /* QZ_RALT 0x3D */
796 0x1d|0x80, /* QZ_RCTRL 0x3E */
797 0, /* */
798 0, /* */
799 0x53, /* QZ_KP_PERIOD 0x41 */
800 0, /* */
801 0x37, /* QZ_KP_MULTIPLY 0x43 */
802 0, /* */
803 0x4e, /* QZ_KP_PLUS 0x45 */
804 0, /* */
805 0x45, /* QZ_NUMLOCK 0x47 */
806 0, /* */
807 0, /* */
808 0, /* */
809 0x35|0x80, /* QZ_KP_DIVIDE 0x4B */
810 0x1c|0x80, /* QZ_KP_ENTER 0x4C */
811 0, /* */
812 0x4a, /* QZ_KP_MINUS 0x4E */
813 0, /* */
814 0, /* */
815 0x0d/*?*/, /* QZ_KP_EQUALS 0x51 */
816 0x52, /* QZ_KP0 0x52 */
817 0x4f, /* QZ_KP1 0x53 */
818 0x50, /* QZ_KP2 0x54 */
819 0x51, /* QZ_KP3 0x55 */
820 0x4b, /* QZ_KP4 0x56 */
821 0x4c, /* QZ_KP5 0x57 */
822 0x4d, /* QZ_KP6 0x58 */
823 0x47, /* QZ_KP7 0x59 */
824 0, /* */
825 0x48, /* QZ_KP8 0x5B */
826 0x49, /* QZ_KP9 0x5C */
827 0, /* */
828 0, /* */
829 0, /* */
830 0x3f, /* QZ_F5 0x60 */
831 0x40, /* QZ_F6 0x61 */
832 0x41, /* QZ_F7 0x62 */
833 0x3d, /* QZ_F3 0x63 */
834 0x42, /* QZ_F8 0x64 */
835 0x43, /* QZ_F9 0x65 */
836 0, /* */
837 0x57, /* QZ_F11 0x67 */
838 0, /* */
839 0x37|0x80, /* QZ_PRINT / F13 0x69 */
840 0x63, /* QZ_F16 0x6A */
841 0x46, /* QZ_SCROLLOCK 0x6B */
842 0, /* */
843 0x44, /* QZ_F10 0x6D */
844 0x5d|0x80, /* */
845 0x58, /* QZ_F12 0x6F */
846 0, /* */
847 0/* 0xe1,0x1d,0x45*/, /* QZ_PAUSE 0x71 */
848 0x52|0x80, /* QZ_INSERT / HELP 0x72 */
849 0x47|0x80, /* QZ_HOME 0x73 */
850 0x49|0x80, /* QZ_PAGEUP 0x74 */
851 0x53|0x80, /* QZ_DELETE 0x75 */
852 0x3e, /* QZ_F4 0x76 */
853 0x4f|0x80, /* QZ_END 0x77 */
854 0x3c, /* QZ_F2 0x78 */
855 0x51|0x80, /* QZ_PAGEDOWN 0x79 */
856 0x3b, /* QZ_F1 0x7A */
857 0x4b|0x80, /* QZ_LEFT 0x7B */
858 0x4d|0x80, /* QZ_RIGHT 0x7C */
859 0x50|0x80, /* QZ_DOWN 0x7D */
860 0x48|0x80, /* QZ_UP 0x7E */
861 0x5e|0x80, /* QZ_POWER 0x7F */ /* have different break key! */
862 };
863
864 if (keycode == 0)
865 {
866 /* This could be a modifier or it could be 'a'. */
867 switch (ev->keysym.sym)
868 {
869 case SDLK_LSHIFT: keycode = 0x2a; break;
870 case SDLK_RSHIFT: keycode = 0x36; break;
871 case SDLK_LCTRL: keycode = 0x1d; break;
872 case SDLK_RCTRL: keycode = 0x1d | 0x80; break;
873 case SDLK_LALT: keycode = 0x38; break;
874 case SDLK_MODE: /* alt gr */
875 case SDLK_RALT: keycode = 0x38 | 0x80; break;
876 case SDLK_RMETA:
877 case SDLK_RSUPER: keycode = 0x5c | 0x80; break;
878 case SDLK_LMETA:
879 case SDLK_LSUPER: keycode = 0x5b | 0x80; break;
880 /* Assumes normal key. */
881 default: keycode = s_aMacToSet1[keycode]; break;
882 }
883 }
884 else
885 {
886 if ((unsigned)keycode < RT_ELEMENTS(s_aMacToSet1))
887 keycode = s_aMacToSet1[keycode];
888 else
889 keycode = 0;
890 if (!keycode)
891 {
892#ifdef DEBUG_bird
893 RTPrintf("Untranslated: keycode=%#x (%d)\n", keycode, keycode);
894#endif
895 keycode = Keyevent2KeycodeFallback(ev);
896 }
897 }
898#ifdef DEBUG_bird
899 RTPrintf("scancode=%#x -> %#x\n", ev->keysym.scancode, keycode);
900#endif
901
902#elif defined(RT_OS_SOLARIS) || defined(RT_OS_OS2)
903 /*
904 * For now, just use the fallback code.
905 */
906 keycode = Keyevent2KeycodeFallback(ev);
907#endif
908 return keycode;
909}
910
911/**
912 * Releases any modifier keys that are currently in pressed state.
913 */
914void SDLConsole::resetKeys(void)
915{
916 int i;
917 for(i = 0; i < 256; i++)
918 {
919 if (gaModifiersState[i])
920 {
921 if (i & 0x80)
922 gKeyboard->PutScancode(0xe0);
923 gKeyboard->PutScancode(i | 0x80);
924 gaModifiersState[i] = 0;
925 }
926 }
927}
928
929/**
930 * Keyboard event handler.
931 *
932 * @param ev SDL keyboard event.
933 */
934void SDLConsole::processKey(SDL_KeyboardEvent *ev)
935{
936 int keycode, v;
937
938#if defined(VBOXSDL_ADVANCED_OPTIONS) && defined(DEBUG) && 0
939#error
940 // first handle the debugger hotkeys
941 uint8_t *keystate = SDL_GetKeyState(NULL);
942 if ((keystate[SDLK_LALT]) && (ev->type == SDL_KEYDOWN))
943 {
944 switch (ev->keysym.sym)
945 {
946 // pressing Alt-F12 toggles the supervisor recompiler
947 case SDLK_F12:
948 {
949 if (gMachineDebugger)
950 {
951 BOOL recompileSupervisor;
952 gMachineDebugger->COMGETTER(RecompileSupervisor)(&recompileSupervisor);
953 gMachineDebugger->COMSETTER(RecompileSupervisor)(!recompileSupervisor);
954 }
955 break;
956 }
957 // pressing Alt-F11 toggles the user recompiler
958 case SDLK_F11:
959 {
960 if (gMachineDebugger)
961 {
962 BOOL recompileUser;
963 gMachineDebugger->COMGETTER(RecompileUser)(&recompileUser);
964 gMachineDebugger->COMSETTER(RecompileUser)(!recompileUser);
965 }
966 break;
967 }
968 // pressing Alt-F10 toggles the patch manager
969 case SDLK_F10:
970 {
971 if (gMachineDebugger)
972 {
973 BOOL patmEnabled;
974 gMachineDebugger->COMGETTER(PATMEnabled)(&patmEnabled);
975 gMachineDebugger->COMSETTER(PATMEnabled)(!patmEnabled);
976 }
977 break;
978 }
979 // pressing Alt-F9 toggles CSAM
980 case SDLK_F9:
981 {
982 if (gMachineDebugger)
983 {
984 BOOL csamEnabled;
985 gMachineDebugger->COMGETTER(CSAMEnabled)(&csamEnabled);
986 gMachineDebugger->COMSETTER(CSAMEnabled)(!csamEnabled);
987 }
988 break;
989 }
990 // pressing Alt-F8 toggles singlestepping mode
991 case SDLK_F8:
992 {
993 if (gMachineDebugger)
994 {
995 BOOL singlestepEnabled;
996 gMachineDebugger->COMGETTER(Singlestep)(&singlestepEnabled);
997 gMachineDebugger->COMSETTER(Singlestep)(!singlestepEnabled);
998 }
999 break;
1000 }
1001
1002 default:
1003 break;
1004 }
1005 }
1006 // pressing Ctrl-F12 toggles the logger
1007 else if ((keystate[SDLK_RCTRL] || keystate[SDLK_LCTRL]) &&
1008 (ev->keysym.sym == SDLK_F12) && (ev->type == SDL_KEYDOWN))
1009 {
1010 PRTLOGGER pLogger = RTLogDefaultInstance();
1011 bool fEnabled = (pLogger && !(pLogger->fFlags & RTLOGFLAGS_DISABLED));
1012 if (fEnabled)
1013 {
1014 RTLogFlags(pLogger, "disabled");
1015 }
1016 else
1017 {
1018 RTLogFlags(pLogger, "nodisabled");
1019 }
1020 }
1021 // pressing F12 sets a logmark
1022 else if ((ev->keysym.sym == SDLK_F12) && (ev->type == SDL_KEYDOWN))
1023 {
1024 RTLogPrintf("****** LOGGING MARK ******\n");
1025 RTLogFlush(NULL);
1026 }
1027 // now update the titlebar flags
1028 updateTitlebar();
1029#endif
1030
1031 // the pause key is the weirdest, needs special handling
1032 if (ev->keysym.sym == SDLK_PAUSE)
1033 {
1034 v = 0;
1035 if (ev->type == SDL_KEYUP)
1036 v |= 0x80;
1037 gKeyboard->PutScancode(0xe1);
1038 gKeyboard->PutScancode(0x1d | v);
1039 gKeyboard->PutScancode(0x45 | v);
1040 return;
1041 }
1042
1043 /*
1044 * Perform SDL key event to scancode conversion
1045 */
1046 keycode = keyEventToKeyCode(ev);
1047
1048 switch(keycode)
1049 {
1050 case 0x00:
1051 {
1052 /* sent when leaving window: reset the modifiers state */
1053 resetKeys();
1054 return;
1055 }
1056
1057 case 0x2a: /* Left Shift */
1058 case 0x36: /* Right Shift */
1059 case 0x1d: /* Left CTRL */
1060 case 0x9d: /* Right CTRL */
1061 case 0x38: /* Left ALT */
1062 case 0xb8: /* Right ALT */
1063 {
1064 if (ev->type == SDL_KEYUP)
1065 gaModifiersState[keycode] = 0;
1066 else
1067 gaModifiersState[keycode] = 1;
1068 break;
1069 }
1070
1071 case 0x45: /* num lock */
1072 case 0x3a: /* caps lock */
1073 {
1074 /* SDL does not send the key up event, so we generate it */
1075 gKeyboard->PutScancode(keycode);
1076 gKeyboard->PutScancode(keycode | 0x80);
1077 return;
1078 }
1079 }
1080
1081 /*
1082 * Now we send the event. Apply extended and release prefixes.
1083 */
1084 if (keycode & 0x80)
1085 gKeyboard->PutScancode(0xe0);
1086 if (ev->type == SDL_KEYUP)
1087 gKeyboard->PutScancode(keycode | 0x80);
1088 else
1089 gKeyboard->PutScancode(keycode & 0x7f);
1090}
1091
1092#ifdef RT_OS_DARWIN
1093
1094RT_C_DECLS_BEGIN
1095/* Private interface in 10.3 and later. */
1096typedef int CGSConnection;
1097typedef enum
1098{
1099 kCGSGlobalHotKeyEnable = 0,
1100 kCGSGlobalHotKeyDisable,
1101 kCGSGlobalHotKeyInvalid = -1 /* bird */
1102} CGSGlobalHotKeyOperatingMode;
1103extern CGSConnection _CGSDefaultConnection(void);
1104extern CGError CGSGetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode *enmMode);
1105extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection Connection, CGSGlobalHotKeyOperatingMode enmMode);
1106RT_C_DECLS_END
1107
1108/** Keeping track of whether we disabled the hotkeys or not. */
1109static bool g_fHotKeysDisabled = false;
1110/** Whether we've connected or not. */
1111static bool g_fConnectedToCGS = false;
1112/** Cached connection. */
1113static CGSConnection g_CGSConnection;
1114
1115/**
1116 * Disables or enabled global hot keys.
1117 */
1118static void DisableGlobalHotKeys(bool fDisable)
1119{
1120 if (!g_fConnectedToCGS)
1121 {
1122 g_CGSConnection = _CGSDefaultConnection();
1123 g_fConnectedToCGS = true;
1124 }
1125
1126 /* get current mode. */
1127 CGSGlobalHotKeyOperatingMode enmMode = kCGSGlobalHotKeyInvalid;
1128 CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmMode);
1129
1130 /* calc new mode. */
1131 if (fDisable)
1132 {
1133 if (enmMode != kCGSGlobalHotKeyEnable)
1134 return;
1135 enmMode = kCGSGlobalHotKeyDisable;
1136 }
1137 else
1138 {
1139 if ( enmMode != kCGSGlobalHotKeyDisable
1140 /*|| !g_fHotKeysDisabled*/)
1141 return;
1142 enmMode = kCGSGlobalHotKeyEnable;
1143 }
1144
1145 /* try set it and check the actual result. */
1146 CGSSetGlobalHotKeyOperatingMode(g_CGSConnection, enmMode);
1147 CGSGlobalHotKeyOperatingMode enmNewMode = kCGSGlobalHotKeyInvalid;
1148 CGSGetGlobalHotKeyOperatingMode(g_CGSConnection, &enmNewMode);
1149 if (enmNewMode == enmMode)
1150 g_fHotKeysDisabled = enmMode == kCGSGlobalHotKeyDisable;
1151}
1152#endif /* RT_OS_DARWIN */
1153
1154/**
1155 * Start grabbing the mouse.
1156 */
1157void SDLConsole::inputGrabStart()
1158{
1159 BOOL fNeedsHostCursor;
1160 gMouse->COMGETTER(NeedsHostCursor)(&fNeedsHostCursor);
1161#ifdef RT_OS_DARWIN
1162 DisableGlobalHotKeys(true);
1163#endif
1164 if (!fNeedsHostCursor)
1165 SDL_ShowCursor(SDL_DISABLE);
1166 SDL_WM_GrabInput(SDL_GRAB_ON);
1167 // dummy read to avoid moving the mouse
1168 SDL_GetRelativeMouseState(NULL, NULL);
1169 mfInputGrab = true;
1170 updateTitlebar();
1171}
1172
1173/**
1174 * End mouse grabbing.
1175 */
1176void SDLConsole::inputGrabEnd()
1177{
1178 BOOL fNeedsHostCursor;
1179 gMouse->COMGETTER(NeedsHostCursor)(&fNeedsHostCursor);
1180 SDL_WM_GrabInput(SDL_GRAB_OFF);
1181 if (!fNeedsHostCursor)
1182 SDL_ShowCursor(SDL_ENABLE);
1183#ifdef RT_OS_DARWIN
1184 DisableGlobalHotKeys(false);
1185#endif
1186 mfInputGrab = false;
1187 updateTitlebar();
1188}
1189
1190/**
1191 * Query mouse position and button state from SDL and send to the VM
1192 *
1193 * @param dz Relative mouse wheel movement
1194 */
1195
1196extern int GetRelativeMouseState(int *, int*);
1197extern int GetMouseState(int *, int*);
1198
1199void SDLConsole::mouseSendEvent(int dz)
1200{
1201 int x, y, state, buttons;
1202 bool abs;
1203 BOOL fMouseAbsolute;
1204 BOOL fNeedsHostCursor;
1205
1206 gMouse->COMGETTER(AbsoluteSupported)(&fMouseAbsolute);
1207 gMouse->COMGETTER(NeedsHostCursor)(&fNeedsHostCursor);
1208 abs = (fMouseAbsolute && !mfInputGrab) || fNeedsHostCursor;
1209
1210 state = abs ? SDL_GetMouseState(&x, &y) : SDL_GetRelativeMouseState(&x, &y);
1211
1212 // process buttons
1213 buttons = 0;
1214 if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
1215 buttons |= PDMIMOUSEPORT_BUTTON_LEFT;
1216 if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
1217 buttons |= PDMIMOUSEPORT_BUTTON_RIGHT;
1218 if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
1219 buttons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
1220
1221 // now send the mouse event
1222 if (abs)
1223 {
1224 /**
1225 * @todo
1226 * PutMouseEventAbsolute() expects x and y starting from 1,1.
1227 * should we do the increment internally in PutMouseEventAbsolute()
1228 * or state it in PutMouseEventAbsolute() docs?
1229 */
1230 /* only send if outside the extra offset area */
1231 if (y >= gFramebuffer->getYOffset())
1232 gMouse->PutMouseEventAbsolute(x + 1, y + 1 - gFramebuffer->getYOffset(), dz, 0, buttons);
1233 }
1234 else
1235 {
1236 gMouse->PutMouseEvent(x, y, dz, 0, buttons);
1237 }
1238}
1239
1240/**
1241 * Update the pointer shape or visibility.
1242 *
1243 * This is called when the mouse pointer shape changes or pointer is
1244 * hidden/displaying. The new shape is passed as a caller allocated
1245 * buffer that will be freed after returning.
1246 *
1247 * @param fVisible Whether the pointer is visible or not.
1248 * @param fAlpha Alpha channel information is present.
1249 * @param xHot Horizontal coordinate of the pointer hot spot.
1250 * @param yHot Vertical coordinate of the pointer hot spot.
1251 * @param width Pointer width in pixels.
1252 * @param height Pointer height in pixels.
1253 * @param pShape The shape buffer. If NULL, then only
1254 * pointer visibility is being changed
1255 */
1256void SDLConsole::onMousePointerShapeChange(bool fVisible,
1257 bool fAlpha, uint32_t xHot,
1258 uint32_t yHot, uint32_t width,
1259 uint32_t height, void *pShape)
1260{
1261 PointerShapeChangeData *data;
1262 data = new PointerShapeChangeData (fVisible, fAlpha, xHot, yHot,
1263 width, height, (const uint8_t *) pShape);
1264 Assert (data);
1265 if (!data)
1266 return;
1267
1268 SDL_Event event = {0};
1269 event.type = SDL_USEREVENT;
1270 event.user.type = SDL_USER_EVENT_POINTER_CHANGE;
1271 event.user.data1 = data;
1272
1273 int rc = SDL_PushEvent (&event);
1274 AssertMsg (!rc, ("Error: SDL_PushEvent was not successful!\n"));
1275 if (rc)
1276 delete data;
1277}
1278
1279void SDLConsole::progressInfo(PVM pVM, unsigned uPercent, void *pvUser)
1280{
1281 if (uPercent != g_uProgressPercent)
1282 {
1283 SDL_Event event = {0};
1284 event.type = SDL_USEREVENT;
1285 event.user.type = SDL_USER_EVENT_UPDATE_TITLEBAR;
1286 SDL_PushEvent(&event);
1287 g_uProgressPercent = uPercent;
1288 }
1289}
1290
1291/**
1292 * Build the titlebar string
1293 */
1294void SDLConsole::updateTitlebar()
1295{
1296 char pszTitle[1024];
1297
1298 RTStrPrintf(pszTitle, sizeof(pszTitle),
1299 "Sun VirtualBox%s%s",
1300 g_uProgressPercent == ~0U && machineState == VMSTATE_SUSPENDED ? " - [Paused]" : "",
1301 mfInputGrab ? " - [Input captured]": "");
1302
1303 if (g_uProgressPercent != ~0U)
1304 RTStrPrintf(pszTitle + strlen(pszTitle), sizeof(pszTitle) - strlen(pszTitle),
1305 " - %s: %u%%", g_pszProgressString, g_uProgressPercent);
1306
1307#if defined(VBOXSDL_ADVANCED_OPTIONS) && defined(DEBUG)
1308 // do we have a debugger interface
1309 if (gMachineDebugger)
1310 {
1311 // query the machine state
1312 BOOL recompileSupervisor = FALSE;
1313 BOOL recompileUser = FALSE;
1314 BOOL patmEnabled = FALSE;
1315 BOOL csamEnabled = FALSE;
1316 BOOL singlestepEnabled = FALSE;
1317 gMachineDebugger->COMGETTER(RecompileSupervisor)(&recompileSupervisor);
1318 gMachineDebugger->COMGETTER(RecompileUser)(&recompileUser);
1319 gMachineDebugger->COMGETTER(PATMEnabled)(&patmEnabled);
1320 gMachineDebugger->COMGETTER(CSAMEnabled)(&csamEnabled);
1321 gMachineDebugger->COMGETTER(Singlestep)(&singlestepEnabled);
1322 PRTLOGGER pLogger = RTLogDefaultInstance();
1323 bool fEnabled = (pLogger && !(pLogger->fFlags & RTLOGFLAGS_DISABLED));
1324 RTStrPrintf(pszTitle + strlen(pszTitle), sizeof(pszTitle) - strlen(pszTitle),
1325 " [STEP=%d CS=%d PAT=%d RR0=%d RR3=%d LOG=%d]",
1326 singlestepEnabled == TRUE, csamEnabled == TRUE, patmEnabled == TRUE,
1327 recompileSupervisor == FALSE, recompileUser == FALSE, fEnabled == TRUE);
1328 }
1329#endif /* DEBUG */
1330
1331 SDL_WM_SetCaption(pszTitle, "Sun vXM VirtualBox");
1332}
1333
1334/**
1335 * Updates the title bar while saving the state.
1336 * @param iPercent Percentage.
1337 */
1338void SDLConsole::updateTitlebarProgress(const char *pszStr, int iPercent)
1339{
1340 char szTitle[256];
1341 AssertMsg(iPercent >= 0 && iPercent <= 100, ("%d\n", iPercent));
1342 RTStrPrintf(szTitle, sizeof(szTitle), "Sun VirtualBox - %s %d%%...", pszStr, iPercent);
1343 SDL_WM_SetCaption(szTitle, "Sun VirtualBox");
1344}
1345
1346/**
1347 * Sets the pointer shape according to parameters.
1348 * Must be called only from the main SDL thread.
1349 */
1350void SDLConsole::setPointerShape (const PointerShapeChangeData *data)
1351{
1352 /*
1353 * don't do anything if there are no guest additions loaded (anymore)
1354 */
1355 BOOL fMouseAbsolute;
1356 gMouse->COMGETTER(AbsoluteSupported)(&fMouseAbsolute);
1357 if (!fMouseAbsolute)
1358 return;
1359
1360 if (data->shape)
1361 {
1362 bool ok = false;
1363
1364 uint32_t andMaskSize = (data->width + 7) / 8 * data->height;
1365 uint32_t srcShapePtrScan = data->width * 4;
1366
1367 const uint8_t *srcAndMaskPtr = data->shape;
1368 const uint8_t *srcShapePtr = data->shape + ((andMaskSize + 3) & ~3);
1369
1370#if defined (RT_OS_WINDOWS)
1371
1372 BITMAPV5HEADER bi;
1373 HBITMAP hBitmap;
1374 void *lpBits;
1375 HCURSOR hAlphaCursor = NULL;
1376
1377 ::ZeroMemory (&bi, sizeof (BITMAPV5HEADER));
1378 bi.bV5Size = sizeof (BITMAPV5HEADER);
1379 bi.bV5Width = data->width;
1380 bi.bV5Height = - (LONG) data->height;
1381 bi.bV5Planes = 1;
1382 bi.bV5BitCount = 32;
1383 bi.bV5Compression = BI_BITFIELDS;
1384 // specifiy a supported 32 BPP alpha format for Windows XP
1385 bi.bV5RedMask = 0x00FF0000;
1386 bi.bV5GreenMask = 0x0000FF00;
1387 bi.bV5BlueMask = 0x000000FF;
1388 if (data->alpha)
1389 bi.bV5AlphaMask = 0xFF000000;
1390 else
1391 bi.bV5AlphaMask = 0;
1392
1393 HDC hdc = ::GetDC (NULL);
1394
1395 // create the DIB section with an alpha channel
1396 hBitmap = ::CreateDIBSection (hdc, (BITMAPINFO *) &bi, DIB_RGB_COLORS,
1397 (void **) &lpBits, NULL, (DWORD) 0);
1398
1399 ::ReleaseDC (NULL, hdc);
1400
1401 HBITMAP hMonoBitmap = NULL;
1402 if (data->alpha)
1403 {
1404 // create an empty mask bitmap
1405 hMonoBitmap = ::CreateBitmap (data->width, data->height, 1, 1, NULL);
1406 }
1407 else
1408 {
1409 // for now, we assert if width is not multiple of 16. the
1410 // alternative is to manually align the AND mask to 16 bits.
1411 AssertMsg (!(data->width % 16), ("AND mask must be word-aligned!\n"));
1412
1413 // create the AND mask bitmap
1414 hMonoBitmap = ::CreateBitmap (data->width, data->height, 1, 1,
1415 srcAndMaskPtr);
1416 }
1417
1418 Assert (hBitmap);
1419 Assert (hMonoBitmap);
1420 if (hBitmap && hMonoBitmap)
1421 {
1422 DWORD *dstShapePtr = (DWORD *) lpBits;
1423
1424 for (uint32_t y = 0; y < data->height; y ++)
1425 {
1426 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
1427 srcShapePtr += srcShapePtrScan;
1428 dstShapePtr += data->width;
1429 }
1430
1431 ICONINFO ii;
1432 ii.fIcon = FALSE;
1433 ii.xHotspot = data->xHot;
1434 ii.yHotspot = data->yHot;
1435 ii.hbmMask = hMonoBitmap;
1436 ii.hbmColor = hBitmap;
1437
1438 hAlphaCursor = ::CreateIconIndirect (&ii);
1439 Assert (hAlphaCursor);
1440 if (hAlphaCursor)
1441 {
1442 // here we do a dirty trick by substituting a Window Manager's
1443 // cursor handle with the handle we created
1444
1445 WMcursor *old_wm_cursor = gpCustomCursor->wm_cursor;
1446
1447 // see SDL12/src/video/wincommon/SDL_sysmouse.c
1448 void *wm_cursor = malloc (sizeof (HCURSOR) + sizeof (uint8_t *) * 2);
1449 *(HCURSOR *) wm_cursor = hAlphaCursor;
1450
1451 gpCustomCursor->wm_cursor = (WMcursor *) wm_cursor;
1452 SDL_SetCursor (gpCustomCursor);
1453 SDL_ShowCursor (SDL_ENABLE);
1454
1455 if (old_wm_cursor)
1456 {
1457 ::DestroyCursor (* (HCURSOR *) old_wm_cursor);
1458 free (old_wm_cursor);
1459 }
1460
1461 ok = true;
1462 }
1463 }
1464
1465 if (hMonoBitmap)
1466 ::DeleteObject (hMonoBitmap);
1467 if (hBitmap)
1468 ::DeleteObject (hBitmap);
1469
1470#elif defined(VBOXBFE_WITH_X11) && !defined(VBOXBFE_WITHOUT_XCURSOR)
1471
1472 XcursorImage *img = XcursorImageCreate (data->width, data->height);
1473 Assert (img);
1474 if (img)
1475 {
1476 img->xhot = data->xHot;
1477 img->yhot = data->yHot;
1478
1479 XcursorPixel *dstShapePtr = img->pixels;
1480
1481 for (uint32_t y = 0; y < data->height; y ++)
1482 {
1483 memcpy (dstShapePtr, srcShapePtr, srcShapePtrScan);
1484
1485 if (!data->alpha)
1486 {
1487 // convert AND mask to the alpha channel
1488 uint8_t byte = 0;
1489 for (uint32_t x = 0; x < data->width; x ++)
1490 {
1491 if (!(x % 8))
1492 byte = *(srcAndMaskPtr ++);
1493 else
1494 byte <<= 1;
1495
1496 if (byte & 0x80)
1497 {
1498 // X11 doesn't support inverted pixels (XOR ops,
1499 // to be exact) in cursor shapes, so we detect such
1500 // pixels and always replace them with black ones to
1501 // make them visible at least over light colors
1502 if (dstShapePtr [x] & 0x00FFFFFF)
1503 dstShapePtr [x] = 0xFF000000;
1504 else
1505 dstShapePtr [x] = 0x00000000;
1506 }
1507 else
1508 dstShapePtr [x] |= 0xFF000000;
1509 }
1510 }
1511
1512 srcShapePtr += srcShapePtrScan;
1513 dstShapePtr += data->width;
1514 }
1515
1516 Cursor cur = XcursorImageLoadCursor (gSdlInfo.info.x11.display, img);
1517 Assert (cur);
1518 if (cur)
1519 {
1520 // here we do a dirty trick by substituting a Window Manager's
1521 // cursor handle with the handle we created
1522
1523 WMcursor *old_wm_cursor = gpCustomCursor->wm_cursor;
1524
1525 // see SDL12/src/video/x11/SDL_x11mouse.c
1526 void *wm_cursor = malloc (sizeof (Cursor));
1527 *(Cursor *) wm_cursor = cur;
1528
1529 gpCustomCursor->wm_cursor = (WMcursor *) wm_cursor;
1530 SDL_SetCursor (gpCustomCursor);
1531 SDL_ShowCursor (SDL_ENABLE);
1532
1533 if (old_wm_cursor)
1534 {
1535 XFreeCursor (gSdlInfo.info.x11.display, *(Cursor *) old_wm_cursor);
1536 free (old_wm_cursor);
1537 }
1538
1539 ok = true;
1540 }
1541
1542 XcursorImageDestroy (img);
1543 }
1544
1545#endif /* VBOXBFE_WITH_X11 */
1546
1547 if (!ok)
1548 {
1549 SDL_SetCursor (gpDefaultCursor);
1550 SDL_ShowCursor (SDL_ENABLE);
1551 }
1552 }
1553 else
1554 {
1555 if (data->visible)
1556 {
1557 SDL_ShowCursor (SDL_ENABLE);
1558 }
1559 else
1560 {
1561 SDL_ShowCursor (SDL_DISABLE);
1562 }
1563 }
1564}
1565
1566void SDLConsole::resetCursor(void)
1567{
1568 SDL_SetCursor (gpDefaultCursor);
1569 SDL_ShowCursor (SDL_ENABLE);
1570}
1571
1572/**
1573 * Handles a host key down event
1574 */
1575int SDLConsole::handleHostKey(const SDL_KeyboardEvent *pEv)
1576{
1577 /*
1578 * Revalidate the host key modifier
1579 */
1580 if ((SDL_GetModState() & ~(KMOD_MODE | KMOD_NUM | KMOD_RESERVED)) != gHostKey)
1581 return VERR_NOT_SUPPORTED;
1582
1583 /*
1584 * What was pressed?
1585 */
1586 switch (pEv->keysym.sym)
1587 {
1588 /* Control-Alt-Delete */
1589 case SDLK_DELETE:
1590 {
1591 gKeyboard->PutCAD();
1592 break;
1593 }
1594
1595 /*
1596 * Fullscreen / Windowed toggle.
1597 */
1598 case SDLK_f:
1599 {
1600 VMCtrlToggleFullscreen();
1601 break;
1602 }
1603
1604 /*
1605 * Pause / Resume toggle.
1606 */
1607 case SDLK_p:
1608 {
1609 if (machineState == VMSTATE_RUNNING)
1610 VMCtrlPause();
1611 else
1612 VMCtrlResume();
1613 updateTitlebar();
1614 break;
1615 }
1616
1617 /*
1618 * Reset the VM
1619 */
1620 case SDLK_r:
1621 {
1622 VMCtrlReset();
1623 break;
1624 }
1625
1626 /*
1627 * Terminate the VM
1628 */
1629 case SDLK_q:
1630 {
1631 return VINF_EM_TERMINATE;
1632 break;
1633 }
1634
1635 /*
1636 * Send ACPI power button press event
1637 */
1638 case SDLK_h:
1639 {
1640 VMCtrlACPIPowerButton();
1641 break;
1642 }
1643
1644 /*
1645 * Save the machine's state and exit
1646 */
1647 case SDLK_s:
1648 {
1649 VMCtrlSave(doEventQuit);
1650 break;
1651 }
1652
1653 /*
1654 * Not a host key combination.
1655 * Indicate this by returning false.
1656 */
1657 default:
1658 return VERR_NOT_SUPPORTED;
1659 }
1660
1661 return VINF_SUCCESS;
1662}
1663
Note: See TracBrowser for help on using the repository browser.

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