VirtualBox

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

Last change on this file since 30045 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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