VirtualBox

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

Last change on this file since 24733 was 20850, checked in by vboxsync, 15 years ago

typo

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