fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 928 lines 21 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/drivers/video/sdl2.c * 7 * Created: 2015-06-15 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2015-2025 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <config.h> 24 25#include <stdio.h> 26#include <stdlib.h> 27 28#include <SDL.h> 29#include <SDL_syswm.h> 30 31#if !(defined(PCE_HOST_WINDOWS) || defined(PCE_HOST_MACOS)) 32#include <X11/Xlib.h> 33#include <X11/Xutil.h> 34#endif 35 36#include <drivers/video/terminal.h> 37#include <drivers/video/keys.h> 38#include <drivers/video/sdl2.h> 39 40 41static sdl2_keymap_t keymap[] = { 42 { SDL_SCANCODE_ESCAPE, PCE_KEY_ESC }, 43 { SDL_SCANCODE_F1, PCE_KEY_F1 }, 44 { SDL_SCANCODE_F2, PCE_KEY_F2 }, 45 { SDL_SCANCODE_F3, PCE_KEY_F3 }, 46 { SDL_SCANCODE_F4, PCE_KEY_F4 }, 47 { SDL_SCANCODE_F5, PCE_KEY_F5 }, 48 { SDL_SCANCODE_F6, PCE_KEY_F6 }, 49 { SDL_SCANCODE_F7, PCE_KEY_F7 }, 50 { SDL_SCANCODE_F8, PCE_KEY_F8 }, 51 { SDL_SCANCODE_F9, PCE_KEY_F9 }, 52 { SDL_SCANCODE_F10, PCE_KEY_F10 }, 53 { SDL_SCANCODE_F11, PCE_KEY_F11 }, 54 { SDL_SCANCODE_F12, PCE_KEY_F12 }, 55 56 { SDL_SCANCODE_PRINTSCREEN, PCE_KEY_PRTSCN }, 57 { SDL_SCANCODE_SCROLLLOCK, PCE_KEY_SCRLK }, 58 { SDL_SCANCODE_PAUSE, PCE_KEY_PAUSE }, 59 60 { SDL_SCANCODE_GRAVE, PCE_KEY_BACKQUOTE }, 61 { SDL_SCANCODE_1, PCE_KEY_1 }, 62 { SDL_SCANCODE_2, PCE_KEY_2 }, 63 { SDL_SCANCODE_3, PCE_KEY_3 }, 64 { SDL_SCANCODE_4, PCE_KEY_4 }, 65 { SDL_SCANCODE_5, PCE_KEY_5 }, 66 { SDL_SCANCODE_6, PCE_KEY_6 }, 67 { SDL_SCANCODE_7, PCE_KEY_7 }, 68 { SDL_SCANCODE_8, PCE_KEY_8 }, 69 { SDL_SCANCODE_9, PCE_KEY_9 }, 70 { SDL_SCANCODE_0, PCE_KEY_0 }, 71 { SDL_SCANCODE_MINUS, PCE_KEY_MINUS }, 72 { SDL_SCANCODE_EQUALS, PCE_KEY_EQUAL }, 73 { SDL_SCANCODE_BACKSPACE, PCE_KEY_BACKSPACE }, 74 75 { SDL_SCANCODE_TAB, PCE_KEY_TAB }, 76 { SDL_SCANCODE_Q, PCE_KEY_Q }, 77 { SDL_SCANCODE_W, PCE_KEY_W }, 78 { SDL_SCANCODE_E, PCE_KEY_E }, 79 { SDL_SCANCODE_R, PCE_KEY_R }, 80 { SDL_SCANCODE_T, PCE_KEY_T }, 81 { SDL_SCANCODE_Y, PCE_KEY_Y }, 82 { SDL_SCANCODE_U, PCE_KEY_U }, 83 { SDL_SCANCODE_I, PCE_KEY_I }, 84 { SDL_SCANCODE_O, PCE_KEY_O }, 85 { SDL_SCANCODE_P, PCE_KEY_P }, 86 { SDL_SCANCODE_LEFTBRACKET, PCE_KEY_LBRACKET }, 87 { SDL_SCANCODE_RIGHTBRACKET, PCE_KEY_RBRACKET }, 88 { SDL_SCANCODE_RETURN, PCE_KEY_RETURN }, 89 90 { SDL_SCANCODE_CAPSLOCK, PCE_KEY_CAPSLOCK }, 91 { SDL_SCANCODE_A, PCE_KEY_A }, 92 { SDL_SCANCODE_S, PCE_KEY_S }, 93 { SDL_SCANCODE_D, PCE_KEY_D }, 94 { SDL_SCANCODE_F, PCE_KEY_F }, 95 { SDL_SCANCODE_G, PCE_KEY_G }, 96 { SDL_SCANCODE_H, PCE_KEY_H }, 97 { SDL_SCANCODE_J, PCE_KEY_J }, 98 { SDL_SCANCODE_K, PCE_KEY_K }, 99 { SDL_SCANCODE_L, PCE_KEY_L }, 100 { SDL_SCANCODE_SEMICOLON, PCE_KEY_SEMICOLON }, 101 { SDL_SCANCODE_APOSTROPHE, PCE_KEY_QUOTE }, 102 { SDL_SCANCODE_BACKSLASH, PCE_KEY_BACKSLASH }, 103 104 { SDL_SCANCODE_LSHIFT, PCE_KEY_LSHIFT }, 105 { SDL_SCANCODE_NONUSBACKSLASH, PCE_KEY_LESS }, 106 { SDL_SCANCODE_Z, PCE_KEY_Z }, 107 { SDL_SCANCODE_X, PCE_KEY_X }, 108 { SDL_SCANCODE_C, PCE_KEY_C }, 109 { SDL_SCANCODE_V, PCE_KEY_V }, 110 { SDL_SCANCODE_B, PCE_KEY_B }, 111 { SDL_SCANCODE_N, PCE_KEY_N }, 112 { SDL_SCANCODE_M, PCE_KEY_M }, 113 { SDL_SCANCODE_COMMA, PCE_KEY_COMMA }, 114 { SDL_SCANCODE_PERIOD, PCE_KEY_PERIOD }, 115 { SDL_SCANCODE_SLASH, PCE_KEY_SLASH }, 116 { SDL_SCANCODE_RSHIFT, PCE_KEY_RSHIFT }, 117 118 { SDL_SCANCODE_LCTRL, PCE_KEY_LCTRL }, 119 { SDL_SCANCODE_LGUI, PCE_KEY_LSUPER }, 120 { SDL_SCANCODE_LALT, PCE_KEY_LALT }, 121 { SDL_SCANCODE_MODE, PCE_KEY_MODE }, 122 { SDL_SCANCODE_SPACE, PCE_KEY_SPACE }, 123 { SDL_SCANCODE_RALT, PCE_KEY_RALT }, 124 { SDL_SCANCODE_RGUI, PCE_KEY_RSUPER }, 125 { SDL_SCANCODE_MENU, PCE_KEY_MENU }, 126 { SDL_SCANCODE_RCTRL, PCE_KEY_RCTRL }, 127 128 { SDL_SCANCODE_NUMLOCKCLEAR, PCE_KEY_NUMLOCK }, 129 { SDL_SCANCODE_KP_DIVIDE, PCE_KEY_KP_SLASH }, 130 { SDL_SCANCODE_KP_MULTIPLY, PCE_KEY_KP_STAR }, 131 { SDL_SCANCODE_KP_MINUS, PCE_KEY_KP_MINUS }, 132 { SDL_SCANCODE_KP_7, PCE_KEY_KP_7 }, 133 { SDL_SCANCODE_KP_8, PCE_KEY_KP_8 }, 134 { SDL_SCANCODE_KP_9, PCE_KEY_KP_9 }, 135 { SDL_SCANCODE_KP_PLUS, PCE_KEY_KP_PLUS }, 136 { SDL_SCANCODE_KP_4, PCE_KEY_KP_4 }, 137 { SDL_SCANCODE_KP_5, PCE_KEY_KP_5 }, 138 { SDL_SCANCODE_KP_6, PCE_KEY_KP_6 }, 139 { SDL_SCANCODE_KP_1, PCE_KEY_KP_1 }, 140 { SDL_SCANCODE_KP_2, PCE_KEY_KP_2 }, 141 { SDL_SCANCODE_KP_3, PCE_KEY_KP_3 }, 142 { SDL_SCANCODE_KP_ENTER, PCE_KEY_KP_ENTER }, 143 { SDL_SCANCODE_KP_0, PCE_KEY_KP_0 }, 144 { SDL_SCANCODE_KP_PERIOD, PCE_KEY_KP_PERIOD }, 145 { SDL_SCANCODE_INSERT, PCE_KEY_INS }, 146 { SDL_SCANCODE_HOME, PCE_KEY_HOME }, 147 { SDL_SCANCODE_PAGEUP, PCE_KEY_PAGEUP }, 148 { SDL_SCANCODE_DELETE, PCE_KEY_DEL }, 149 { SDL_SCANCODE_END, PCE_KEY_END }, 150 { SDL_SCANCODE_PAGEDOWN, PCE_KEY_PAGEDN }, 151 { SDL_SCANCODE_UP, PCE_KEY_UP }, 152 { SDL_SCANCODE_LEFT, PCE_KEY_LEFT }, 153 { SDL_SCANCODE_DOWN, PCE_KEY_DOWN }, 154 { SDL_SCANCODE_RIGHT, PCE_KEY_RIGHT }, 155 { 0, PCE_KEY_NONE } 156}; 157 158 159static 160void sdl2_set_keymap (sdl2_t *sdl, SDL_Scancode src, pce_key_t dst) 161{ 162 unsigned i; 163 sdl2_keymap_t *tmp; 164 165 for (i = 0; i < sdl->keymap_cnt; i++) { 166 if (sdl->keymap[i].sdlkey == src) { 167 sdl->keymap[i].pcekey = dst; 168 return; 169 } 170 } 171 172 tmp = realloc (sdl->keymap, (sdl->keymap_cnt + 1) * sizeof (sdl2_keymap_t)); 173 174 if (tmp == NULL) { 175 return; 176 } 177 178 tmp[sdl->keymap_cnt].sdlkey = src; 179 tmp[sdl->keymap_cnt].pcekey = dst; 180 181 sdl->keymap = tmp; 182 sdl->keymap_cnt += 1; 183} 184 185static 186void sdl2_init_keymap_default (sdl2_t *sdl) 187{ 188 unsigned i, n; 189 190 sdl->keymap_cnt = 0; 191 sdl->keymap = NULL; 192 193 n = 0; 194 while (keymap[n].pcekey != PCE_KEY_NONE) { 195 n += 1; 196 } 197 198 sdl->keymap = malloc (n * sizeof (sdl2_keymap_t)); 199 200 if (sdl->keymap == NULL) { 201 return; 202 } 203 204 for (i = 0; i < n; i++) { 205 sdl->keymap[i] = keymap[i]; 206 } 207 208 sdl->keymap_cnt = n; 209} 210 211static 212void sdl2_init_keymap_user (sdl2_t *sdl, ini_sct_t *sct) 213{ 214 const char *str; 215 ini_val_t *val; 216 unsigned long sdlkey; 217 pce_key_t pcekey; 218 219 val = NULL; 220 221 while (1) { 222 val = ini_next_val (sct, val, "keymap"); 223 224 if (val == NULL) { 225 break; 226 } 227 228 str = ini_val_get_str (val); 229 230 if (str == NULL) { 231 continue; 232 } 233 234 if (pce_key_get_map (str, &sdlkey, &pcekey)) { 235 continue; 236 } 237 238 sdl2_set_keymap (sdl, (SDL_Scancode) sdlkey, pcekey); 239 } 240} 241 242static 243void sdl2_grab (sdl2_t *sdl, int grab) 244{ 245 sdl->grab = (grab != 0); 246 247 if (sdl->window != NULL) { 248 if (sdl->grab_keyboard) { 249 SDL_SetWindowKeyboardGrab (sdl->window, sdl->grab ? SDL_TRUE : SDL_FALSE); 250 } 251 SDL_SetWindowMouseGrab (sdl->window, sdl->grab ? SDL_TRUE : SDL_FALSE); 252 SDL_SetRelativeMouseMode (sdl->grab ? SDL_TRUE : SDL_FALSE); 253 } 254} 255 256static 257void sdl2_set_fullscreen (sdl2_t *sdl, int val) 258{ 259 if ((val != 0) == (sdl->fullscreen != 0)) { 260 return; 261 } 262 263 sdl->fullscreen = (val != 0); 264 265 if (sdl->window != NULL) { 266 SDL_SetWindowFullscreen (sdl->window, val ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); 267 } 268} 269 270static 271int sdl2_set_window_size (sdl2_t *sdl, unsigned w, unsigned h) 272{ 273#if !(defined(PCE_HOST_WINDOWS) || defined(PCE_HOST_MACOS)) 274 XSizeHints hints; 275 SDL_SysWMinfo info; 276 long r; 277#endif 278 279 if ((w == 0) || (h == 0)) { 280 return (1); 281 } 282 283 if ((sdl->wdw_w == w) && (sdl->wdw_h == h)) { 284 return (0); 285 } 286 287#if !(defined(PCE_HOST_WINDOWS) || defined(PCE_HOST_MACOS)) 288 if (sdl->autosize == 2) { 289 SDL_VERSION(&info.version); 290 if (SDL_GetWindowWMInfo(sdl->window, &info) && 291 info.subsystem == SDL_SYSWM_X11 && 292 XGetWMSizeHints(info.info.x11.display, info.info.x11.window, &hints, &r, XA_WM_SIZE_HINTS) == 0) { 293 hints.flags = PMinSize | PMaxSize | PAspect; 294 hints.max_width = w; 295 hints.min_width = w; 296 hints.max_height = h; 297 hints.min_height = h; 298 XSetWMNormalHints (info.info.x11.display, info.info.x11.window, &hints); 299 } 300 } 301#endif 302 303 SDL_SetWindowSize (sdl->window, w, h); 304 305 sdl->wdw_w = w; 306 sdl->wdw_h = h; 307 308 return (0); 309} 310 311static 312int sdl2_set_window_size_auto (sdl2_t *sdl) 313{ 314 unsigned fx, fy, tw, th, ww, wh; 315 316 tw = sdl->trm.w; 317 th = sdl->trm.h; 318 319 trm_get_scale (&sdl->trm, tw, th, &fx, &fy); 320 321 ww = fx * tw; 322 wh = fy * th; 323 324 if (sdl2_set_window_size (sdl, ww, wh)) { 325 return (1); 326 } 327 328 return (0); 329} 330 331static 332int sdl2_set_frame_size (sdl2_t *sdl) 333{ 334 unsigned tw, th; 335 336 tw = sdl->trm.w; 337 th = sdl->trm.h; 338 339 if (sdl->autosize) { 340 sdl2_set_window_size_auto (sdl); 341 } 342 343 if ((sdl->txt_w == tw) && (sdl->txt_h == th)) { 344 return (0); 345 } 346 347 if (sdl->texture != NULL) { 348 SDL_DestroyTexture (sdl->texture); 349 sdl->texture = NULL; 350 } 351 352 sdl->texture = SDL_CreateTexture (sdl->render, 353 SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, tw, th 354 ); 355 356 if (sdl->texture == NULL) { 357 fprintf (stderr, "sdl2: texture\n"); 358 return (1); 359 } 360 361 sdl->txt_w = tw; 362 sdl->txt_h = th; 363 364 return (0); 365} 366 367static 368unsigned sdl2_map_key (sdl2_t *sdl, SDL_Scancode key) 369{ 370 unsigned i; 371 372 for (i = 0; i < sdl->keymap_cnt; i++) { 373 if (sdl->keymap[i].sdlkey == key) { 374 return (sdl->keymap[i].pcekey); 375 } 376 } 377 378 return (PCE_KEY_NONE); 379} 380 381static 382void sdl2_update (sdl2_t *sdl) 383{ 384 terminal_t *trm; 385 void *pixels; 386 int pitch; 387 388 trm = &sdl->trm; 389 390 sdl->update = 0; 391 392 if ((trm->w == 0) || (trm->h == 0)) { 393 return; 394 } 395 396 if (sdl2_set_frame_size (sdl)) { 397 return; 398 } 399 400 if ((sdl->texture == NULL) || (sdl->render == NULL)) { 401 return; 402 } 403 404 SDL_LockTexture (sdl->texture, NULL, &pixels, &pitch); 405 memcpy (pixels, trm->buf, 3UL * trm->w * trm->h); 406 SDL_UnlockTexture (sdl->texture); 407 408 SDL_RenderCopy (sdl->render, sdl->texture, NULL, NULL); 409 SDL_RenderPresent (sdl->render); 410} 411 412static 413void sdl2_event_keydown (sdl2_t *sdl, SDL_Scancode key, SDL_Keymod mod) 414{ 415 pce_key_t pcekey; 416 417 if (sdl->ignore_keys || !sdl->grab) { 418 return; 419 } 420 421 if (key == SDL_SCANCODE_GRAVE) { 422 if (sdl->grave_down) { 423 return; 424 } 425 else if (mod & KMOD_LCTRL) { 426 sdl->grave_down = 1; 427 sdl2_grab (sdl, 0); 428 sdl2_set_fullscreen (sdl, 0); 429 trm_set_msg_emu (&sdl->trm, "emu.stop", "1"); 430 return; 431 } 432 } 433 else if (key == SDL_SCANCODE_PRINTSCREEN) { 434 trm_screenshot (&sdl->trm, NULL); 435 return; 436 } 437 438 pcekey = sdl2_map_key (sdl, key); 439 440 if (sdl->report_keys || (pcekey == PCE_KEY_NONE)) { 441 fprintf (stderr, "sdl: key = 0x%04x (%s)\n", 442 (unsigned) key, SDL_GetScancodeName (key) 443 ); 444 } 445 446 if (pcekey == PCE_KEY_NONE) { 447 return; 448 } 449 450 trm_set_key (&sdl->trm, PCE_KEY_EVENT_DOWN, pcekey); 451 452 if (key == SDL_SCANCODE_NUMLOCKCLEAR) { 453 trm_set_key (&sdl->trm, PCE_KEY_EVENT_UP, pcekey); 454 } 455} 456 457static 458void sdl2_event_keyup (sdl2_t *sdl, SDL_Scancode key, SDL_Keymod mod) 459{ 460 pce_key_t pcekey; 461 462 if (sdl->ignore_keys) { 463 return; 464 } 465 466 pcekey = sdl2_map_key (sdl, key); 467 468 if (key == SDL_SCANCODE_GRAVE) { 469 if (sdl->grave_down) { 470 sdl->grave_down = 0; 471 return; 472 } 473 } 474 else if (key == SDL_SCANCODE_PRINTSCREEN) { 475 return; 476 } 477 478 if (pcekey != PCE_KEY_NONE) { 479 if (key == SDL_SCANCODE_NUMLOCKCLEAR) { 480 trm_set_key (&sdl->trm, PCE_KEY_EVENT_DOWN, pcekey); 481 } 482 483 trm_set_key (&sdl->trm, PCE_KEY_EVENT_UP, pcekey); 484 } 485} 486 487static 488void sdl2_event_mouse_button (sdl2_t *sdl, int down, unsigned button) 489{ 490 if (button == 0) { 491 return; 492 } 493 494 if (button == 2) { 495 button = 3; 496 } 497 else if (button == 3) { 498 button = 2; 499 } 500 501 button -= 1; 502 503 if (down) { 504 sdl->button |= 1U << button; 505 } 506 else { 507 sdl->button &= ~(1U << button); 508 } 509 510 if (sdl->grab == 0) { 511 if (down == 0) { 512 sdl2_grab (sdl, 1); 513 } 514 return; 515 } 516 517 if (sdl->trm.set_mouse == NULL) { 518 return; 519 } 520 521 trm_set_mouse (&sdl->trm, 0, 0, sdl->button); 522} 523 524static 525void sdl2_event_mouse_motion (sdl2_t *sdl, int dx, int dy) 526{ 527 int ax, ay, fx, fy; 528 529 if (sdl->grab == 0) { 530 return; 531 } 532 533 if (sdl->trm.set_mouse == NULL) { 534 return; 535 } 536 537 trm_set_mouse (&sdl->trm, dx, dy, sdl->button); 538 539 if (!sdl->autograb || sdl->trm.get_mouse == NULL || sdl->fullscreen) { 540 return; 541 } 542 543 trm_get_mouse (&sdl->trm, &ax, &ay); 544 545 /* if at screen edge and still moving that direction, unbind */ 546 if ((ax == 0 && dx < 0) || (ay == 0 && dy < 0) || 547 (ax == sdl->trm.w && dx > 0) || (ay == sdl->trm.h && dy > 0)) { 548 trm_get_scale (&sdl->trm, sdl->trm.w, sdl->trm.h, &fx, &fy); 549 SDL_WarpMouseInWindow (sdl->window, ax * fx, ay * fy); 550 sdl2_grab (sdl, 0); 551 } 552} 553 554static 555void sdl2_event_window (sdl2_t *sdl, SDL_WindowEvent *evt) 556{ 557 if (sdl->window == NULL) { 558 return; 559 } 560 561 if (evt->windowID != SDL_GetWindowID (sdl->window)) { 562 return; 563 } 564 565 switch (evt->event) { 566 case SDL_WINDOWEVENT_SIZE_CHANGED: 567 sdl->update = 1; 568 break; 569 570 case SDL_WINDOWEVENT_RESIZED: 571 if ((sdl->wdw_w != evt->data1) || (sdl->wdw_h != evt->data2)) { 572 sdl->wdw_w = evt->data1; 573 sdl->wdw_h = evt->data2; 574 sdl->autosize = 0; 575 if (sdl->autosize != 2) 576 sdl->autosize = 0; 577 } 578 sdl->update = 1; 579 break; 580 581 case SDL_WINDOWEVENT_RESTORED: 582 sdl->update = 1; 583 break; 584 585 case SDL_WINDOWEVENT_EXPOSED: 586 sdl->update = 1; 587 break; 588 589 case SDL_WINDOWEVENT_MOVED: 590 break; 591 592 case SDL_WINDOWEVENT_ENTER: 593 if (sdl->autograb && sdl->grab == 0) { 594 sdl2_grab (sdl, 1); 595 } 596 break; 597 598 case SDL_WINDOWEVENT_LEAVE: 599 break; 600 601 case SDL_WINDOWEVENT_FOCUS_GAINED: 602 sdl->ignore_keys = 1; 603 break; 604 605 case SDL_WINDOWEVENT_FOCUS_LOST: 606 break; 607 608 case SDL_WINDOWEVENT_SHOWN: 609 sdl->update = 1; 610 break; 611 612 case SDL_WINDOWEVENT_HIDDEN: 613 break; 614 615 case SDL_WINDOWEVENT_MINIMIZED: 616 break; 617 618 case SDL_WINDOWEVENT_MAXIMIZED: 619 sdl->update = 1; 620 break; 621 622 case SDL_WINDOWEVENT_TAKE_FOCUS: 623 break; 624 625 default: 626#ifdef DEBUG_SDL2 627 fprintf (stderr, "sdl2: window event %u\n", evt->event); 628#endif 629 break; 630 } 631} 632 633static 634void sdl2_check (sdl2_t *sdl) 635{ 636 static SDL_Event cur_keydown_evt = { 0 }; 637 SDL_Event evt; 638 SDL_Event peek_evt; 639 unsigned int now; 640 641 if (sdl->mouse_button_delay) { 642 now = SDL_GetTicks(); 643 644 SDL_PumpEvents(); 645 if (SDL_PeepEvents(&peek_evt, 1, SDL_PEEKEVENT, SDL_MOUSEMOTION, 646 SDL_MOUSEBUTTONUP) > 0 && 647 now - sdl->last_mouse_button_at <= sdl->mouse_button_delay) { 648 goto done; 649 } 650 } 651 652 while (SDL_PollEvent (&evt)) { 653 switch (evt.type) { 654 case SDL_KEYDOWN: 655 cur_keydown_evt = evt; 656 sdl2_event_keydown (sdl, evt.key.keysym.scancode, evt.key.keysym.mod); 657 break; 658 659 case SDL_KEYUP: 660 memset(&cur_keydown_evt, 0, sizeof(cur_keydown_evt)); 661 sdl2_event_keyup (sdl, evt.key.keysym.scancode, evt.key.keysym.mod); 662 break; 663 664 case SDL_TEXTINPUT: 665 case SDL_KEYMAPCHANGED: 666 break; 667 668 case SDL_MOUSEBUTTONDOWN: 669 if (sdl->mouse_button_delay) { 670 sdl->last_mouse_button_at = now; 671 } 672 sdl2_event_mouse_button (sdl, 1, evt.button.button); 673 goto done; 674 675 case SDL_MOUSEBUTTONUP: 676 if (sdl->mouse_button_delay) { 677 sdl->last_mouse_button_at = now; 678 } 679 sdl2_event_mouse_button (sdl, 0, evt.button.button); 680 goto done; 681 682 case SDL_MOUSEMOTION: 683 sdl2_event_mouse_motion (sdl, evt.motion.xrel, evt.motion.yrel); 684 break; 685 686 case SDL_WINDOWEVENT: 687 sdl2_event_window (sdl, &evt.window); 688 break; 689 690 case SDL_QUIT: 691 if (cur_keydown_evt.key.keysym.sym && sdl->grab) 692 break; 693 sdl2_grab (sdl, 0); 694 trm_set_msg_emu (&sdl->trm, "emu.exit", "1"); 695 break; 696 697 case SDL_AUDIODEVICEADDED: 698 break; 699 700 default: 701#ifdef DEBUG_SDL2 702 fprintf (stderr, "sdl2: event %u\n", evt.type); 703#endif 704 break; 705 } 706 } 707done: 708 709 if (sdl->update) { 710 sdl2_update (sdl); 711 } 712 713 if (sdl->ignore_keys) { 714 sdl->ignore_keys = 0; 715 } 716} 717 718static 719int sdl2_set_msg_trm (sdl2_t *sdl, const char *msg, const char *val) 720{ 721 if (val == NULL) { 722 val = ""; 723 } 724 725 if (strcmp (msg, "term.grab") == 0) { 726 sdl2_grab (sdl, 1); 727 return (0); 728 } 729 else if (strcmp (msg, "term.release") == 0) { 730 sdl2_grab (sdl, 0); 731 return (0); 732 } 733 else if (strcmp (msg, "term.title") == 0) { 734 if (sdl->window != NULL) { 735 SDL_SetWindowTitle (sdl->window, val); 736 } 737 return (0); 738 } 739 else if (strcmp (msg, "term.fullscreen.toggle") == 0) { 740 sdl2_set_fullscreen (sdl, !sdl->fullscreen); 741 return (0); 742 } 743 else if (strcmp (msg, "term.fullscreen") == 0) { 744 int v; 745 746 v = strtol (val, NULL, 0); 747 748 sdl2_set_fullscreen (sdl, v != 0); 749 750 return (0); 751 } 752 else if (strcmp (msg, "term.autosize") == 0) { 753 sdl->autosize = 1; 754 sdl->update = 1; 755 return (0); 756 } 757 758 return (-1); 759} 760 761static 762void sdl2_del (sdl2_t *sdl) 763{ 764 free (sdl); 765} 766 767static 768int sdl2_open (sdl2_t *sdl, unsigned w, unsigned h) 769{ 770 unsigned x, y; 771 unsigned fx, fy; 772 unsigned flags; 773 774 trm_get_scale (&sdl->trm, w, h, &fx, &fy); 775 776 w *= fx; 777 h *= fy; 778 779 if ((w == 0) || (h == 0)) { 780 w = 512; 781 h = 384; 782 } 783 784 if (SDL_WasInit (SDL_INIT_VIDEO) == 0) { 785 if (SDL_InitSubSystem (SDL_INIT_VIDEO) < 0) { 786 return (1); 787 } 788 } 789 790 sdl->window = NULL; 791 sdl->render = NULL; 792 sdl->texture = NULL; 793 794 SDL_EventState (SDL_MOUSEMOTION, SDL_ENABLE); 795 796 SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, sdl->scale_quality); 797 SDL_SetHint (SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); 798 799 flags = SDL_WINDOW_RESIZABLE; 800 801 if (sdl->fullscreen) { 802 flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; 803 } 804 805 x = SDL_WINDOWPOS_UNDEFINED; 806 y = SDL_WINDOWPOS_UNDEFINED; 807 808 sdl->window = SDL_CreateWindow ("pce", x, y, w, h, flags); 809 810 if (sdl->window == NULL) { 811 fprintf (stderr, "sdl2: window\n"); 812 return (1); 813 } 814 815 SDL_ShowWindow (sdl->window); 816 817 sdl->wdw_w = w; 818 sdl->wdw_h = h; 819 820 sdl->render = SDL_CreateRenderer (sdl->window, -1, 0); 821 822 if (sdl->render == NULL) { 823 fprintf (stderr, "sdl2: renderer\n"); 824 return (1); 825 } 826 827 return (0); 828} 829 830static 831int sdl2_close (sdl2_t *sdl) 832{ 833 sdl2_grab (sdl, 0); 834 835 if (sdl->texture != NULL) { 836 SDL_DestroyTexture (sdl->texture); 837 sdl->texture = NULL; 838 } 839 840 if (sdl->render != NULL) { 841 SDL_DestroyRenderer (sdl->render); 842 sdl->render = NULL; 843 } 844 845 if (sdl->window != NULL) { 846 SDL_DestroyWindow (sdl->window); 847 sdl->window = NULL; 848 } 849 850 return (0); 851} 852 853static 854void sdl2_init (sdl2_t *sdl, ini_sct_t *sct) 855{ 856 int val; 857 unsigned int autosize; 858 const char *str; 859 860 trm_init (&sdl->trm, sdl); 861 862 sdl->trm.del = (void *) sdl2_del; 863 sdl->trm.open = (void *) sdl2_open; 864 sdl->trm.close = (void *) sdl2_close; 865 sdl->trm.set_msg_trm = (void *) sdl2_set_msg_trm; 866 sdl->trm.update = (void *) sdl2_update; 867 sdl->trm.check = (void *) sdl2_check; 868 869 sdl->window = NULL; 870 sdl->render = NULL; 871 sdl->texture = NULL; 872 873 sdl->txt_w = 0; 874 sdl->txt_h = 0; 875 876 sdl->wdw_w = 0; 877 sdl->wdw_h = 0; 878 879 sdl->update = 0; 880 881 sdl->button = 0; 882 883 ini_get_bool (sct, "fullscreen", &val, 0); 884 sdl->fullscreen = (val != 0); 885 886 ini_get_string (sct, "scale_quality", &sdl->scale_quality, "linear"); 887 888 sdl->grab = 0; 889 890 ini_get_bool (sct, "grab_keyboard", &val, 1); 891 sdl->grab_keyboard = (val != 0); 892 893 ini_get_bool (sct, "autograb", &val, 0); 894 sdl->autograb = (val != 0); 895 896 ini_get_bool (sct, "report_keys", &val, 0); 897 sdl->report_keys = (val != 0); 898 899 if (ini_get_string (sct, "scale_quality", &str, NULL) == 0) { 900 SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, str); 901 } 902 903 ini_get_uint16 (sct, "autosize", &autosize, 1); 904 sdl->autosize = (autosize & 0xff); 905 906 sdl->grave_down = 0; 907 sdl->ignore_keys = 0; 908 909 ini_get_uint16 (sct, "mouse_button_delay", &sdl->mouse_button_delay, 0); 910 911 sdl2_init_keymap_default (sdl); 912 sdl2_init_keymap_user (sdl, sct); 913 914 SDL_SetHint (SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); 915} 916 917terminal_t *sdl2_new (ini_sct_t *sct) 918{ 919 sdl2_t *sdl; 920 921 if ((sdl = malloc (sizeof (sdl2_t))) == NULL) { 922 return (NULL); 923 } 924 925 sdl2_init (sdl, sct); 926 927 return (&sdl->trm); 928}