VirtualBox

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

Last change on this file since 6238 was 6238, checked in by vboxsync, 17 years ago

VBoxBFE: L4: forward port of the latest VBoxBFE changes

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