sdl.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. /*
  2. * QEMU SDL display driver
  3. *
  4. * Copyright (c) 2003 Fabrice Bellard
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. /* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
  25. #undef WIN32_LEAN_AND_MEAN
  26. #include <SDL.h>
  27. #include <SDL_syswm.h>
  28. #include "qemu-common.h"
  29. #include "ui/console.h"
  30. #include "sysemu/sysemu.h"
  31. #include "x_keymap.h"
  32. #include "sdl_zoom.h"
  33. static DisplayChangeListener *dcl;
  34. static SDL_Surface *real_screen;
  35. static SDL_Surface *guest_screen = NULL;
  36. static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
  37. static int last_vm_running;
  38. static bool gui_saved_scaling;
  39. static int gui_saved_width;
  40. static int gui_saved_height;
  41. static int gui_saved_grab;
  42. static int gui_fullscreen;
  43. static int gui_noframe;
  44. static int gui_key_modifier_pressed;
  45. static int gui_keysym;
  46. static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
  47. static uint8_t modifiers_state[256];
  48. static SDL_Cursor *sdl_cursor_normal;
  49. static SDL_Cursor *sdl_cursor_hidden;
  50. static int absolute_enabled = 0;
  51. static int guest_cursor = 0;
  52. static int guest_x, guest_y;
  53. static SDL_Cursor *guest_sprite = NULL;
  54. static SDL_PixelFormat host_format;
  55. static int scaling_active = 0;
  56. static Notifier mouse_mode_notifier;
  57. static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
  58. {
  59. // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
  60. SDL_Rect rec;
  61. rec.x = x;
  62. rec.y = y;
  63. rec.w = w;
  64. rec.h = h;
  65. if (guest_screen) {
  66. if (!scaling_active) {
  67. SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
  68. } else {
  69. if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
  70. fprintf(stderr, "Zoom blit failed\n");
  71. exit(1);
  72. }
  73. }
  74. }
  75. SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
  76. }
  77. static void sdl_setdata(DisplayState *ds)
  78. {
  79. if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
  80. guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
  81. ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
  82. ds->surface->pf.rmask, ds->surface->pf.gmask,
  83. ds->surface->pf.bmask, ds->surface->pf.amask);
  84. }
  85. static void do_sdl_resize(int width, int height, int bpp)
  86. {
  87. int flags;
  88. // printf("resizing to %d %d\n", w, h);
  89. flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
  90. if (gui_fullscreen) {
  91. flags |= SDL_FULLSCREEN;
  92. } else {
  93. flags |= SDL_RESIZABLE;
  94. }
  95. if (gui_noframe)
  96. flags |= SDL_NOFRAME;
  97. real_screen = SDL_SetVideoMode(width, height, bpp, flags);
  98. if (!real_screen) {
  99. fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width,
  100. height, bpp, SDL_GetError());
  101. exit(1);
  102. }
  103. }
  104. static void sdl_resize(DisplayState *ds)
  105. {
  106. if (!scaling_active) {
  107. do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
  108. } else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds)) {
  109. do_sdl_resize(real_screen->w, real_screen->h,
  110. ds_get_bits_per_pixel(ds));
  111. }
  112. sdl_setdata(ds);
  113. }
  114. /* generic keyboard conversion */
  115. #include "sdl_keysym.h"
  116. static kbd_layout_t *kbd_layout = NULL;
  117. static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
  118. {
  119. int keysym;
  120. /* workaround for X11+SDL bug with AltGR */
  121. keysym = ev->keysym.sym;
  122. if (keysym == 0 && ev->keysym.scancode == 113)
  123. keysym = SDLK_MODE;
  124. /* For Japanese key '\' and '|' */
  125. if (keysym == 92 && ev->keysym.scancode == 133) {
  126. keysym = 0xa5;
  127. }
  128. return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
  129. }
  130. /* specific keyboard conversions from scan codes */
  131. #if defined(_WIN32)
  132. static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
  133. {
  134. return ev->keysym.scancode;
  135. }
  136. #else
  137. #if defined(SDL_VIDEO_DRIVER_X11)
  138. #include <X11/XKBlib.h>
  139. static int check_for_evdev(void)
  140. {
  141. SDL_SysWMinfo info;
  142. XkbDescPtr desc = NULL;
  143. int has_evdev = 0;
  144. char *keycodes = NULL;
  145. SDL_VERSION(&info.version);
  146. if (!SDL_GetWMInfo(&info)) {
  147. return 0;
  148. }
  149. desc = XkbGetKeyboard(info.info.x11.display,
  150. XkbGBN_AllComponentsMask,
  151. XkbUseCoreKbd);
  152. if (desc && desc->names) {
  153. keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
  154. if (keycodes == NULL) {
  155. fprintf(stderr, "could not lookup keycode name\n");
  156. } else if (strstart(keycodes, "evdev", NULL)) {
  157. has_evdev = 1;
  158. } else if (!strstart(keycodes, "xfree86", NULL)) {
  159. fprintf(stderr, "unknown keycodes `%s', please report to "
  160. "qemu-devel@nongnu.org\n", keycodes);
  161. }
  162. }
  163. if (desc) {
  164. XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
  165. }
  166. if (keycodes) {
  167. XFree(keycodes);
  168. }
  169. return has_evdev;
  170. }
  171. #else
  172. static int check_for_evdev(void)
  173. {
  174. return 0;
  175. }
  176. #endif
  177. static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
  178. {
  179. int keycode;
  180. static int has_evdev = -1;
  181. if (has_evdev == -1)
  182. has_evdev = check_for_evdev();
  183. keycode = ev->keysym.scancode;
  184. if (keycode < 9) {
  185. keycode = 0;
  186. } else if (keycode < 97) {
  187. keycode -= 8; /* just an offset */
  188. } else if (keycode < 158) {
  189. /* use conversion table */
  190. if (has_evdev)
  191. keycode = translate_evdev_keycode(keycode - 97);
  192. else
  193. keycode = translate_xfree86_keycode(keycode - 97);
  194. } else if (keycode == 208) { /* Hiragana_Katakana */
  195. keycode = 0x70;
  196. } else if (keycode == 211) { /* backslash */
  197. keycode = 0x73;
  198. } else {
  199. keycode = 0;
  200. }
  201. return keycode;
  202. }
  203. #endif
  204. static void reset_keys(void)
  205. {
  206. int i;
  207. for(i = 0; i < 256; i++) {
  208. if (modifiers_state[i]) {
  209. if (i & SCANCODE_GREY)
  210. kbd_put_keycode(SCANCODE_EMUL0);
  211. kbd_put_keycode(i | SCANCODE_UP);
  212. modifiers_state[i] = 0;
  213. }
  214. }
  215. }
  216. static void sdl_process_key(SDL_KeyboardEvent *ev)
  217. {
  218. int keycode, v;
  219. if (ev->keysym.sym == SDLK_PAUSE) {
  220. /* specific case */
  221. v = 0;
  222. if (ev->type == SDL_KEYUP)
  223. v |= SCANCODE_UP;
  224. kbd_put_keycode(0xe1);
  225. kbd_put_keycode(0x1d | v);
  226. kbd_put_keycode(0x45 | v);
  227. return;
  228. }
  229. if (kbd_layout) {
  230. keycode = sdl_keyevent_to_keycode_generic(ev);
  231. } else {
  232. keycode = sdl_keyevent_to_keycode(ev);
  233. }
  234. switch(keycode) {
  235. case 0x00:
  236. /* sent when leaving window: reset the modifiers state */
  237. reset_keys();
  238. return;
  239. case 0x2a: /* Left Shift */
  240. case 0x36: /* Right Shift */
  241. case 0x1d: /* Left CTRL */
  242. case 0x9d: /* Right CTRL */
  243. case 0x38: /* Left ALT */
  244. case 0xb8: /* Right ALT */
  245. if (ev->type == SDL_KEYUP)
  246. modifiers_state[keycode] = 0;
  247. else
  248. modifiers_state[keycode] = 1;
  249. break;
  250. #define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION)
  251. #if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14
  252. /* SDL versions before 1.2.14 don't support key up for caps/num lock. */
  253. case 0x45: /* num lock */
  254. case 0x3a: /* caps lock */
  255. /* SDL does not send the key up event, so we generate it */
  256. kbd_put_keycode(keycode);
  257. kbd_put_keycode(keycode | SCANCODE_UP);
  258. return;
  259. #endif
  260. }
  261. /* now send the key code */
  262. if (keycode & SCANCODE_GREY)
  263. kbd_put_keycode(SCANCODE_EMUL0);
  264. if (ev->type == SDL_KEYUP)
  265. kbd_put_keycode(keycode | SCANCODE_UP);
  266. else
  267. kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
  268. }
  269. static void sdl_update_caption(void)
  270. {
  271. char win_title[1024];
  272. char icon_title[1024];
  273. const char *status = "";
  274. if (!runstate_is_running())
  275. status = " [Stopped]";
  276. else if (gui_grab) {
  277. if (alt_grab)
  278. status = " - Press Ctrl-Alt-Shift to exit mouse grab";
  279. else if (ctrl_grab)
  280. status = " - Press Right-Ctrl to exit mouse grab";
  281. else
  282. status = " - Press Ctrl-Alt to exit mouse grab";
  283. }
  284. if (qemu_name) {
  285. snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
  286. snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
  287. } else {
  288. snprintf(win_title, sizeof(win_title), "QEMU%s", status);
  289. snprintf(icon_title, sizeof(icon_title), "QEMU");
  290. }
  291. SDL_WM_SetCaption(win_title, icon_title);
  292. }
  293. static void sdl_hide_cursor(void)
  294. {
  295. if (!cursor_hide)
  296. return;
  297. if (kbd_mouse_is_absolute()) {
  298. SDL_ShowCursor(1);
  299. SDL_SetCursor(sdl_cursor_hidden);
  300. } else {
  301. SDL_ShowCursor(0);
  302. }
  303. }
  304. static void sdl_show_cursor(void)
  305. {
  306. if (!cursor_hide)
  307. return;
  308. if (!kbd_mouse_is_absolute() || !is_graphic_console()) {
  309. SDL_ShowCursor(1);
  310. if (guest_cursor &&
  311. (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
  312. SDL_SetCursor(guest_sprite);
  313. else
  314. SDL_SetCursor(sdl_cursor_normal);
  315. }
  316. }
  317. static void sdl_grab_start(void)
  318. {
  319. /*
  320. * If the application is not active, do not try to enter grab state. This
  321. * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
  322. * application (SDL bug).
  323. */
  324. if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) {
  325. return;
  326. }
  327. if (guest_cursor) {
  328. SDL_SetCursor(guest_sprite);
  329. if (!kbd_mouse_is_absolute() && !absolute_enabled)
  330. SDL_WarpMouse(guest_x, guest_y);
  331. } else
  332. sdl_hide_cursor();
  333. SDL_WM_GrabInput(SDL_GRAB_ON);
  334. gui_grab = 1;
  335. sdl_update_caption();
  336. }
  337. static void sdl_grab_end(void)
  338. {
  339. SDL_WM_GrabInput(SDL_GRAB_OFF);
  340. gui_grab = 0;
  341. sdl_show_cursor();
  342. sdl_update_caption();
  343. }
  344. static void absolute_mouse_grab(void)
  345. {
  346. int mouse_x, mouse_y;
  347. SDL_GetMouseState(&mouse_x, &mouse_y);
  348. if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
  349. mouse_y > 0 && mouse_y < real_screen->h - 1) {
  350. sdl_grab_start();
  351. }
  352. }
  353. static void sdl_mouse_mode_change(Notifier *notify, void *data)
  354. {
  355. if (kbd_mouse_is_absolute()) {
  356. if (!absolute_enabled) {
  357. absolute_enabled = 1;
  358. if (is_graphic_console()) {
  359. absolute_mouse_grab();
  360. }
  361. }
  362. } else if (absolute_enabled) {
  363. if (!gui_fullscreen) {
  364. sdl_grab_end();
  365. }
  366. absolute_enabled = 0;
  367. }
  368. }
  369. static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
  370. {
  371. int buttons = 0;
  372. if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
  373. buttons |= MOUSE_EVENT_LBUTTON;
  374. }
  375. if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
  376. buttons |= MOUSE_EVENT_RBUTTON;
  377. }
  378. if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
  379. buttons |= MOUSE_EVENT_MBUTTON;
  380. }
  381. if (kbd_mouse_is_absolute()) {
  382. dx = x * 0x7FFF / (real_screen->w - 1);
  383. dy = y * 0x7FFF / (real_screen->h - 1);
  384. } else if (guest_cursor) {
  385. x -= guest_x;
  386. y -= guest_y;
  387. guest_x += x;
  388. guest_y += y;
  389. dx = x;
  390. dy = y;
  391. }
  392. kbd_mouse_event(dx, dy, dz, buttons);
  393. }
  394. static void sdl_scale(DisplayState *ds, int width, int height)
  395. {
  396. int bpp = real_screen->format->BitsPerPixel;
  397. if (bpp != 16 && bpp != 32) {
  398. bpp = 32;
  399. }
  400. do_sdl_resize(width, height, bpp);
  401. scaling_active = 1;
  402. if (!is_buffer_shared(ds->surface)) {
  403. ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds),
  404. ds_get_height(ds));
  405. dpy_gfx_resize(ds);
  406. }
  407. }
  408. static void toggle_full_screen(DisplayState *ds)
  409. {
  410. gui_fullscreen = !gui_fullscreen;
  411. if (gui_fullscreen) {
  412. gui_saved_width = real_screen->w;
  413. gui_saved_height = real_screen->h;
  414. gui_saved_scaling = scaling_active;
  415. do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
  416. ds_get_bits_per_pixel(ds));
  417. scaling_active = 0;
  418. gui_saved_grab = gui_grab;
  419. sdl_grab_start();
  420. } else {
  421. if (gui_saved_scaling) {
  422. sdl_scale(ds, gui_saved_width, gui_saved_height);
  423. } else {
  424. do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
  425. }
  426. if (!gui_saved_grab || !is_graphic_console()) {
  427. sdl_grab_end();
  428. }
  429. }
  430. vga_hw_invalidate();
  431. vga_hw_update();
  432. }
  433. static void handle_keydown(DisplayState *ds, SDL_Event *ev)
  434. {
  435. int mod_state;
  436. int keycode;
  437. if (alt_grab) {
  438. mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
  439. (gui_grab_code | KMOD_LSHIFT);
  440. } else if (ctrl_grab) {
  441. mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
  442. } else {
  443. mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
  444. }
  445. gui_key_modifier_pressed = mod_state;
  446. if (gui_key_modifier_pressed) {
  447. keycode = sdl_keyevent_to_keycode(&ev->key);
  448. switch (keycode) {
  449. case 0x21: /* 'f' key on US keyboard */
  450. toggle_full_screen(ds);
  451. gui_keysym = 1;
  452. break;
  453. case 0x16: /* 'u' key on US keyboard */
  454. if (scaling_active) {
  455. scaling_active = 0;
  456. sdl_resize(ds);
  457. vga_hw_invalidate();
  458. vga_hw_update();
  459. }
  460. gui_keysym = 1;
  461. break;
  462. case 0x02 ... 0x0a: /* '1' to '9' keys */
  463. /* Reset the modifiers sent to the current console */
  464. reset_keys();
  465. console_select(keycode - 0x02);
  466. gui_keysym = 1;
  467. if (gui_fullscreen) {
  468. break;
  469. }
  470. if (!is_graphic_console()) {
  471. /* release grab if going to a text console */
  472. if (gui_grab) {
  473. sdl_grab_end();
  474. } else if (absolute_enabled) {
  475. sdl_show_cursor();
  476. }
  477. } else if (absolute_enabled) {
  478. sdl_hide_cursor();
  479. absolute_mouse_grab();
  480. }
  481. break;
  482. case 0x1b: /* '+' */
  483. case 0x35: /* '-' */
  484. if (!gui_fullscreen) {
  485. int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50),
  486. 160);
  487. int height = (ds_get_height(ds) * width) / ds_get_width(ds);
  488. sdl_scale(ds, width, height);
  489. vga_hw_invalidate();
  490. vga_hw_update();
  491. gui_keysym = 1;
  492. }
  493. default:
  494. break;
  495. }
  496. } else if (!is_graphic_console()) {
  497. int keysym = 0;
  498. if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
  499. switch (ev->key.keysym.sym) {
  500. case SDLK_UP:
  501. keysym = QEMU_KEY_CTRL_UP;
  502. break;
  503. case SDLK_DOWN:
  504. keysym = QEMU_KEY_CTRL_DOWN;
  505. break;
  506. case SDLK_LEFT:
  507. keysym = QEMU_KEY_CTRL_LEFT;
  508. break;
  509. case SDLK_RIGHT:
  510. keysym = QEMU_KEY_CTRL_RIGHT;
  511. break;
  512. case SDLK_HOME:
  513. keysym = QEMU_KEY_CTRL_HOME;
  514. break;
  515. case SDLK_END:
  516. keysym = QEMU_KEY_CTRL_END;
  517. break;
  518. case SDLK_PAGEUP:
  519. keysym = QEMU_KEY_CTRL_PAGEUP;
  520. break;
  521. case SDLK_PAGEDOWN:
  522. keysym = QEMU_KEY_CTRL_PAGEDOWN;
  523. break;
  524. default:
  525. break;
  526. }
  527. } else {
  528. switch (ev->key.keysym.sym) {
  529. case SDLK_UP:
  530. keysym = QEMU_KEY_UP;
  531. break;
  532. case SDLK_DOWN:
  533. keysym = QEMU_KEY_DOWN;
  534. break;
  535. case SDLK_LEFT:
  536. keysym = QEMU_KEY_LEFT;
  537. break;
  538. case SDLK_RIGHT:
  539. keysym = QEMU_KEY_RIGHT;
  540. break;
  541. case SDLK_HOME:
  542. keysym = QEMU_KEY_HOME;
  543. break;
  544. case SDLK_END:
  545. keysym = QEMU_KEY_END;
  546. break;
  547. case SDLK_PAGEUP:
  548. keysym = QEMU_KEY_PAGEUP;
  549. break;
  550. case SDLK_PAGEDOWN:
  551. keysym = QEMU_KEY_PAGEDOWN;
  552. break;
  553. case SDLK_BACKSPACE:
  554. keysym = QEMU_KEY_BACKSPACE;
  555. break;
  556. case SDLK_DELETE:
  557. keysym = QEMU_KEY_DELETE;
  558. break;
  559. default:
  560. break;
  561. }
  562. }
  563. if (keysym) {
  564. kbd_put_keysym(keysym);
  565. } else if (ev->key.keysym.unicode != 0) {
  566. kbd_put_keysym(ev->key.keysym.unicode);
  567. }
  568. }
  569. if (is_graphic_console() && !gui_keysym) {
  570. sdl_process_key(&ev->key);
  571. }
  572. }
  573. static void handle_keyup(DisplayState *ds, SDL_Event *ev)
  574. {
  575. int mod_state;
  576. if (!alt_grab) {
  577. mod_state = (ev->key.keysym.mod & gui_grab_code);
  578. } else {
  579. mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
  580. }
  581. if (!mod_state && gui_key_modifier_pressed) {
  582. gui_key_modifier_pressed = 0;
  583. if (gui_keysym == 0) {
  584. /* exit/enter grab if pressing Ctrl-Alt */
  585. if (!gui_grab) {
  586. if (is_graphic_console()) {
  587. sdl_grab_start();
  588. }
  589. } else if (!gui_fullscreen) {
  590. sdl_grab_end();
  591. }
  592. /* SDL does not send back all the modifiers key, so we must
  593. * correct it. */
  594. reset_keys();
  595. return;
  596. }
  597. gui_keysym = 0;
  598. }
  599. if (is_graphic_console() && !gui_keysym) {
  600. sdl_process_key(&ev->key);
  601. }
  602. }
  603. static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
  604. {
  605. int max_x, max_y;
  606. if (is_graphic_console() &&
  607. (kbd_mouse_is_absolute() || absolute_enabled)) {
  608. max_x = real_screen->w - 1;
  609. max_y = real_screen->h - 1;
  610. if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
  611. ev->motion.x == max_x || ev->motion.y == max_y)) {
  612. sdl_grab_end();
  613. }
  614. if (!gui_grab &&
  615. (ev->motion.x > 0 && ev->motion.x < max_x &&
  616. ev->motion.y > 0 && ev->motion.y < max_y)) {
  617. sdl_grab_start();
  618. }
  619. }
  620. if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
  621. sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
  622. ev->motion.x, ev->motion.y, ev->motion.state);
  623. }
  624. }
  625. static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
  626. {
  627. int buttonstate = SDL_GetMouseState(NULL, NULL);
  628. SDL_MouseButtonEvent *bev;
  629. int dz;
  630. if (!is_graphic_console()) {
  631. return;
  632. }
  633. bev = &ev->button;
  634. if (!gui_grab && !kbd_mouse_is_absolute()) {
  635. if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
  636. /* start grabbing all events */
  637. sdl_grab_start();
  638. }
  639. } else {
  640. dz = 0;
  641. if (ev->type == SDL_MOUSEBUTTONDOWN) {
  642. buttonstate |= SDL_BUTTON(bev->button);
  643. } else {
  644. buttonstate &= ~SDL_BUTTON(bev->button);
  645. }
  646. #ifdef SDL_BUTTON_WHEELUP
  647. if (bev->button == SDL_BUTTON_WHEELUP &&
  648. ev->type == SDL_MOUSEBUTTONDOWN) {
  649. dz = -1;
  650. } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
  651. ev->type == SDL_MOUSEBUTTONDOWN) {
  652. dz = 1;
  653. }
  654. #endif
  655. sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
  656. }
  657. }
  658. static void handle_activation(DisplayState *ds, SDL_Event *ev)
  659. {
  660. #ifdef _WIN32
  661. /* Disable grab if the window no longer has the focus
  662. * (Windows-only workaround) */
  663. if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
  664. !ev->active.gain && !gui_fullscreen) {
  665. sdl_grab_end();
  666. }
  667. #endif
  668. if (!gui_grab && ev->active.gain && is_graphic_console() &&
  669. (kbd_mouse_is_absolute() || absolute_enabled)) {
  670. absolute_mouse_grab();
  671. }
  672. if (ev->active.state & SDL_APPACTIVE) {
  673. if (ev->active.gain) {
  674. /* Back to default interval */
  675. dcl->gui_timer_interval = 0;
  676. dcl->idle = 0;
  677. } else {
  678. /* Sleeping interval */
  679. dcl->gui_timer_interval = 500;
  680. dcl->idle = 1;
  681. }
  682. }
  683. }
  684. static void sdl_refresh(DisplayState *ds)
  685. {
  686. SDL_Event ev1, *ev = &ev1;
  687. if (last_vm_running != runstate_is_running()) {
  688. last_vm_running = runstate_is_running();
  689. sdl_update_caption();
  690. }
  691. vga_hw_update();
  692. SDL_EnableUNICODE(!is_graphic_console());
  693. while (SDL_PollEvent(ev)) {
  694. switch (ev->type) {
  695. case SDL_VIDEOEXPOSE:
  696. sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
  697. break;
  698. case SDL_KEYDOWN:
  699. handle_keydown(ds, ev);
  700. break;
  701. case SDL_KEYUP:
  702. handle_keyup(ds, ev);
  703. break;
  704. case SDL_QUIT:
  705. if (!no_quit) {
  706. no_shutdown = 0;
  707. qemu_system_shutdown_request();
  708. }
  709. break;
  710. case SDL_MOUSEMOTION:
  711. handle_mousemotion(ds, ev);
  712. break;
  713. case SDL_MOUSEBUTTONDOWN:
  714. case SDL_MOUSEBUTTONUP:
  715. handle_mousebutton(ds, ev);
  716. break;
  717. case SDL_ACTIVEEVENT:
  718. handle_activation(ds, ev);
  719. break;
  720. case SDL_VIDEORESIZE:
  721. sdl_scale(ds, ev->resize.w, ev->resize.h);
  722. vga_hw_invalidate();
  723. vga_hw_update();
  724. break;
  725. default:
  726. break;
  727. }
  728. }
  729. }
  730. static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
  731. {
  732. if (on) {
  733. if (!guest_cursor)
  734. sdl_show_cursor();
  735. if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
  736. SDL_SetCursor(guest_sprite);
  737. if (!kbd_mouse_is_absolute() && !absolute_enabled)
  738. SDL_WarpMouse(x, y);
  739. }
  740. } else if (gui_grab)
  741. sdl_hide_cursor();
  742. guest_cursor = on;
  743. guest_x = x, guest_y = y;
  744. }
  745. static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c)
  746. {
  747. uint8_t *image, *mask;
  748. int bpl;
  749. if (guest_sprite)
  750. SDL_FreeCursor(guest_sprite);
  751. bpl = cursor_get_mono_bpl(c);
  752. image = g_malloc0(bpl * c->height);
  753. mask = g_malloc0(bpl * c->height);
  754. cursor_get_mono_image(c, 0x000000, image);
  755. cursor_get_mono_mask(c, 0, mask);
  756. guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
  757. c->hot_x, c->hot_y);
  758. g_free(image);
  759. g_free(mask);
  760. if (guest_cursor &&
  761. (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
  762. SDL_SetCursor(guest_sprite);
  763. }
  764. static void sdl_cleanup(void)
  765. {
  766. if (guest_sprite)
  767. SDL_FreeCursor(guest_sprite);
  768. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  769. }
  770. void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
  771. {
  772. int flags;
  773. uint8_t data = 0;
  774. const SDL_VideoInfo *vi;
  775. char *filename;
  776. #if defined(__APPLE__)
  777. /* always use generic keymaps */
  778. if (!keyboard_layout)
  779. keyboard_layout = "en-us";
  780. #endif
  781. if(keyboard_layout) {
  782. kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
  783. if (!kbd_layout)
  784. exit(1);
  785. }
  786. if (no_frame)
  787. gui_noframe = 1;
  788. if (!full_screen) {
  789. setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
  790. }
  791. #ifdef __linux__
  792. /* on Linux, SDL may use fbcon|directfb|svgalib when run without
  793. * accessible $DISPLAY to open X11 window. This is often the case
  794. * when qemu is run using sudo. But in this case, and when actually
  795. * run in X11 environment, SDL fights with X11 for the video card,
  796. * making current display unavailable, often until reboot.
  797. * So make x11 the default SDL video driver if this variable is unset.
  798. * This is a bit hackish but saves us from bigger problem.
  799. * Maybe it's a good idea to fix this in SDL instead.
  800. */
  801. setenv("SDL_VIDEODRIVER", "x11", 0);
  802. #endif
  803. /* Enable normal up/down events for Caps-Lock and Num-Lock keys.
  804. * This requires SDL >= 1.2.14. */
  805. setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
  806. flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
  807. if (SDL_Init (flags)) {
  808. fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
  809. SDL_GetError());
  810. exit(1);
  811. }
  812. vi = SDL_GetVideoInfo();
  813. host_format = *(vi->vfmt);
  814. /* Load a 32x32x4 image. White pixels are transparent. */
  815. filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
  816. if (filename) {
  817. SDL_Surface *image = SDL_LoadBMP(filename);
  818. if (image) {
  819. uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
  820. SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
  821. SDL_WM_SetIcon(image, NULL);
  822. }
  823. g_free(filename);
  824. }
  825. if (full_screen) {
  826. gui_fullscreen = 1;
  827. sdl_grab_start();
  828. }
  829. dcl = g_malloc0(sizeof(DisplayChangeListener));
  830. dcl->dpy_gfx_update = sdl_update;
  831. dcl->dpy_gfx_resize = sdl_resize;
  832. dcl->dpy_refresh = sdl_refresh;
  833. dcl->dpy_gfx_setdata = sdl_setdata;
  834. dcl->dpy_mouse_set = sdl_mouse_warp;
  835. dcl->dpy_cursor_define = sdl_mouse_define;
  836. register_displaychangelistener(ds, dcl);
  837. mouse_mode_notifier.notify = sdl_mouse_mode_change;
  838. qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
  839. sdl_update_caption();
  840. SDL_EnableKeyRepeat(250, 50);
  841. gui_grab = 0;
  842. sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
  843. sdl_cursor_normal = SDL_GetCursor();
  844. atexit(sdl_cleanup);
  845. }