DOSBox-X
|
00001 00011 /* 00012 * Copyright (C) 2002-2020 The DOSBox Team 00013 * 00014 * This program is free software; you can redistribute it and/or modify 00015 * it under the terms of the GNU General Public License as published by 00016 * the Free Software Foundation; either version 2 of the License, or 00017 * (at your option) any later version. 00018 * 00019 * This program is distributed in the hope that it will be useful, 00020 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00021 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00022 * GNU General Public License for more details. 00023 * 00024 * You should have received a copy of the GNU General Public License along 00025 * with this program; if not, write to the Free Software Foundation, Inc., 00026 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00027 */ 00028 00029 #ifdef WIN32 00030 # ifndef WIN32_LEAN_AND_MEAN 00031 # define WIN32_LEAN_AND_MEAN 00032 # endif 00033 #endif 00034 00035 #ifdef OS2 00036 # define INCL_DOS 00037 # define INCL_WIN 00038 #endif 00039 00040 extern bool dpi_aware_enable; 00041 extern bool log_int21; 00042 extern bool log_fileio; 00043 extern bool force_load_state; 00044 00045 bool OpenGL_using(void); 00046 void GFX_OpenGLRedrawScreen(void); 00047 00048 #ifndef _GNU_SOURCE 00049 # define _GNU_SOURCE 00050 #endif 00051 00052 // Tell Mac OS X to shut up about deprecated OpenGL calls 00053 #ifndef GL_SILENCE_DEPRECATION 00054 #define GL_SILENCE_DEPRECATION 00055 #endif 00056 00057 #include <stdlib.h> 00058 #include <string.h> 00059 #include <stdio.h> 00060 #include <unistd.h> 00061 #include <assert.h> 00062 #include <stdarg.h> 00063 #include <sys/types.h> 00064 #include <algorithm> // std::transform 00065 #include <fcntl.h> 00066 #ifdef WIN32 00067 # include <signal.h> 00068 # include <sys/stat.h> 00069 # include <process.h> 00070 # if !defined(__MINGW32__) /* MinGW does not have these headers */ 00071 # include <shcore.h> 00072 # include <shellscalingapi.h> 00073 # endif 00074 #endif 00075 00076 #include "dosbox.h" 00077 #include "pic.h" 00078 #include "timer.h" 00079 #include "setup.h" 00080 #include "bios.h" 00081 #include "support.h" 00082 #include "debug.h" 00083 #include "ide.h" 00084 #include "bitop.h" 00085 #include "ptrop.h" 00086 #include "mapper.h" 00087 #include "sdlmain.h" 00088 #include "zipfile.h" 00089 #include "shell.h" 00090 00091 #if defined(LINUX) && defined(HAVE_ALSA) 00092 # include <alsa/asoundlib.h> 00093 #endif 00094 00095 #if defined(WIN32) && !defined(HX_DOS) 00096 # include <shobjidl.h> 00097 #endif 00098 00099 #if defined(WIN32) && defined(__MINGW32__) /* MinGW does not have IID_ITaskbarList3 */ 00100 /* MinGW now contains this, the older MinGW for HX-DOS does not. 00101 * Keep things simple and just #define around it like this */ 00102 static const GUID __my_CLSID_TaskbarList ={ 0x56FDF344,0xFD6D,0x11d0,{0x95,0x8A,0x00,0x60,0x97,0xC9,0xA0,0x90}}; 00103 # define CLSID_TaskbarList __my_CLSID_TaskbarList 00104 00105 static const GUID __my_IID_ITaskbarList3 = { 0xEA1AFB91ul,0x9E28u,0x4B86u,0x90u,0xE9u,0x9Eu,0x9Fu,0x8Au,0x5Eu,0xEFu,0xAFu }; 00106 # define IID_ITaskbarList3 __my_IID_ITaskbarList3 00107 #endif 00108 00109 #if defined(WIN32) && defined(__MINGW32__) /* MinGW does not have this */ 00110 typedef enum PROCESS_DPI_AWARENESS { 00111 PROCESS_DPI_UNAWARE = 0, 00112 PROCESS_SYSTEM_DPI_AWARE = 1, 00113 PROCESS_PER_MONITOR_DPI_AWARE = 2 00114 } PROCESS_DPI_AWARENESS; 00115 #endif 00116 00117 #if C_EMSCRIPTEN 00118 # include <emscripten.h> 00119 #endif 00120 00121 #include "../src/libs/gui_tk/gui_tk.h" 00122 00123 #ifdef __WIN32__ 00124 # include "callback.h" 00125 # include "dos_inc.h" 00126 # include <malloc.h> 00127 # include "Commdlg.h" 00128 # include "windows.h" 00129 # include "Shellapi.h" 00130 # include "shell.h" 00131 # include <cstring> 00132 # include <fstream> 00133 # if defined(__MINGW32__) && !defined(HX_DOS) 00134 # include <imm.h> // input method editor 00135 # endif 00136 #endif // WIN32 00137 00138 #include <sstream> 00139 00140 #include "mapper.h" 00141 #include "vga.h" 00142 #include "keyboard.h" 00143 #include "cpu.h" 00144 #include "fpu.h" 00145 #include "cross.h" 00146 #include "keymap.h" 00147 00148 #ifdef _MSC_VER 00149 # define MIN(a,b) ((a) < (b) ? (a) : (b)) 00150 # define MAX(a,b) ((a) > (b) ? (a) : (b)) 00151 #else 00152 # define MIN(a,b) std::min(a,b) 00153 # define MAX(a,b) std::max(a,b) 00154 #endif 00155 00156 #if !defined(C_SDL2) && !defined(RISCOS) 00157 # include "SDL_version.h" 00158 # ifndef SDL_DOSBOX_X_SPECIAL 00159 # error This code must be compiled using the SDL 1.x library provided in this source repository 00160 # endif 00161 #endif 00162 00163 #include "sdlmain.h" 00164 00165 #ifdef MACOSX 00166 extern bool has_touch_bar_support; 00167 bool osx_detect_nstouchbar(void); 00168 void osx_init_touchbar(void); 00169 #endif 00170 00171 void ShutDownMemHandles(Section * sec); 00172 void MAPPER_AutoType(std::vector<std::string> &sequence, const uint32_t wait_ms, const uint32_t pacing_ms); 00173 00174 SDL_Block sdl; 00175 Bitu frames = 0; 00176 00177 ScreenSizeInfo screen_size_info; 00178 00179 extern bool dos_kernel_disabled; 00180 00181 void MenuBootDrive(char drive); 00182 void MenuUnmountDrive(char drive); 00183 void SetGameState_Run(int value); 00184 size_t GetGameState_Run(void); 00185 00186 bool save_slot_0_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00187 (void)menu;//UNUSED 00188 (void)menuitem;//UNUSED 00189 SetGameState_Run(0); 00190 return true; 00191 } 00192 00193 bool save_slot_1_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00194 (void)menu;//UNUSED 00195 (void)menuitem;//UNUSED 00196 SetGameState_Run(1); 00197 return true; 00198 } 00199 00200 bool save_slot_2_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00201 (void)menu;//UNUSED 00202 (void)menuitem;//UNUSED 00203 SetGameState_Run(2); 00204 return true; 00205 } 00206 00207 bool save_slot_3_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00208 (void)menu;//UNUSED 00209 (void)menuitem;//UNUSED 00210 SetGameState_Run(3); 00211 return true; 00212 } 00213 00214 bool save_slot_4_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00215 (void)menu;//UNUSED 00216 (void)menuitem;//UNUSED 00217 SetGameState_Run(4); 00218 return true; 00219 } 00220 00221 bool save_slot_5_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00222 (void)menu;//UNUSED 00223 (void)menuitem;//UNUSED 00224 SetGameState_Run(5); 00225 return true; 00226 } 00227 00228 bool save_slot_6_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00229 (void)menu;//UNUSED 00230 (void)menuitem;//UNUSED 00231 SetGameState_Run(6); 00232 return true; 00233 } 00234 00235 bool save_slot_7_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00236 (void)menu;//UNUSED 00237 (void)menuitem;//UNUSED 00238 SetGameState_Run(7); 00239 return true; 00240 } 00241 00242 bool save_slot_8_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00243 (void)menu;//UNUSED 00244 (void)menuitem;//UNUSED 00245 SetGameState_Run(8); 00246 return true; 00247 } 00248 00249 bool save_slot_9_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00250 (void)menu;//UNUSED 00251 (void)menuitem;//UNUSED 00252 SetGameState_Run(9); 00253 return true; 00254 } 00255 00256 #if defined(WIN32) 00257 void MenuMountDrive(char drive, const char drive2[DOS_PATHLENGTH]); 00258 void MenuBrowseFolder(char drive, std::string drive_type); 00259 void MenuBrowseImageFile(char drive, bool boot); 00260 00261 bool drive_mountauto_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00262 (void)menu;//UNUSED 00263 (void)menuitem;//UNUSED 00264 00265 /* menu item has name "drive_A_" ... */ 00266 int drive; 00267 const char *mname = menuitem->get_name().c_str(); 00268 if (!strncmp(mname,"drive_",6)) { 00269 drive = mname[6] - 'A'; 00270 if (drive < 0 || drive >= DOS_DRIVES) return false; 00271 } 00272 else { 00273 return false; 00274 } 00275 00276 if (dos_kernel_disabled) return true; 00277 00278 char root[4]="A:\\"; 00279 root[0]=drive+'A'; 00280 MenuMountDrive(drive+'A', root); 00281 00282 return true; 00283 } 00284 00285 bool drive_mounthd_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00286 (void)menu;//UNUSED 00287 (void)menuitem;//UNUSED 00288 00289 /* menu item has name "drive_A_" ... */ 00290 int drive; 00291 const char *mname = menuitem->get_name().c_str(); 00292 if (!strncmp(mname,"drive_",6)) { 00293 drive = mname[6] - 'A'; 00294 if (drive < 0 || drive >= DOS_DRIVES) return false; 00295 } 00296 else { 00297 return false; 00298 } 00299 00300 if (dos_kernel_disabled) return true; 00301 00302 MenuBrowseFolder(drive+'A', "LOCAL"); 00303 00304 return true; 00305 } 00306 00307 bool drive_mountcd_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00308 (void)menu;//UNUSED 00309 (void)menuitem;//UNUSED 00310 00311 /* menu item has name "drive_A_" ... */ 00312 int drive; 00313 const char *mname = menuitem->get_name().c_str(); 00314 if (!strncmp(mname,"drive_",6)) { 00315 drive = mname[6] - 'A'; 00316 if (drive < 0 || drive >= DOS_DRIVES) return false; 00317 } 00318 else { 00319 return false; 00320 } 00321 00322 if (dos_kernel_disabled) return true; 00323 00324 MenuBrowseFolder(drive+'A', "CDROM"); 00325 00326 return true; 00327 } 00328 00329 bool drive_mountfd_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00330 (void)menu;//UNUSED 00331 (void)menuitem;//UNUSED 00332 00333 /* menu item has name "drive_A_" ... */ 00334 int drive; 00335 const char *mname = menuitem->get_name().c_str(); 00336 if (!strncmp(mname,"drive_",6)) { 00337 drive = mname[6] - 'A'; 00338 if (drive < 0 || drive >= DOS_DRIVES) return false; 00339 } 00340 else { 00341 return false; 00342 } 00343 00344 if (dos_kernel_disabled) return true; 00345 00346 MenuBrowseFolder(drive+'A', "FLOPPY"); 00347 00348 return true; 00349 } 00350 00351 bool drive_mountimg_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00352 (void)menu;//UNUSED 00353 (void)menuitem;//UNUSED 00354 00355 /* menu item has name "drive_A_" ... */ 00356 int drive; 00357 const char *mname = menuitem->get_name().c_str(); 00358 if (!strncmp(mname,"drive_",6)) { 00359 drive = mname[6] - 'A'; 00360 if (drive < 0 || drive >= DOS_DRIVES) return false; 00361 } 00362 else { 00363 return false; 00364 } 00365 00366 if (dos_kernel_disabled) return true; 00367 00368 MenuBrowseImageFile(drive+'A', false); 00369 00370 return true; 00371 } 00372 00373 bool drive_bootimg_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00374 (void)menu;//UNUSED 00375 (void)menuitem;//UNUSED 00376 00377 int drive; 00378 const char *mname = menuitem->get_name().c_str(); 00379 if (!strncmp(mname,"drive_",6)) { 00380 drive = mname[6] - 'A'; 00381 if (drive != 0 && drive != 2 && drive != 3) return false; 00382 } 00383 else { 00384 return false; 00385 } 00386 00387 if (dos_kernel_disabled) return true; 00388 00389 MenuBrowseImageFile(drive+'A', true); 00390 00391 return true; 00392 } 00393 #endif 00394 00395 bool drive_unmount_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00396 (void)menu;//UNUSED 00397 (void)menuitem;//UNUSED 00398 00399 /* menu item has name "drive_A_" ... */ 00400 int drive; 00401 const char *mname = menuitem->get_name().c_str(); 00402 if (!strncmp(mname,"drive_",6)) { 00403 drive = mname[6] - 'A'; 00404 if (drive < 0 || drive >= DOS_DRIVES) return false; 00405 } 00406 else { 00407 return false; 00408 } 00409 00410 if (dos_kernel_disabled) return true; 00411 00412 MenuUnmountDrive(drive+'A'); 00413 00414 return true; 00415 } 00416 00417 bool drive_rescan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00418 (void)menu;//UNUSED 00419 (void)menuitem;//UNUSED 00420 00421 /* menu item has name "drive_A_" ... */ 00422 int drive; 00423 const char *mname = menuitem->get_name().c_str(); 00424 if (!strncmp(mname,"drive_",6)) { 00425 drive = mname[6] - 'A'; 00426 if (drive < 0 || drive >= DOS_DRIVES) return false; 00427 } 00428 else { 00429 return false; 00430 } 00431 00432 if (dos_kernel_disabled) return true; 00433 00434 if (drive < DOS_DRIVES && Drives[drive]) { 00435 LOG(LOG_DOSMISC,LOG_DEBUG)("Triggering rescan on drive %c",drive+'A'); 00436 Drives[drive]->EmptyCache(); 00437 } 00438 00439 return true; 00440 } 00441 00442 bool drive_boot_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 00443 (void)menu;//UNUSED 00444 (void)menuitem;//UNUSED 00445 00446 /* menu item has name "drive_A_" ... */ 00447 int drive; 00448 const char *mname = menuitem->get_name().c_str(); 00449 if (!strncmp(mname,"drive_",6)) { 00450 drive = mname[6] - 'A'; 00451 if (drive != 0 && drive != 2 && drive != 3) return false; 00452 } 00453 else { 00454 return false; 00455 } 00456 00457 if (dos_kernel_disabled) return true; 00458 00459 MenuBootDrive(drive+'A'); 00460 00461 return true; 00462 } 00463 00464 const DOSBoxMenu::callback_t drive_callbacks[] = { 00465 #if defined(WIN32) 00466 drive_mountauto_menu_callback, 00467 drive_mounthd_menu_callback, 00468 drive_mountcd_menu_callback, 00469 drive_mountfd_menu_callback, 00470 drive_mountimg_menu_callback, 00471 #endif 00472 drive_unmount_menu_callback, 00473 drive_rescan_menu_callback, 00474 drive_boot_menu_callback, 00475 #if defined(WIN32) 00476 drive_bootimg_menu_callback, 00477 #endif 00478 NULL 00479 }; 00480 00481 const char *drive_opts[][2] = { 00482 #if defined(WIN32) 00483 { "mountauto", "Mount Automatically" }, 00484 { "mounthd", "Mount as Hard Disk" }, 00485 { "mountcd", "Mount as CD-ROM" }, 00486 { "mountfd", "Mount as Floppy" }, 00487 { "mountimg", "Mount disk image" }, 00488 #endif 00489 { "unmount", "Unmount" }, 00490 { "rescan", "Rescan" }, 00491 { "boot", "Boot from drive" }, 00492 #if defined(WIN32) 00493 { "bootimg", "Boot from disk image" }, 00494 #endif 00495 { NULL, NULL } 00496 }; 00497 00498 const char *scaler_menu_opts[][2] = { 00499 { "none", "None" }, 00500 { "normal2x", "Normal 2X" }, 00501 { "normal3x", "Normal 3X" }, 00502 { "normal4x", "Normal 4X" }, 00503 { "normal5x", "Normal 5X" }, 00504 { "hardware_none", "Hardware None" }, 00505 { "hardware2x", "Hardware 2X" }, 00506 { "hardware3x", "Hardware 3X" }, 00507 { "hardware4x", "Hardware 4X" }, 00508 { "hardware5x", "Hardware 5X" }, 00509 { "gray", "Grayscale" }, 00510 { "gray2x", "Grayscale 2X" }, 00511 { "tv2x", "TV 2X" }, 00512 { "tv3x", "TV 3X" }, 00513 { "scan2x", "Scan 2X" }, 00514 { "scan3x", "Scan 3X" }, 00515 { "rgb2x", "RGB 2X" }, 00516 { "rgb3x", "RGB 3X" }, 00517 { "advmame2x", "Advanced MAME 2X" }, 00518 { "advmame3x", "Advanced MAME 3X" }, 00519 { "hq2x", "HQ 2X" }, 00520 { "hq3x", "HQ 3X" }, 00521 { "advinterp2x", "Advanced Interpolation 2X" }, 00522 { "advinterp3x", "Advanced Interpolation 3X" }, 00523 { "2xsai", "2xSai" }, 00524 { "super2xsai", "Super2xSai" }, 00525 { "supereagle", "SuperEagle" }, 00526 #if C_XBRZ 00527 { "xbrz", "xBRZ" }, 00528 { "xbrz_bilinear", "xBRZ Bilinear" }, 00529 #endif 00530 { NULL, NULL } 00531 }; 00532 00533 #if defined(WIN32) && !defined(C_SDL2) 00534 bool isVirtualBox = false; /* OpenGL never works with Windows XP inside VirtualBox */ 00535 #endif 00536 00537 bool OpenGL_using(void); 00538 00539 #if defined(WIN32) && !defined(S_ISREG) 00540 # define S_ISREG(x) ((x & S_IFREG) == S_IFREG) 00541 #endif 00542 00543 using namespace std; 00544 00545 void UpdateOverscanMenu(void); 00546 00547 const char *DKM_to_string(const unsigned int dkm) { 00548 switch (dkm) { 00549 case DKM_US: return "us"; 00550 case DKM_DEU: return "ger"; 00551 case DKM_JPN_PC98: return "jpn_pc98"; 00552 case DKM_JPN: return "jpn"; 00553 default: break; 00554 } 00555 00556 return ""; 00557 } 00558 00559 const char *DKM_to_descriptive_string(const unsigned int dkm) { 00560 switch (dkm) { 00561 case DKM_US: return "US English"; 00562 case DKM_DEU: return "German"; 00563 case DKM_JPN_PC98: return "Japanese (PC-98)"; 00564 case DKM_JPN: return "Japanese"; 00565 default: break; 00566 } 00567 00568 return ""; 00569 } 00570 00571 #if defined(WIN32) && !defined(HX_DOS) 00572 ITaskbarList3 *winTaskbarList = NULL; 00573 #endif 00574 00575 #if defined(WIN32) && !defined(HX_DOS) 00576 void WindowsTaskbarUpdatePreviewRegion(void) { 00577 if (winTaskbarList != NULL) { 00578 /* Windows 7/8/10: Tell the taskbar which part of our window contains the DOS screen */ 00579 RECT r; 00580 00581 r.top = sdl.clip.y; 00582 r.left = sdl.clip.x; 00583 r.right = sdl.clip.x + sdl.clip.w; 00584 r.bottom = sdl.clip.y + sdl.clip.h; 00585 00586 /* NTS: The MSDN documentation is misleading. Apparently, despite 30+ years of Windows SDK 00587 behavior where the "client area" is the area below the menu bar and inside the frame, 00588 ITaskbarList3's idea of the "client area" is the the area inside the frame INCLUDING 00589 the menu bar. Why? */ 00590 if (GetMenu(GetHWND()) != NULL) { 00591 MENUBARINFO mb; 00592 int rh; 00593 00594 memset(&mb, 0, sizeof(mb)); 00595 mb.cbSize = sizeof(mb); 00596 00597 GetMenuBarInfo(GetHWND(), OBJID_MENU, 0, &mb); // returns absolute screen coordinates, apparently. 00598 rh = mb.rcBar.bottom + 1 - mb.rcBar.top; // menu screen space is top <= y <= bottom, inclusive. 00599 00600 r.top += rh; 00601 r.bottom += rh; 00602 } 00603 00604 if (winTaskbarList->SetThumbnailClip(GetHWND(), &r) != S_OK) 00605 LOG_MSG("WARNING: ITaskbarList3::SetThumbnailClip() failed"); 00606 } 00607 } 00608 00609 void WindowsTaskbarResetPreviewRegion(void) { 00610 if (winTaskbarList != NULL) { 00611 /* Windows 7/8/10: Tell the taskbar which part of our window contains the client area (not including the menu bar) */ 00612 RECT r; 00613 00614 GetClientRect(GetHWND(), &r); 00615 00616 /* NTS: The MSDN documentation is misleading. Apparently, despite 30+ years of Windows SDK 00617 behavior where the "client area" is the area below the menu bar and inside the frame, 00618 ITaskbarList3's idea of the "client area" is the the area inside the frame INCLUDING 00619 the menu bar. Why? */ 00620 if (GetMenu(GetHWND()) != NULL) { 00621 MENUBARINFO mb; 00622 int rh; 00623 00624 memset(&mb, 0, sizeof(mb)); 00625 mb.cbSize = sizeof(mb); 00626 00627 GetMenuBarInfo(GetHWND(), OBJID_MENU, 0, &mb); // returns absolute screen coordinates, apparently. 00628 rh = mb.rcBar.bottom + 1 - mb.rcBar.top; // menu screen space is top <= y <= bottom, inclusive. 00629 00630 r.top += rh; 00631 r.bottom += rh; 00632 } 00633 00634 if (winTaskbarList->SetThumbnailClip(GetHWND(), &r) != S_OK) 00635 LOG_MSG("WARNING: ITaskbarList3::SetThumbnailClip() failed"); 00636 } 00637 } 00638 #endif 00639 00640 unsigned int mapper_keyboard_layout = DKM_US; 00641 unsigned int host_keyboard_layout = DKM_US; 00642 00643 void KeyboardLayoutDetect(void) { 00644 unsigned int nlayout = DKM_US; 00645 00646 #if defined(LINUX) 00647 unsigned int Linux_GetKeyboardLayout(void); 00648 nlayout = Linux_GetKeyboardLayout(); 00649 00650 /* BUGFIX: The xkbmap for 'jp' in Linux/X11 has a problem that maps both 00651 * Ro and Yen to backslash, which in SDL's default state makes 00652 * it impossible to map them properly in the mapper. */ 00653 if (nlayout == DKM_JPN) { 00654 LOG_MSG("Engaging Linux/X11 fix for jp xkbmap in order to handle Ro/Yen keys"); 00655 00656 void Linux_JPXKBFix(void); 00657 Linux_JPXKBFix(); 00658 } 00659 #elif defined(WIN32) 00660 WORD lid = LOWORD(GetKeyboardLayout(0)); 00661 00662 LOG_MSG("Windows keyboard layout ID is 0x%04x", lid); 00663 00664 switch (lid) { 00665 case 0x0407: nlayout = DKM_DEU; break; 00666 case 0x0409: nlayout = DKM_US; break; 00667 case 0x0411: nlayout = DKM_JPN; break; 00668 default: break; 00669 } 00670 #endif 00671 00672 host_keyboard_layout = nlayout; 00673 00674 LOG_MSG("Host keyboard layout is now %s (%s)", 00675 DKM_to_string(host_keyboard_layout), 00676 DKM_to_descriptive_string(host_keyboard_layout)); 00677 } 00678 00679 void SetMapperKeyboardLayout(const unsigned int dkm) { 00680 /* TODO: Make mapper re-initialize layout. If the mapper interface is visible, redraw it. */ 00681 mapper_keyboard_layout = dkm; 00682 00683 LOG_MSG("Mapper keyboard layout is now %s (%s)", 00684 DKM_to_string(mapper_keyboard_layout), 00685 DKM_to_descriptive_string(mapper_keyboard_layout)); 00686 } 00687 00688 #if defined(WIN32) && !defined(C_SDL2) 00689 extern "C" unsigned char SDL1_hax_hasLayoutChanged(void); 00690 extern "C" void SDL1_hax_ackLayoutChanged(void); 00691 #endif 00692 00693 void CheckMapperKeyboardLayout(void) { 00694 #if defined(WIN32) && !defined(C_SDL2) 00695 if (SDL1_hax_hasLayoutChanged()) { 00696 SDL1_hax_ackLayoutChanged(); 00697 LOG_MSG("Keyboard layout changed"); 00698 KeyboardLayoutDetect(); 00699 00700 if (host_keyboard_layout == DKM_JPN && IS_PC98_ARCH) 00701 SetMapperKeyboardLayout(DKM_JPN_PC98); 00702 else 00703 SetMapperKeyboardLayout(host_keyboard_layout); 00704 } 00705 #endif 00706 } 00707 00708 /* yksoft1 says that older MinGW headers lack this value --Jonathan C. */ 00709 #ifndef MAPVK_VK_TO_VSC 00710 #define MAPVK_VK_TO_VSC 0 00711 #endif 00712 00713 bool boot_debug_break = false; 00714 00715 bool window_was_maximized = false; 00716 00717 /* this flag is needed in order to know if we're AT the shell, 00718 or if we're in a program running under the shell. */ 00719 bool dos_shell_running_program = false; 00720 00721 Bitu userResizeWindowWidth = 0, userResizeWindowHeight = 0; 00722 Bitu currentWindowWidth = 640, currentWindowHeight = 480; 00723 00724 bool setSizeButNotResize() { 00725 return (userResizeWindowWidth > 0 && userResizeWindowHeight > 0); 00726 } 00727 00728 int NonUserResizeCounter = 0; 00729 00730 Bitu time_limit_ms = 0; 00731 00732 extern bool keep_umb_on_boot; 00733 extern bool keep_private_area_on_boot; 00734 extern bool dos_kernel_disabled; 00735 bool guest_machine_power_on = false; 00736 00737 std::string custom_savedir; 00738 00739 void SHELL_Run(); 00740 void DisableINT33(); 00741 void EMS_DoShutDown(); 00742 void XMS_DoShutDown(); 00743 void DOS_DoShutDown(); 00744 void GUS_DOS_Shutdown(); 00745 void SBLASTER_DOS_Shutdown(); 00746 void DOS_ShutdownDevices(void); 00747 void RemoveEMSPageFrame(void); 00748 void RemoveUMBBlock(); 00749 void DOS_GetMemory_unmap(); 00750 void VFILE_Shutdown(void); 00751 void PROGRAMS_Shutdown(void); 00752 void DOS_UninstallMisc(void); 00753 void CALLBACK_Shutdown(void); 00754 void DOS_ShutdownDrives(); 00755 void VFILE_Shutdown(void); 00756 void DOS_ShutdownFiles(); 00757 void FreeBIOSDiskList(); 00758 void GFX_ShutDown(void); 00759 void MAPPER_Shutdown(); 00760 void SHELL_Init(void); 00761 void PasteClipboard(bool bPressed); 00762 void CopyClipboard(void); 00763 00764 #if C_DYNAMIC_X86 00765 void CPU_Core_Dyn_X86_Shutdown(void); 00766 #endif 00767 00768 void UpdateWindowMaximized(bool flag) { 00769 menu.maxwindow = flag; 00770 } 00771 00772 void UpdateWindowDimensions(Bitu width, Bitu height) 00773 { 00774 currentWindowWidth = width; 00775 currentWindowHeight = height; 00776 } 00777 00778 void PrintScreenSizeInfo(void) { 00779 #if 1 00780 const char *method = "?"; 00781 00782 switch (screen_size_info.method) { 00783 case METHOD_NONE: method = "None"; break; 00784 case METHOD_X11: method = "X11"; break; 00785 case METHOD_XRANDR: method = "XRandR"; break; 00786 case METHOD_WIN98BASE: method = "Win98base"; break; 00787 case METHOD_COREGRAPHICS:method = "CoreGraphics";break; 00788 default: break; 00789 } 00790 00791 LOG_MSG("Screen report: Method '%s' (%.3f x %.3f pixels) at (%.3f x %.3f) (%.3f x %.3f mm) (%.3f x %.3f in) (%.3f x %.3f DPI)", 00792 method, 00793 00794 screen_size_info.screen_dimensions_pixels.width, 00795 screen_size_info.screen_dimensions_pixels.height, 00796 00797 screen_size_info.screen_position_pixels.x, 00798 screen_size_info.screen_position_pixels.y, 00799 00800 screen_size_info.screen_dimensions_mm.width, 00801 screen_size_info.screen_dimensions_mm.height, 00802 00803 screen_size_info.screen_dimensions_mm.width / 25.4, 00804 screen_size_info.screen_dimensions_mm.height / 25.4, 00805 00806 screen_size_info.screen_dpi.width, 00807 screen_size_info.screen_dpi.height); 00808 #endif 00809 } 00810 00811 #if defined(WIN32) 00812 void Windows_GetWindowDPI(ScreenSizeInfo &info) { 00813 info.clear(); 00814 00815 # if !defined(HX_DOS) 00816 HMONITOR mon; 00817 HWND hwnd; 00818 00819 info.method = METHOD_WIN98BASE; 00820 00821 hwnd = GetHWND(); 00822 if (hwnd == NULL) return; 00823 00824 mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); 00825 if (mon == NULL) mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); 00826 if (mon == NULL) return; 00827 00828 MONITORINFO mi; 00829 memset(&mi,0,sizeof(mi)); 00830 mi.cbSize = sizeof(mi); 00831 if (!GetMonitorInfo(mon,&mi)) return; 00832 00833 info.screen_position_pixels.x = mi.rcMonitor.left; 00834 info.screen_position_pixels.y = mi.rcMonitor.top; 00835 00836 info.screen_dimensions_pixels.width = mi.rcMonitor.right - mi.rcMonitor.left; 00837 info.screen_dimensions_pixels.height = mi.rcMonitor.bottom - mi.rcMonitor.top; 00838 00839 /* Windows 10 build 1607 and later offer a "Get DPI of window" function */ 00840 { 00841 HMODULE __user32; 00842 00843 __user32 = GetModuleHandle("USER32.DLL"); 00844 if (__user32) { 00845 UINT (WINAPI *__GetDpiForWindow)(HWND) = NULL; 00846 00847 __GetDpiForWindow = (UINT (WINAPI *)(HWND))GetProcAddress(__user32,"GetDpiForWindow"); 00848 if (__GetDpiForWindow) { 00849 UINT dpi = __GetDpiForWindow(hwnd); 00850 00851 if (dpi != 0) { 00852 info.screen_dpi.width = dpi; 00853 info.screen_dpi.height = dpi; 00854 00855 info.screen_dimensions_mm.width = (25.4 * screen_size_info.screen_dimensions_pixels.width) / dpi; 00856 info.screen_dimensions_mm.height = (25.4 * screen_size_info.screen_dimensions_pixels.height) / dpi; 00857 } 00858 } 00859 } 00860 } 00861 # endif 00862 } 00863 #endif 00864 00865 void UpdateWindowDimensions(void) 00866 { 00867 #if defined(C_SDL2) 00868 int w = 640,h = 480; 00869 SDL_GetWindowSize(sdl.window, &w, &h); 00870 UpdateWindowDimensions(w,h); 00871 00872 Uint32 fl = SDL_GetWindowFlags(sdl.window); 00873 UpdateWindowMaximized((fl & SDL_WINDOW_MAXIMIZED) != 0); 00874 #endif 00875 #if defined(MACOSX) 00876 void MacOSX_GetWindowDPI(ScreenSizeInfo &info); 00877 MacOSX_GetWindowDPI(/*&*/screen_size_info); 00878 #endif 00879 #if defined(WIN32) 00880 // When maximized, SDL won't actually tell us our new dimensions, so get it ourselves. 00881 // FIXME: Instead of GetHWND() we need to track our own handle or add something to SDL 1.x 00882 // to provide the handle! 00883 RECT r = { 0 }; 00884 00885 GetClientRect(GetHWND(), &r); 00886 UpdateWindowDimensions(r.right, r.bottom); 00887 UpdateWindowMaximized(IsZoomed(GetHWND())); 00888 Windows_GetWindowDPI(/*&*/screen_size_info); 00889 #endif 00890 #if defined(LINUX) 00891 void UpdateWindowDimensions_Linux(void); 00892 UpdateWindowDimensions_Linux(); 00893 void Linux_GetWindowDPI(ScreenSizeInfo &info); 00894 Linux_GetWindowDPI(/*&*/screen_size_info); 00895 #endif 00896 PrintScreenSizeInfo(); 00897 } 00898 00899 #define MAPPERFILE_SDL1 "mapper-" VERSION ".map" 00900 #define MAPPERFILE_SDL2 "mapper-" VERSION ".sdl2.map" 00901 #if defined(C_SDL2) 00902 # define MAPPERFILE MAPPERFILE_SDL2 00903 #else 00904 # define MAPPERFILE MAPPERFILE_SDL1 00905 #endif 00906 00907 void GUI_ResetResize(bool); 00908 void GUI_LoadFonts(); 00909 void GUI_Run(bool); 00910 00911 const char* titlebar = NULL; 00912 extern const char* RunningProgram; 00913 extern bool CPU_CycleAutoAdjust; 00914 #if !(ENVIRON_INCLUDED) 00915 extern char** environ; 00916 #endif 00917 00918 double rtdelta = 0; 00919 bool emu_paused = false; 00920 bool mouselocked = false; //Global variable for mapper 00921 bool fullscreen_switch = true; 00922 bool dos_kernel_disabled = true; 00923 bool startup_state_numlock = false; // Global for keyboard initialisation 00924 bool startup_state_capslock = false; // Global for keyboard initialisation 00925 bool startup_state_scrlock = false; // Global for keyboard initialisation 00926 int mouse_start_x=-1, mouse_start_y=-1, mouse_end_x=-1, mouse_end_y=-1, fx=-1, fy=-1, paste_speed=20, wheel_key=0; 00927 const char *modifier; 00928 00929 #if defined(WIN32) && !defined(C_SDL2) 00930 extern "C" void SDL1_hax_SetMenu(HMENU menu); 00931 #endif 00932 00933 #ifdef WIN32 00934 # include <windows.h> 00935 #endif 00936 00937 #ifdef WIN32 00938 # define STDOUT_FILE TEXT("stdout.txt") 00939 # define STDERR_FILE TEXT("stderr.txt") 00940 # define DEFAULT_CONFIG_FILE "/dosbox-x.conf" 00941 #elif defined(MACOSX) 00942 # define DEFAULT_CONFIG_FILE "/Library/Preferences/DOSBox Preferences" 00943 #elif defined(HAIKU) 00944 #define DEFAULT_CONFIG_FILE "~/config/settings/dosbox-x/dosbox-x.conf" 00945 #else /*linux freebsd*/ 00946 # define DEFAULT_CONFIG_FILE "/.dosboxrc" 00947 #endif 00948 00949 #if C_SET_PRIORITY 00950 # include <sys/resource.h> 00951 # define PRIO_TOTAL (PRIO_MAX-PRIO_MIN) 00952 #endif 00953 00954 #ifdef OS2 00955 # include <os2.h> 00956 #endif 00957 00958 #if defined(C_SDL2) 00959 # if defined(WIN32) 00960 HWND GetHWND() 00961 { 00962 SDL_SysWMinfo wmi; 00963 SDL_VERSION(&wmi.version); 00964 if (sdl.window == NULL) 00965 return nullptr; 00966 if (!SDL_GetWindowWMInfo(sdl.window, &wmi)) 00967 return nullptr; 00968 return wmi.info.win.window; 00969 } 00970 00971 HWND GetSurfaceHWND() 00972 { 00973 return GetHWND(); 00974 } 00975 # endif 00976 #endif 00977 void SDL_rect_cliptoscreen(SDL_Rect &r) { 00978 if (r.x < 0) { 00979 r.w += r.x; 00980 r.x = 0; 00981 } 00982 if (r.y < 0) { 00983 r.h += r.y; 00984 r.y = 0; 00985 } 00986 if ((r.x+r.w) > sdl.surface->w) 00987 r.w = sdl.surface->w - r.x; 00988 if ((r.y+r.h) > sdl.surface->h) 00989 r.h = sdl.surface->h - r.y; 00990 /* NTS: Apparently r.w and r.h are unsigned, therefore no need to check if negative */ 00991 // if (r.w < 0) r.w = 0; 00992 // if (r.h < 0) r.h = 0; 00993 } 00994 00995 Bitu GUI_JoystickCount(void) { 00996 return sdl.num_joysticks; 00997 } 00998 00999 #if !defined(MACOSX) 01000 /* TODO: should move to it's own file ================================================ */ 01001 static unsigned char logo[32*32*4]= { 01002 #include "dosbox_logo.h" 01003 }; 01004 #endif 01005 01006 #if !defined(MACOSX) 01007 static void DOSBox_SetOriginalIcon(void) { 01008 SDL_Surface *logos; 01009 01010 #ifdef WORDS_BIGENDIAN 01011 logos = SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0xff000000,0x00ff0000,0x0000ff00,0); 01012 #else 01013 logos = SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0x000000ff,0x0000ff00,0x00ff0000,0); 01014 #endif 01015 01016 #if defined(C_SDL2) 01017 SDL_SetWindowIcon(sdl.window, logos); 01018 #else 01019 SDL_WM_SetIcon(logos,NULL); 01020 #endif 01021 } 01022 #endif 01023 /* =================================================================================== */ 01024 01025 #if defined (WIN32) 01026 bool GFX_SDLUsingWinDIB(void) { 01027 return sdl.using_windib; 01028 } 01029 #endif 01030 01031 void GFX_SetIcon(void) 01032 { 01033 #if !defined(MACOSX) 01034 /* Set Icon (must be done before any sdl_setvideomode call) */ 01035 /* But don't set it on OS X, as we use a nicer external icon there. */ 01036 /* Made into a separate call, so it can be called again when we restart the graphics output on win32 */ 01037 if (menu_compatible) { DOSBox_SetOriginalIcon(); return; } 01038 #endif 01039 01040 #if defined(WIN32) && !defined(C_SDL2) 01041 HICON hIcon1; 01042 01043 hIcon1 = (HICON) LoadImage( GetModuleHandle(NULL), MAKEINTRESOURCE(dosbox_ico), IMAGE_ICON, 01044 16,16,LR_DEFAULTSIZE); 01045 01046 SendMessage(GetHWND(), WM_SETICON, ICON_SMALL, (LPARAM) hIcon1 ); 01047 #endif 01048 } 01049 01050 #if C_DEBUG 01051 bool IsDebuggerActive(void); 01052 #endif 01053 01054 extern std::string dosbox_title; 01055 01056 void GFX_SetTitle(Bit32s cycles,Bits frameskip,Bits timing,bool paused){ 01057 (void)frameskip;//UNUSED 01058 (void)timing;//UNUSED 01059 // static Bits internal_frameskip=0; 01060 static Bit32s internal_cycles=0; 01061 // static Bits internal_timing=0; 01062 char title[200] = {0}; 01063 01064 Section_prop *section = static_cast<Section_prop *>(control->GetSection("SDL")); 01065 assert(section != NULL); 01066 titlebar = section->Get_string("titlebar"); 01067 01068 if (cycles != -1) internal_cycles = cycles; 01069 // if (timing != -1) internal_timing = timing; 01070 // if (frameskip != -1) internal_frameskip = frameskip; 01071 01072 if (CPU_CycleAutoAdjust) { 01073 sprintf(title,"%s%sDOSBox-X %s, %d%%", 01074 dosbox_title.c_str(),dosbox_title.empty()?"":": ", 01075 VERSION,(int)internal_cycles); 01076 } 01077 else { 01078 sprintf(title,"%s%sDOSBox-X %s, %d cyc/ms", 01079 dosbox_title.c_str(),dosbox_title.empty()?"":": ", 01080 VERSION,(int)internal_cycles); 01081 } 01082 01083 { 01084 const char *what = (titlebar != NULL && *titlebar != 0) ? titlebar : RunningProgram; 01085 01086 if (what != NULL && *what != 0) { 01087 char *p = title + strlen(title); // append to end of string 01088 01089 sprintf(p,", %s",what); 01090 } 01091 } 01092 01093 if (!menu.hidecycles) { 01094 char *p = title + strlen(title); // append to end of string 01095 01096 sprintf(p,", FPS %2d",(int)frames); 01097 } 01098 01099 if (menu.showrt) { 01100 char *p = title + strlen(title); // append to end of string 01101 01102 sprintf(p,", %2d%%/RT",(int)floor((rtdelta / 10) + 0.5)); 01103 } 01104 01105 if (paused) strcat(title," PAUSED"); 01106 #if C_DEBUG 01107 if (IsDebuggerActive()) strcat(title," DEBUGGER"); 01108 #endif 01109 #if defined(C_SDL2) 01110 SDL_SetWindowTitle(sdl.window,title); 01111 #else 01112 SDL_WM_SetCaption(title,VERSION); 01113 #endif 01114 } 01115 01116 bool warn_on_mem_write = false; 01117 01118 void CPU_Snap_Back_To_Real_Mode(); 01119 01120 static void KillSwitch(bool pressed) { 01121 if (!pressed) return; 01122 if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); 01123 #if 0 /* Re-enable this hack IF DOSBox-X continues to have problems page-faulting on kill switch */ 01124 CPU_Snap_Back_To_Real_Mode(); /* TEMPORARY HACK. There are portions of DOSBox that write to memory as if still running DOS. */ 01125 /* ^ Without this hack, when running Windows NT 3.1 this Kill Switch effectively becomes the Instant Page Fault BSOD switch 01126 * because the DOSBox-X code attempting to write to real mode memory causes a page fault (though hitting the kill switch a 01127 * second time shuts DOSBox-X down properly). It's sort of the same issue behind the INT 33h emulation causing instant BSOD 01128 * in Windows NT the instant you moved or clicked the mouse. The purpose of this hack is that, before any of that DOSBox-X 01129 * code has a chance, we force the CPU back into real mode so that the code doesn't trigger funny page faults and DOSBox-X 01130 * shuts down properly. */ 01131 #endif 01132 warn_on_mem_write = true; 01133 throw 1; 01134 } 01135 01136 void DoKillSwitch(void) { 01137 KillSwitch(true); 01138 } 01139 01140 void BlankDisplay(void) { 01141 if (OpenGL_using()) { 01142 LOG_MSG("FIXME: BlankDisplay() not implemented for OpenGL mode"); 01143 } 01144 else { 01145 SDL_FillRect(sdl.surface,0,0); 01146 #if defined(C_SDL2) 01147 SDL_UpdateWindowSurface(sdl.window); 01148 #else 01149 SDL_Flip(sdl.surface); 01150 #endif 01151 } 01152 } 01153 01154 void GFX_SDL_Overscan(void) { 01155 sdl.overscan_color=0; 01156 if (sdl.overscan_width) { 01157 Bitu border_color = GFX_GetRGB(vga.dac.rgb[vga.attr.overscan_color].red<<2, 01158 vga.dac.rgb[vga.attr.overscan_color].green<<2, vga.dac.rgb[vga.attr.overscan_color].blue<<2); 01159 if (border_color != sdl.overscan_color) { 01160 sdl.overscan_color = border_color; 01161 01162 // Find four rectangles forming the border 01163 SDL_Rect *rect = &sdl.updateRects[0]; 01164 rect->x = 0; rect->y = 0; rect->w = sdl.draw.width+(unsigned int)(2*sdl.clip.x); rect->h = (uint16_t)sdl.clip.y; // top 01165 if ((Bitu)rect->h > (Bitu)sdl.overscan_width) { rect->y += (int)(rect->h-sdl.overscan_width); rect->h = (uint16_t)sdl.overscan_width; } 01166 if ((Bitu)sdl.clip.x > (Bitu)sdl.overscan_width) { rect->x += (int)sdl.clip.x-(int)sdl.overscan_width; rect->w -= (uint16_t)(2*((int)sdl.clip.x-(int)sdl.overscan_width)); } 01167 rect = &sdl.updateRects[1]; 01168 rect->x = 0; rect->y = sdl.clip.y; rect->w = (uint16_t)sdl.clip.x; rect->h = (uint16_t)sdl.draw.height; // left 01169 if ((unsigned int)rect->w > (unsigned int)sdl.overscan_width) { rect->x += (int)rect->w-(int)sdl.overscan_width; rect->w = (uint16_t)sdl.overscan_width; } 01170 rect = &sdl.updateRects[2]; 01171 rect->x = (int)sdl.clip.x+(int)sdl.draw.width; rect->y = sdl.clip.y; rect->w = (uint16_t)sdl.clip.x; rect->h = (uint16_t)sdl.draw.height; // right 01172 if ((unsigned int)rect->w > (unsigned int)sdl.overscan_width) { rect->w = (uint16_t)sdl.overscan_width; } 01173 rect = &sdl.updateRects[3]; 01174 rect->x = 0; rect->y = (int)sdl.clip.y+(int)sdl.draw.height; rect->w = sdl.draw.width+(unsigned int)(2*sdl.clip.x); rect->h = (uint16_t)sdl.clip.y; // bottom 01175 if ((Bitu)rect->h > (Bitu)sdl.overscan_width) { rect->h = (uint16_t)sdl.overscan_width; } 01176 if ((Bitu)sdl.clip.x > (Bitu)sdl.overscan_width) { rect->x += (int)sdl.clip.x-(int)sdl.overscan_width; rect->w -= (unsigned int)(2*((int)sdl.clip.x-(int)sdl.overscan_width)); } 01177 01178 if (sdl.surface->format->BitsPerPixel == 8) { // SDL_FillRect seems to have some issues with palettized hw surfaces 01179 Bit8u* pixelptr = (Bit8u*)sdl.surface->pixels; 01180 Bitu linepitch = sdl.surface->pitch; 01181 for (Bitu i=0; i<4; i++) { 01182 rect = &sdl.updateRects[i]; 01183 Bit8u* start = pixelptr + (unsigned int)rect->y*(unsigned int)linepitch + (unsigned int)rect->x; 01184 for (Bitu j=0; j<(unsigned int)rect->h; j++) { 01185 memset(start, vga.attr.overscan_color, rect->w); 01186 start += linepitch; 01187 } 01188 } 01189 } else { 01190 for (Bitu i=0; i<4; i++) 01191 SDL_FillRect(sdl.surface, &sdl.updateRects[i], (Uint32)border_color); 01192 01193 #if defined(C_SDL2) 01194 SDL_UpdateWindowSurfaceRects(sdl.window, sdl.updateRects, 4); 01195 #else 01196 SDL_UpdateRects(sdl.surface, 4, sdl.updateRects); 01197 #endif 01198 } 01199 } 01200 } 01201 } 01202 01203 bool DOSBox_Paused() 01204 { 01205 return emu_paused; 01206 } 01207 01208 bool pause_on_vsync = false; 01209 01210 #if defined(C_SDL2) 01211 static bool IsFullscreen() { 01212 if (sdl.window == NULL) return false; 01213 uint32_t windowFlags = SDL_GetWindowFlags(sdl.window); 01214 if (windowFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) return true; 01215 return false; 01216 } 01217 #endif 01218 01219 bool is_paused = false; 01220 bool unpause_now = false; 01221 bool pausewithinterrupts_enable = false; 01222 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU 01223 int pause_menu_item_tag = -1; 01224 #endif 01225 01226 void PushDummySDL(void) { 01227 SDL_Event event; 01228 01229 memset(&event,0,sizeof(event)); 01230 event.type = SDL_KEYUP; 01231 SDL_PushEvent(&event); 01232 } 01233 01234 static void HandleMouseMotion(SDL_MouseMotionEvent * motion); 01235 static void HandleMouseButton(SDL_MouseButtonEvent * button, SDL_MouseMotionEvent * motion); 01236 01237 #if defined(C_SDL2) 01238 # if !defined(IGNORE_TOUCHSCREEN) 01239 static void HandleTouchscreenFinger(SDL_TouchFingerEvent * finger); 01240 # endif 01241 #endif 01242 01243 #if defined(C_SDL2) 01244 static const SDL_TouchID no_touch_id = (SDL_TouchID)(~0ULL); 01245 static const SDL_FingerID no_finger_id = (SDL_FingerID)(~0ULL); 01246 static SDL_FingerID touchscreen_finger_lock = no_finger_id; 01247 static SDL_TouchID touchscreen_touch_lock = no_touch_id; 01248 #endif 01249 01250 void PauseDOSBoxLoop(Bitu /*unused*/) { 01251 bool paused = true; 01252 SDL_Event event; 01253 01254 /* reflect in the menu that we're paused now */ 01255 mainMenu.get_item("mapper_pause").check(true).refresh_item(mainMenu); 01256 01257 void MAPPER_ReleaseAllKeys(void); 01258 MAPPER_ReleaseAllKeys(); 01259 01260 GFX_SetTitle(-1,-1,-1,true); 01261 // KEYBOARD_ClrBuffer(); 01262 GFX_LosingFocus(); 01263 while (SDL_PollEvent(&event)); // flush event queue. 01264 01265 // reset pause conditions 01266 pause_on_vsync = false; 01267 01268 // give mouse to win32 (ex. alt-tab) 01269 #if defined(C_SDL2) 01270 SDL_SetRelativeMouseMode(SDL_FALSE); 01271 #else 01272 SDL_WM_GrabInput(SDL_GRAB_OFF); 01273 #endif 01274 01275 is_paused = true; 01276 01277 while (paused) { 01278 if (unpause_now) { 01279 unpause_now = false; 01280 break; 01281 } 01282 01283 #if C_EMSCRIPTEN 01284 emscripten_sleep_with_yield(0); 01285 SDL_PollEvent(&event); 01286 #else 01287 SDL_WaitEvent(&event); // since we're not polling, cpu usage drops to 0. 01288 #endif 01289 01290 #ifdef __WIN32__ 01291 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 01292 if (event.type==SDL_SYSWMEVENT && event.syswm.msg->msg == WM_COMMAND && (LOWORD(event.syswm.msg->wParam) == ID_WIN_SYSMENU_PAUSE || LOWORD(event.syswm.msg->wParam) == (mainMenu.get_item("mapper_pause").get_master_id()+DOSBoxMenu::winMenuMinimumID))) { 01293 paused=false; 01294 GFX_SetTitle(-1,-1,-1,false); 01295 break; 01296 } 01297 if (event.type == SDL_SYSWMEVENT && event.syswm.msg->msg == WM_SYSCOMMAND && LOWORD(event.syswm.msg->wParam) == ID_WIN_SYSMENU_PAUSE) { 01298 paused = false; 01299 GFX_SetTitle(-1, -1, -1, false); 01300 break; 01301 } 01302 #endif 01303 #endif 01304 switch (event.type) { 01305 01306 case SDL_QUIT: KillSwitch(true); break; 01307 case SDL_KEYDOWN: // Must use Pause/Break or escape Key to resume. 01308 if(event.key.keysym.sym == SDLK_PAUSE || event.key.keysym.sym == SDLK_ESCAPE) { 01309 01310 paused = false; 01311 GFX_SetTitle(-1,-1,-1,false); 01312 break; 01313 } 01314 else if (event.key.keysym.sym == SDLK_SPACE) { /* spacebar = single frame step */ 01315 /* resume, but let the VGA code know to call us on vertical retrace */ 01316 paused = false; 01317 pause_on_vsync = true; 01318 GFX_SetTitle(-1,-1,-1,false); 01319 break; 01320 } 01321 #if defined (MACOSX) && !defined(C_SDL2) 01322 if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { 01323 /* On macs, all apps exit when pressing cmd-q */ 01324 KillSwitch(true); 01325 break; 01326 } 01327 #endif 01328 case SDL_MOUSEMOTION: 01329 #if defined(C_SDL2) 01330 if (touchscreen_finger_lock == no_finger_id && 01331 touchscreen_touch_lock == no_touch_id && 01332 event.motion.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */ 01333 HandleMouseMotion(&event.motion); 01334 } 01335 #else 01336 HandleMouseMotion(&event.motion); 01337 #endif 01338 break; 01339 case SDL_MOUSEBUTTONDOWN: 01340 case SDL_MOUSEBUTTONUP: 01341 #if defined(C_SDL2) 01342 if (touchscreen_finger_lock == no_finger_id && 01343 touchscreen_touch_lock == no_touch_id && 01344 event.button.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */ 01345 HandleMouseButton(&event.button,&event.motion); 01346 } 01347 #else 01348 HandleMouseButton(&event.button,&event.motion); 01349 #endif 01350 break; 01351 #if defined(C_SDL2) 01352 # if !defined(IGNORE_TOUCHSCREEN) 01353 case SDL_FINGERDOWN: 01354 case SDL_FINGERUP: 01355 case SDL_FINGERMOTION: 01356 HandleTouchscreenFinger(&event.tfinger); 01357 break; 01358 # endif 01359 #endif 01360 } 01361 } 01362 01363 // restore mouse state 01364 void GFX_UpdateSDLCaptureState(); 01365 GFX_UpdateSDLCaptureState(); 01366 01367 void MAPPER_ReleaseAllKeys(void); 01368 MAPPER_ReleaseAllKeys(); 01369 01370 // KEYBOARD_ClrBuffer(); 01371 GFX_LosingFocus(); 01372 01373 // redraw screen (ex. fullscreen - pause - alt+tab x2 - unpause) 01374 if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackReset ); 01375 01376 /* reflect in the menu that we're paused now */ 01377 mainMenu.get_item("mapper_pause").check(false).refresh_item(mainMenu); 01378 01379 is_paused = false; 01380 } 01381 01382 void PauseDOSBox(bool pressed) { 01383 if (pressed) { 01384 if (is_paused) { 01385 unpause_now = true; 01386 PushDummySDL(); 01387 } 01388 else { 01389 PIC_AddEvent(PauseDOSBoxLoop,0.001); 01390 } 01391 } 01392 } 01393 01394 #if defined(C_SDL2) 01395 static bool SDL2_resize_enable = false; 01396 01397 SDL_Window* GFX_GetSDLWindow(void) { 01398 return sdl.window; 01399 } 01400 01401 SDL_Window* GFX_SetSDLWindowMode(Bit16u width, Bit16u height, SCREEN_TYPES screenType) 01402 { 01403 static SCREEN_TYPES lastType = SCREEN_SURFACE; 01404 if (sdl.renderer) { 01405 SDL_DestroyRenderer(sdl.renderer); 01406 sdl.renderer=0; 01407 } 01408 if (sdl.texture.pixelFormat) { 01409 SDL_FreeFormat(sdl.texture.pixelFormat); 01410 sdl.texture.pixelFormat = 0; 01411 } 01412 if (sdl.texture.texture) { 01413 SDL_DestroyTexture(sdl.texture.texture); 01414 sdl.texture.texture=0; 01415 } 01416 sdl.window_desired_width = width; 01417 sdl.window_desired_height = height; 01418 int currWidth, currHeight; 01419 if (sdl.window) { 01420 //SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); 01421 if (!sdl.update_window) { 01422 SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); 01423 sdl.update_display_contents = ((width == currWidth) && (height == currHeight)); 01424 01425 currentWindowWidth = currWidth; 01426 currentWindowHeight = currHeight; 01427 01428 return sdl.window; 01429 } 01430 } 01431 01432 #if C_OPENGL 01433 if (sdl_opengl.context) { 01434 SDL_GL_DeleteContext(sdl_opengl.context); 01435 sdl_opengl.context=0; 01436 } 01437 #endif 01438 01439 /* If we change screen type, recreate the window. Furthermore, if 01440 * it is our very first time then we simply create a new window. 01441 */ 01442 if (!sdl.window 01443 || (lastType != screenType) 01444 // || (currWidth != width) || (currHeight != height) 01445 // || (glwindow != (0 != (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_OPENGL))) 01446 // || (fullscreen && (0 == (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_FULLSCREEN))) 01447 // || (fullscreen != (SDL_WINDOW_FULLSCREEN == (SDL_GetWindowFlags(sdl.window) & SDL_WINDOW_FULLSCREEN))) 01448 // || (fullscreen && ((width != currWidth) || (height != currHeight))) 01449 ) { 01450 lastType = screenType; 01451 if (sdl.window) { 01452 SDL_DestroyWindow(sdl.window); 01453 } 01454 01455 sdl.window = SDL_CreateWindow("", 01456 SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber), 01457 SDL_WINDOWPOS_UNDEFINED_DISPLAY(sdl.displayNumber), 01458 width, height, 01459 (GFX_IsFullscreen() ? (sdl.desktop.full.display_res ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN) : 0) 01460 | ((screenType == SCREEN_OPENGL) ? SDL_WINDOW_OPENGL : 0) | SDL_WINDOW_SHOWN 01461 | (SDL2_resize_enable ? SDL_WINDOW_RESIZABLE : 0) 01462 | (dpi_aware_enable ? SDL_WINDOW_ALLOW_HIGHDPI : 0)); 01463 if (sdl.window) { 01464 GFX_SetTitle(-1, -1, -1, false); //refresh title. 01465 } 01466 sdl.surface = SDL_GetWindowSurface(sdl.window); 01467 SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); 01468 sdl.update_display_contents = ((width == currWidth) && (height == currHeight)); 01469 01470 currentWindowWidth = currWidth; 01471 currentWindowHeight = currHeight; 01472 01473 #if C_OPENGL 01474 if (screenType == SCREEN_OPENGL) { 01475 sdl_opengl.context = SDL_GL_CreateContext(sdl.window); 01476 if (sdl_opengl.context == NULL) LOG_MSG("WARNING: SDL2 unable to create GL context"); 01477 if (SDL_GL_MakeCurrent(sdl.window, sdl_opengl.context) != 0) LOG_MSG("WARNING: SDL2 unable to make current GL context"); 01478 } 01479 #endif 01480 01481 return sdl.window; 01482 } 01483 /* Fullscreen mode switching has its limits, and is also problematic on 01484 * some window managers. For now, the following may work up to some 01485 * level. On X11, SDL_VIDEO_X11_LEGACY_FULLSCREEN=1 can also help, 01486 * although it has its own issues. 01487 * Suggestion: Use the desktop res if possible, with output=surface 01488 * if one is not interested in scaling. 01489 * On Android, desktop res is the only way. 01490 */ 01491 SDL_SetWindowResizable(sdl.window, SDL2_resize_enable ? SDL_TRUE : SDL_FALSE); 01492 if (GFX_IsFullscreen()) { 01493 SDL_DisplayMode displayMode; 01494 SDL_GetWindowDisplayMode(sdl.window, &displayMode); 01495 displayMode.w = width; 01496 displayMode.h = height; 01497 SDL_SetWindowDisplayMode(sdl.window, &displayMode); 01498 01499 SDL_SetWindowFullscreen(sdl.window, SDL_WINDOW_FULLSCREEN_DESKTOP); 01500 } else { 01501 SDL_SetWindowFullscreen(sdl.window, 0); 01502 01503 SDL_SetWindowSize(sdl.window, width, height); 01504 } 01505 /* Maybe some requested fullscreen resolution is unsupported? */ 01506 SDL_GetWindowSize(sdl.window, &currWidth, &currHeight); 01507 sdl.update_display_contents = ((width == currWidth) && (height == currHeight)); 01508 sdl.surface = SDL_GetWindowSurface(sdl.window); 01509 01510 currentWindowWidth = currWidth; 01511 currentWindowHeight = currHeight; 01512 01513 #if C_OPENGL 01514 if (screenType == SCREEN_OPENGL) { 01515 sdl_opengl.context = SDL_GL_CreateContext(sdl.window); 01516 if (sdl_opengl.context == NULL) LOG_MSG("WARNING: SDL2 unable to create GL context"); 01517 if (SDL_GL_MakeCurrent(sdl.window, sdl_opengl.context) != 0) LOG_MSG("WARNING: SDL2 unable to make current GL context"); 01518 } 01519 #endif 01520 01521 return sdl.window; 01522 } 01523 01524 void GFX_SetResizeable(bool enable) { 01525 if (SDL2_resize_enable != enable) { 01526 SDL2_resize_enable = enable; 01527 01528 if (sdl.window != NULL) 01529 SDL_SetWindowResizable(sdl.window, SDL2_resize_enable ? SDL_TRUE : SDL_FALSE); 01530 } 01531 } 01532 01533 // Used for the mapper UI and more: Creates a fullscreen window with desktop res 01534 // on Android, and a non-fullscreen window with the input dimensions otherwise. 01535 SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height) { 01536 return GFX_SetSDLWindowMode(width, height, SCREEN_SURFACE); 01537 } 01538 01539 // Returns the rectangle in the current window to be used for scaling a 01540 // sub-window with the given dimensions, like the mapper UI. 01541 SDL_Rect GFX_GetSDLSurfaceSubwindowDims(Bit16u width, Bit16u height) { 01542 SDL_Rect rect; 01543 rect.x=rect.y=0; 01544 rect.w=width; 01545 rect.h=height; 01546 return rect; 01547 } 01548 01549 # if !defined(C_SDL2) 01550 // Currently used for an initial test here 01551 static SDL_Window * GFX_SetSDLOpenGLWindow(Bit16u width, Bit16u height) { 01552 return GFX_SetSDLWindowMode(width, height, SCREEN_OPENGL); 01553 } 01554 # endif 01555 #endif 01556 01557 #if C_OPENGL && DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01558 unsigned int SDLDrawGenFontTextureUnitPerRow = 16; 01559 unsigned int SDLDrawGenFontTextureRows = 16; 01560 unsigned int SDLDrawGenFontTextureWidth = SDLDrawGenFontTextureUnitPerRow * 8; 01561 unsigned int SDLDrawGenFontTextureHeight = SDLDrawGenFontTextureRows * 16; 01562 bool SDLDrawGenFontTextureInit = false; 01563 GLuint SDLDrawGenFontTexture = (GLuint)(~0UL); 01564 #endif 01565 01566 #if !defined(C_SDL2) 01567 /* Reset the screen with current values in the sdl structure */ 01568 Bitu GFX_GetBestMode(Bitu flags) 01569 { 01570 Bitu retFlags = 0; 01571 01572 switch (sdl.desktop.want_type) 01573 { 01574 case SCREEN_SURFACE: 01575 retFlags = OUTPUT_SURFACE_GetBestMode(flags); 01576 break; 01577 01578 #if C_OPENGL 01579 case SCREEN_OPENGL: 01580 retFlags = OUTPUT_OPENGL_GetBestMode(flags); 01581 break; 01582 #endif 01583 01584 #if C_DIRECT3D 01585 case SCREEN_DIRECT3D: 01586 retFlags = OUTPUT_DIRECT3D_GetBestMode(flags); 01587 break; 01588 #endif 01589 01590 default: 01591 // we should never reach here 01592 retFlags = 0; 01593 break; 01594 } 01595 01596 if (!retFlags) 01597 { 01598 if (sdl.desktop.want_type != SCREEN_SURFACE) 01599 { 01600 // try falling back down to surface 01601 OUTPUT_SURFACE_Select(); 01602 retFlags = OUTPUT_SURFACE_GetBestMode(flags); 01603 } 01604 if (retFlags == 0) 01605 LOG_MSG("SDL:Failed everything including falling back to surface GFX_GetBestMode"); // completely failed it seems 01606 } 01607 01608 return retFlags; 01609 } 01610 #endif 01611 01612 /* FIXME: This prepares the SDL library to accept Win32 drag+drop events from the Windows shell. 01613 * So it should be named something like EnableDragAcceptFiles() not SDL_Prepare() */ 01614 void SDL_Prepare(void) { 01615 if (menu_compatible) return; 01616 01617 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) // Microsoft Windows specific 01618 LOG(LOG_MISC,LOG_DEBUG)("Win32: Preparing main window to accept files dragged in from the Windows shell"); 01619 01620 SDL_PumpEvents(); SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); 01621 DragAcceptFiles(GetHWND(), TRUE); 01622 #endif 01623 } 01624 01625 void GFX_ForceRedrawScreen(void) { 01626 GFX_Stop(); 01627 if (sdl.draw.callback) 01628 (sdl.draw.callback)( GFX_CallBackReset ); 01629 GFX_Start(); 01630 } 01631 01632 void GFX_ResetScreen(void) { 01633 fullscreen_switch=false; 01634 GFX_Stop(); 01635 if (sdl.draw.callback) 01636 (sdl.draw.callback)( GFX_CallBackReset ); 01637 GFX_Start(); 01638 CPU_Reset_AutoAdjust(); 01639 fullscreen_switch=true; 01640 #if !defined(C_SDL2) 01641 if (!sdl.desktop.fullscreen) DOSBox_RefreshMenu(); // for menu 01642 #endif 01643 } 01644 01645 void GFX_ForceFullscreenExit(void) { 01646 if (sdl.desktop.lazy_fullscreen) { 01647 LOG_MSG("GFX LF: invalid screen change"); 01648 } else { 01649 sdl.desktop.fullscreen=false; 01650 GFX_ResetScreen(); 01651 } 01652 } 01653 01654 uint32_t GFX_Rmask; 01655 unsigned char GFX_Rshift; 01656 uint32_t GFX_Gmask; 01657 unsigned char GFX_Gshift; 01658 uint32_t GFX_Bmask; 01659 unsigned char GFX_Bshift; 01660 uint32_t GFX_Amask; 01661 unsigned char GFX_Ashift; 01662 unsigned char GFX_bpp; 01663 01664 unsigned int GFX_GetBShift() { 01665 return sdl.surface->format->Bshift; 01666 } 01667 01668 void GFX_LogSDLState(void) 01669 { 01670 LOG(LOG_MISC,LOG_DEBUG)("SDL video mode: %ux%u (clip %ux%u with upper-left at %ux%u) %ubpp", 01671 (unsigned)sdl.surface->w,(unsigned)sdl.surface->h, 01672 (unsigned)sdl.clip.w,(unsigned)sdl.clip.h, 01673 (unsigned)sdl.clip.x,(unsigned)sdl.clip.y, 01674 (unsigned)sdl.surface->format->BitsPerPixel); 01675 LOG(LOG_MISC,LOG_DEBUG)(" red: shift=%u mask=0x%08lx", 01676 (unsigned)sdl.surface->format->Rshift, 01677 (unsigned long)sdl.surface->format->Rmask); 01678 LOG(LOG_MISC,LOG_DEBUG)(" green: shift=%u mask=0x%08lx", 01679 (unsigned)sdl.surface->format->Gshift, 01680 (unsigned long)sdl.surface->format->Gmask); 01681 LOG(LOG_MISC,LOG_DEBUG)(" blue: shift=%u mask=0x%08lx", 01682 (unsigned)sdl.surface->format->Bshift, 01683 (unsigned long)sdl.surface->format->Bmask); 01684 LOG(LOG_MISC,LOG_DEBUG)(" alpha: shift=%u mask=0x%08lx", 01685 (unsigned)sdl.surface->format->Ashift, 01686 (unsigned long)sdl.surface->format->Amask); 01687 01688 GFX_bpp = sdl.surface->format->BitsPerPixel; 01689 GFX_Rmask = sdl.surface->format->Rmask; 01690 GFX_Rshift = sdl.surface->format->Rshift; 01691 GFX_Gmask = sdl.surface->format->Gmask; 01692 GFX_Gshift = sdl.surface->format->Gshift; 01693 GFX_Bmask = sdl.surface->format->Bmask; 01694 GFX_Bshift = sdl.surface->format->Bshift; 01695 GFX_Amask = sdl.surface->format->Amask; 01696 GFX_Ashift = sdl.surface->format->Ashift; 01697 } 01698 01699 void GFX_TearDown(void) { 01700 if (sdl.updating) 01701 GFX_EndUpdate( 0 ); 01702 01703 if (sdl.blit.surface) { 01704 SDL_FreeSurface(sdl.blit.surface); 01705 sdl.blit.surface=0; 01706 } 01707 } 01708 01709 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 01710 void MenuShadeRect(int x,int y,int w,int h) { 01711 if (OpenGL_using()) { 01712 #if C_OPENGL 01713 glShadeModel (GL_FLAT); 01714 glBlendFunc(GL_ONE, GL_SRC_ALPHA); 01715 glDisable (GL_DEPTH_TEST); 01716 glDisable (GL_LIGHTING); 01717 glEnable(GL_BLEND); 01718 glDisable(GL_CULL_FACE); 01719 glDisable(GL_ALPHA_TEST); 01720 glDisable(GL_FOG); 01721 glDisable(GL_SCISSOR_TEST); 01722 glDisable(GL_STENCIL_TEST); 01723 glDisable(GL_TEXTURE_2D); 01724 01725 glColor4ub(0, 0, 0, 64); 01726 glBegin(GL_QUADS); 01727 glVertex2i(x ,y ); 01728 glVertex2i(x+w,y ); 01729 glVertex2i(x+w,y+h); 01730 glVertex2i(x ,y+h); 01731 glEnd(); 01732 01733 glBlendFunc(GL_ONE, GL_ZERO); 01734 glEnable(GL_TEXTURE_2D); 01735 #endif 01736 } 01737 else { 01738 if (x < 0) { 01739 w += x; 01740 x = 0; 01741 } 01742 if (y < 0) { 01743 h += y; 01744 y = 0; 01745 } 01746 if ((x+w) > sdl.surface->w) 01747 w = sdl.surface->w - x; 01748 if ((y+h) > sdl.surface->h) 01749 h = sdl.surface->h - y; 01750 if (w <= 0 || h <= 0) 01751 return; 01752 01753 if (sdl.surface->format->BitsPerPixel == 32) { 01754 unsigned char *scan; 01755 uint32_t mask; 01756 01757 mask = ((sdl.surface->format->Rmask >> 2) & sdl.surface->format->Rmask) | 01758 ((sdl.surface->format->Gmask >> 2) & sdl.surface->format->Gmask) | 01759 ((sdl.surface->format->Bmask >> 2) & sdl.surface->format->Bmask); 01760 01761 assert(sdl.surface->pixels != NULL); 01762 01763 scan = (unsigned char*)sdl.surface->pixels; 01764 scan += y * sdl.surface->pitch; 01765 scan += x * 4; 01766 while (h-- > 0) { 01767 uint32_t *row = (uint32_t*)scan; 01768 scan += sdl.surface->pitch; 01769 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (row[c] >> 2) & mask; 01770 } 01771 } 01772 else if (sdl.surface->format->BitsPerPixel == 16) { 01773 unsigned char *scan; 01774 uint16_t mask; 01775 01776 mask = ((sdl.surface->format->Rmask >> 2) & sdl.surface->format->Rmask) | 01777 ((sdl.surface->format->Gmask >> 2) & sdl.surface->format->Gmask) | 01778 ((sdl.surface->format->Bmask >> 2) & sdl.surface->format->Bmask); 01779 01780 assert(sdl.surface->pixels != NULL); 01781 01782 scan = (unsigned char*)sdl.surface->pixels; 01783 scan += y * sdl.surface->pitch; 01784 scan += x * 2; 01785 while (h-- > 0) { 01786 uint16_t *row = (uint16_t*)scan; 01787 scan += sdl.surface->pitch; 01788 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (row[c] >> 2) & mask; 01789 } 01790 } 01791 else { 01792 /* TODO */ 01793 } 01794 } 01795 } 01796 01797 void MenuDrawRect(int x,int y,int w,int h,Bitu color) { 01798 if (OpenGL_using()) { 01799 #if C_OPENGL 01800 glShadeModel (GL_FLAT); 01801 glBlendFunc(GL_ONE, GL_ZERO); 01802 glDisable (GL_DEPTH_TEST); 01803 glDisable (GL_LIGHTING); 01804 glDisable(GL_BLEND); 01805 glDisable(GL_CULL_FACE); 01806 glDisable(GL_ALPHA_TEST); 01807 glDisable(GL_FOG); 01808 glDisable(GL_SCISSOR_TEST); 01809 glDisable(GL_STENCIL_TEST); 01810 glDisable(GL_TEXTURE_2D); 01811 01812 glColor3ub((color >> 16UL) & 0xFF,(color >> 8UL) & 0xFF,(color >> 0UL) & 0xFF); 01813 glBegin(GL_QUADS); 01814 glVertex2i(x ,y ); 01815 glVertex2i(x+w,y ); 01816 glVertex2i(x+w,y+h); 01817 glVertex2i(x ,y+h); 01818 glEnd(); 01819 01820 glBlendFunc(GL_ONE, GL_ZERO); 01821 glEnable(GL_TEXTURE_2D); 01822 #endif 01823 } 01824 else { 01825 if (x < 0) { 01826 w += x; 01827 x = 0; 01828 } 01829 if (y < 0) { 01830 h += y; 01831 y = 0; 01832 } 01833 if ((x+w) > sdl.surface->w) 01834 w = sdl.surface->w - x; 01835 if ((y+h) > sdl.surface->h) 01836 h = sdl.surface->h - y; 01837 if (w <= 0 || h <= 0) 01838 return; 01839 01840 if (sdl.surface->format->BitsPerPixel == 32) { 01841 unsigned char *scan; 01842 01843 assert(sdl.surface->pixels != NULL); 01844 01845 scan = (unsigned char*)sdl.surface->pixels; 01846 scan += y * sdl.surface->pitch; 01847 scan += x * 4; 01848 while (h-- > 0) { 01849 uint32_t *row = (uint32_t*)scan; 01850 scan += sdl.surface->pitch; 01851 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (uint32_t)color; 01852 } 01853 } 01854 else if (sdl.surface->format->BitsPerPixel == 16) { 01855 unsigned char *scan; 01856 01857 assert(sdl.surface->pixels != NULL); 01858 01859 scan = (unsigned char*)sdl.surface->pixels; 01860 scan += y * sdl.surface->pitch; 01861 scan += x * 2; 01862 while (h-- > 0) { 01863 uint16_t *row = (uint16_t*)scan; 01864 scan += sdl.surface->pitch; 01865 for (unsigned int c=0;c < (unsigned int)w;c++) row[c] = (uint16_t)color; 01866 } 01867 } 01868 else { 01869 /* TODO */ 01870 } 01871 } 01872 } 01873 01874 extern Bit8u int10_font_14[256 * 14]; 01875 extern Bit8u int10_font_16[256 * 16]; 01876 01877 void MenuDrawTextChar(int x,int y,unsigned char c,Bitu color) { 01878 static const unsigned int fontHeight = 16; 01879 01880 if (x < 0 || y < 0 || 01881 (unsigned int)(x+8) > (unsigned int)sdl.surface->w || 01882 (unsigned int)(y+(int)fontHeight) > (unsigned int)sdl.surface->h) 01883 return; 01884 01885 unsigned char *bmp = (unsigned char*)int10_font_16 + (c * fontHeight); 01886 01887 if (OpenGL_using()) { 01888 #if C_OPENGL 01889 unsigned int tx = (c % 16u) * 8u; 01890 unsigned int ty = (c / 16u) * 16u; 01891 01892 /* MenuDrawText() has prepared OpenGL state for us */ 01893 glBegin(GL_QUADS); 01894 // lower left 01895 glTexCoord2i((int)tx+0, (int)ty ); glVertex2i((int)x, (int)y ); 01896 // lower right 01897 glTexCoord2i((int)tx+8, (int)ty ); glVertex2i((int)x+8,(int)y ); 01898 // upper right 01899 glTexCoord2i((int)tx+8, (int)ty+(int)fontHeight); glVertex2i((int)x+8,(int)y+(int)fontHeight); 01900 // upper left 01901 glTexCoord2i((int)tx+0, (int)ty+(int)fontHeight); glVertex2i((int)x, (int)y+(int)fontHeight); 01902 glEnd(); 01903 #endif 01904 } 01905 else { 01906 unsigned char *scan; 01907 01908 assert(sdl.surface->pixels != NULL); 01909 01910 if (x < 0 || y < 0) 01911 return; 01912 if ((x + 8) > sdl.surface->w) 01913 return; 01914 if ((y + (int)fontHeight) > sdl.surface->h) 01915 return; 01916 01917 scan = (unsigned char*)sdl.surface->pixels; 01918 scan += (unsigned int)y * (unsigned int)sdl.surface->pitch; 01919 scan += (unsigned int)x * (((unsigned int)sdl.surface->format->BitsPerPixel+7u)/8u); 01920 01921 for (unsigned int row=0;row < fontHeight;row++) { 01922 unsigned char rb = bmp[row]; 01923 01924 if (sdl.surface->format->BitsPerPixel == 32) { 01925 uint32_t *dp = (uint32_t*)scan; 01926 for (unsigned int colm=0x80;colm != 0;colm >>= 1) { 01927 if (rb & colm) *dp = (uint32_t)color; 01928 dp++; 01929 } 01930 } 01931 else if (sdl.surface->format->BitsPerPixel == 16) { 01932 uint16_t *dp = (uint16_t*)scan; 01933 for (unsigned int colm=0x80;colm != 0;colm >>= 1) { 01934 if (rb & colm) *dp = (uint16_t)color; 01935 dp++; 01936 } 01937 } 01938 01939 scan += (size_t)sdl.surface->pitch; 01940 } 01941 } 01942 } 01943 01944 void MenuDrawTextChar2x(int x,int y,unsigned char c,Bitu color) { 01945 static const unsigned int fontHeight = 16; 01946 01947 if (x < 0 || y < 0 || 01948 (unsigned int)(x+8) > (unsigned int)sdl.surface->w || 01949 (unsigned int)(y+(int)fontHeight) > (unsigned int)sdl.surface->h) 01950 return; 01951 01952 unsigned char *bmp = (unsigned char*)int10_font_16 + (c * fontHeight); 01953 01954 if (OpenGL_using()) { 01955 #if C_OPENGL 01956 unsigned int tx = (c % 16u) * 8u; 01957 unsigned int ty = (c / 16u) * 16u; 01958 01959 /* MenuDrawText() has prepared OpenGL state for us */ 01960 glBegin(GL_QUADS); 01961 // lower left 01962 glTexCoord2i((int)tx+0, (int)ty ); glVertex2i(x, y ); 01963 // lower right 01964 glTexCoord2i((int)tx+8, (int)ty ); glVertex2i(x+(8*2),y ); 01965 // upper right 01966 glTexCoord2i((int)tx+8, (int)ty+(int)fontHeight); glVertex2i(x+(8*2),y+((int)fontHeight*2)); 01967 // upper left 01968 glTexCoord2i((int)tx+0, (int)ty+(int)fontHeight); glVertex2i(x, y+((int)fontHeight*2)); 01969 glEnd(); 01970 #endif 01971 } 01972 else { 01973 unsigned char *scan; 01974 01975 assert(sdl.surface->pixels != NULL); 01976 01977 if (x < 0 || y < 0) 01978 return; 01979 if ((x + 16) > sdl.surface->w) 01980 return; 01981 if ((y + ((int)fontHeight * 2)) > sdl.surface->h) 01982 return; 01983 01984 scan = (unsigned char*)sdl.surface->pixels; 01985 scan += y * sdl.surface->pitch; 01986 scan += x * ((sdl.surface->format->BitsPerPixel+7)/8); 01987 01988 for (unsigned int row=0;row < (fontHeight*2);row++) { 01989 unsigned char rb = bmp[row>>1U]; 01990 01991 if (sdl.surface->format->BitsPerPixel == 32) { 01992 uint32_t *dp = (uint32_t*)scan; 01993 for (unsigned int colm=0x80;colm != 0;colm >>= 1) { 01994 if (rb & colm) { 01995 *dp++ = (uint32_t)color; 01996 *dp++ = (uint32_t)color; 01997 } 01998 else { 01999 dp += 2; 02000 } 02001 } 02002 } 02003 else if (sdl.surface->format->BitsPerPixel == 16) { 02004 uint16_t *dp = (uint16_t*)scan; 02005 for (unsigned int colm=0x80;colm != 0;colm >>= 1) { 02006 if (rb & colm) { 02007 *dp++ = (uint16_t)color; 02008 *dp++ = (uint16_t)color; 02009 } 02010 else { 02011 dp += 2; 02012 } 02013 } 02014 } 02015 02016 scan += sdl.surface->pitch; 02017 } 02018 } 02019 } 02020 02021 void MenuDrawText(int x,int y,const char *text,Bitu color) { 02022 #if C_OPENGL 02023 if (OpenGL_using()) { 02024 glBindTexture(GL_TEXTURE_2D,SDLDrawGenFontTexture); 02025 02026 glPushMatrix(); 02027 02028 glMatrixMode (GL_TEXTURE); 02029 glLoadIdentity (); 02030 glScaled(1.0 / SDLDrawGenFontTextureWidth, 1.0 / SDLDrawGenFontTextureHeight, 1.0); 02031 02032 glColor4ub((color >> 16UL) & 0xFF,(color >> 8UL) & 0xFF,(color >> 0UL) & 0xFF,0xFF); 02033 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 02034 02035 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 02036 glEnable(GL_TEXTURE_2D); 02037 glEnable(GL_ALPHA_TEST); 02038 glEnable(GL_BLEND); 02039 } 02040 #endif 02041 02042 while (*text != 0) { 02043 if (mainMenu.fontCharScale >= 2) 02044 MenuDrawTextChar2x(x,y,(unsigned char)(*text++),color); 02045 else 02046 MenuDrawTextChar(x,y,(unsigned char)(*text++),color); 02047 02048 x += (int)mainMenu.fontCharWidth; 02049 } 02050 02051 #if C_OPENGL 02052 if (OpenGL_using()) { 02053 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 02054 glBlendFunc(GL_ONE, GL_ZERO); 02055 glDisable(GL_ALPHA_TEST); 02056 glEnable(GL_TEXTURE_2D); 02057 02058 glPopMatrix(); 02059 02060 glBindTexture(GL_TEXTURE_2D,sdl_opengl.texture); 02061 } 02062 #endif 02063 } 02064 02065 void DOSBoxMenu::item::drawMenuItem(DOSBoxMenu &menu) { 02066 (void)menu;//UNUSED 02067 02068 Bitu bgcolor = GFX_GetRGB(63, 63, 63); 02069 Bitu fgcolor = GFX_GetRGB(191, 191, 191); 02070 Bitu fgshortcolor = GFX_GetRGB(127, 127, 191); 02071 Bitu fgcheckcolor = GFX_GetRGB(191, 191, 127); 02072 02073 if (type >= separator_type_id) { 02074 /* separators never change visual state on hover/select */ 02075 } 02076 else if (!status.enabled) { 02077 if (itemHover) 02078 bgcolor = GFX_GetRGB(79, 79, 79); 02079 02080 fgcolor = GFX_GetRGB(144, 144, 144); 02081 fgshortcolor = GFX_GetRGB(63, 63, 144); 02082 fgcheckcolor = GFX_GetRGB(144, 144, 63); 02083 } 02084 else if (itemHilight) { 02085 bgcolor = GFX_GetRGB(0, 0, 63); 02086 fgcolor = GFX_GetRGB(255, 255, 255); 02087 fgshortcolor = GFX_GetRGB(191, 191, 255); 02088 } 02089 else if (itemHover) { 02090 bgcolor = GFX_GetRGB(127, 127, 127); 02091 fgcolor = GFX_GetRGB(255, 255, 255); 02092 fgshortcolor = GFX_GetRGB(191, 191, 255); 02093 } 02094 02095 itemHoverDrawn = itemHover; 02096 itemHilightDrawn = itemHilight; 02097 02098 if (SDL_MUSTLOCK(sdl.surface)) 02099 SDL_LockSurface(sdl.surface); 02100 02101 MenuDrawRect(screenBox.x, screenBox.y, screenBox.w, screenBox.h, bgcolor); 02102 if (checkBox.w != 0 && checkBox.h != 0) { 02103 const char *str = status.checked ? "\xFB" : " "; 02104 02105 MenuDrawText(screenBox.x+checkBox.x, screenBox.y+checkBox.y, str, fgcheckcolor); 02106 } 02107 if (textBox.w != 0 && textBox.h != 0) 02108 MenuDrawText(screenBox.x+textBox.x, screenBox.y+textBox.y, text.c_str(), fgcolor); 02109 if (shortBox.w != 0 && shortBox.h != 0) 02110 MenuDrawText(screenBox.x+shortBox.x, screenBox.y+shortBox.y, shortcut_text.c_str(), fgshortcolor); 02111 02112 if (type == submenu_type_id && borderTop/*not toplevel*/) 02113 MenuDrawText((int)((int)screenBox.x+(int)screenBox.w - (int)mainMenu.fontCharWidth - 1), (int)((int)screenBox.y+(int)textBox.y), "\x10", fgcheckcolor); 02114 02115 if (type == separator_type_id) 02116 MenuDrawRect((int)screenBox.x, (int)screenBox.y + ((int)screenBox.h/2), (int)screenBox.w, 1, fgcolor); 02117 else if (type == vseparator_type_id) 02118 MenuDrawRect((int)screenBox.x + ((int)screenBox.w/2), (int)screenBox.y, 1, (int)screenBox.h, fgcolor); 02119 02120 if (SDL_MUSTLOCK(sdl.surface)) 02121 SDL_UnlockSurface(sdl.surface); 02122 } 02123 02124 void DOSBoxMenu::displaylist::DrawDisplayList(DOSBoxMenu &menu,bool updateScreen) { 02125 for (auto &id : disp_list) { 02126 DOSBoxMenu::item &item = menu.get_item(id); 02127 02128 item.drawMenuItem(menu); 02129 if (updateScreen) item.updateScreenFromItem(menu); 02130 } 02131 } 02132 02133 bool DOSBox_isMenuVisible(void); 02134 02135 void GFX_DrawSDLMenu(DOSBoxMenu &menu, DOSBoxMenu::displaylist &dl) { 02136 if (!menu.needsRedraw() || (sdl.updating && !OpenGL_using())) { 02137 return; 02138 } 02139 if (!DOSBox_isMenuVisible() || sdl.desktop.fullscreen) { 02140 // BUGFIX: If the menu is hidden then silently clear "needs redraw" to avoid excess redraw of nothing 02141 menu.clearRedraw(); 02142 return; 02143 } 02144 02145 bool mustLock = !OpenGL_using() && SDL_MUSTLOCK(sdl.surface); 02146 02147 if (mustLock) { 02148 SDL_LockSurface(sdl.surface); 02149 } 02150 02151 if (&dl == &menu.display_list) { /* top level menu, draw background */ 02152 MenuDrawRect(menu.menuBox.x, menu.menuBox.y, menu.menuBox.w, menu.menuBox.h - 1, GFX_GetRGB(63, 63, 63)); 02153 MenuDrawRect(menu.menuBox.x, menu.menuBox.y + menu.menuBox.h - 1, menu.menuBox.w, 1, 02154 GFX_GetRGB(31, 31, 31)); 02155 } 02156 02157 if (mustLock) { 02158 SDL_UnlockSurface(sdl.surface); 02159 } 02160 02161 #if 0 02162 LOG_MSG("menudraw %u",(unsigned int)SDL_GetTicks()); 02163 #endif 02164 02165 menu.clearRedraw(); 02166 menu.display_list.DrawDisplayList(menu,/*updateScreen*/false); 02167 02168 if (!OpenGL_using()) { 02169 #if defined(C_SDL2) 02170 SDL_UpdateWindowSurfaceRects( sdl.window, &menu.menuBox, 1 ); 02171 #else 02172 SDL_UpdateRects(sdl.surface, 1, &menu.menuBox); 02173 #endif 02174 } 02175 } 02176 #endif 02177 02178 void RENDER_Reset(void); 02179 02180 Bitu GFX_SetSize(Bitu width, Bitu height, Bitu flags, double scalex, double scaley, GFX_CallBack_t callback) 02181 { 02182 if (width == 0 || height == 0) { 02183 E_Exit("GFX_SetSize with width=%d height=%d zero dimensions not allowed",(int)width,(int)height); 02184 return 0; 02185 } 02186 02187 if (sdl.updating) 02188 GFX_EndUpdate( 0 ); 02189 02190 sdl.must_redraw_all = true; 02191 02192 sdl.draw.width = (Bit32u)width; 02193 sdl.draw.height = (Bit32u)height; 02194 sdl.draw.flags = flags; 02195 sdl.draw.callback = callback; 02196 sdl.draw.scalex = scalex; 02197 sdl.draw.scaley = scaley; 02198 02199 LOG(LOG_MISC,LOG_DEBUG)("GFX_SetSize %ux%u flags=0x%x scale=%.3fx%.3f", 02200 (unsigned int)width,(unsigned int)height, 02201 (unsigned int)flags, 02202 scalex,scaley); 02203 02204 // Bitu bpp = 0; 02205 Bitu retFlags = 0; 02206 02207 if (sdl.blit.surface) { 02208 SDL_FreeSurface(sdl.blit.surface); 02209 sdl.blit.surface=0; 02210 } 02211 02212 switch (sdl.desktop.want_type) { 02213 case SCREEN_SURFACE: 02214 retFlags = OUTPUT_SURFACE_SetSize(); 02215 break; 02216 02217 #if C_OPENGL 02218 case SCREEN_OPENGL: 02219 retFlags = OUTPUT_OPENGL_SetSize(); 02220 break; 02221 #endif 02222 02223 #if C_DIRECT3D 02224 case SCREEN_DIRECT3D: 02225 retFlags = OUTPUT_DIRECT3D_SetSize(); 02226 break; 02227 #endif 02228 02229 default: 02230 // we should never reach here 02231 retFlags = 0; 02232 break; 02233 } 02234 02235 if (!retFlags) 02236 { 02237 if (sdl.desktop.want_type != SCREEN_SURFACE) 02238 { 02239 // try falling back down to surface 02240 OUTPUT_SURFACE_Select(); 02241 retFlags = OUTPUT_SURFACE_SetSize(); 02242 } 02243 if (retFlags == 0) 02244 LOG_MSG("SDL:Failed everything including falling back to surface in GFX_GetSize"); // completely failed it seems 02245 } 02246 02247 // we have selected an actual desktop type 02248 sdl.desktop.type = sdl.desktop.want_type; 02249 02250 GFX_LogSDLState(); 02251 02252 if (retFlags) 02253 GFX_Start(); 02254 02255 if (!sdl.mouse.autoenable && !sdl.mouse.locked) 02256 SDL_ShowCursor(sdl.mouse.autolock?SDL_DISABLE:SDL_ENABLE); 02257 02258 UpdateWindowDimensions(); 02259 02260 #if defined(WIN32) && !defined(HX_DOS) 02261 WindowsTaskbarUpdatePreviewRegion(); 02262 #endif 02263 02264 return retFlags; 02265 } 02266 02267 #if defined(WIN32) && !defined(HX_DOS) 02268 // WARNING: Not recommended, there is danger you cannot exit emulator because mouse+keyboard are taken 02269 static bool enable_hook_everything = false; 02270 #endif 02271 02272 // Whether or not to hook the keyboard and block special keys. 02273 // Setting this is recommended so that your keyboard is fully usable in the guest OS when you 02274 // enable the mouse+keyboard capture. But hooking EVERYTHING is not recommended because there is a 02275 // danger you become trapped in the DOSBox-X emulator! 02276 static bool enable_hook_special_keys = true; 02277 02278 #if defined(WIN32) && !defined(HX_DOS) 02279 // Whether or not to hook Num/Scroll/Caps lock in order to give the guest OS full control of the 02280 // LEDs on the keyboard (i.e. the LEDs do not change until the guest OS changes their state). 02281 // This flag also enables code to set the LEDs to guest state when setting mouse+keyboard capture, 02282 // and restoring LED state when releasing capture. 02283 static bool enable_hook_lock_toggle_keys = true; 02284 #endif 02285 02286 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 02287 // and this is where we store host LED state when capture is set. 02288 static bool on_capture_num_lock_was_on = true; // reasonable guess 02289 static bool on_capture_scroll_lock_was_on = false; 02290 static bool on_capture_caps_lock_was_on = false; 02291 #endif 02292 02293 static bool exthook_enabled = false; 02294 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 02295 static HHOOK exthook_winhook = NULL; 02296 02297 #if !defined(__MINGW32__) 02298 extern "C" void SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(unsigned char x); 02299 #endif 02300 02301 static LRESULT CALLBACK WinExtHookKeyboardHookProc(int nCode,WPARAM wParam,LPARAM lParam) { 02302 if (nCode == HC_ACTION) { 02303 HWND myHwnd = GetHWND(); 02304 02305 if (exthook_enabled && GetFocus() == myHwnd) { /* intercept only if DOSBox-X is the focus and the keyboard is hooked */ 02306 if (wParam == WM_SYSKEYDOWN || wParam == WM_KEYDOWN || wParam == WM_SYSKEYUP || wParam == WM_KEYUP) { 02307 KBDLLHOOKSTRUCT *st_hook = (KBDLLHOOKSTRUCT*)lParam; 02308 02309 if (st_hook->flags & LLKHF_INJECTED) { 02310 // injected keys are automatically allowed, especially if we are injecting keyboard input into ourself 02311 // to control Num/Scroll/Caps Lock LEDs. If we don't check this we cannot control the LEDs. Injecting 02312 // keydown/keyup for Num Lock is the only means provided by Windows to control those LEDs. 02313 } 02314 else if (st_hook->vkCode == VK_MENU/*alt*/ || st_hook->vkCode == VK_CONTROL || 02315 st_hook->vkCode == VK_LSHIFT || st_hook->vkCode == VK_RSHIFT) { 02316 // always allow modifier keys through, so other applications are not left with state inconsistent from 02317 // actual keyboard state. 02318 } 02319 else { 02320 bool nopass = enable_hook_everything; // if the user wants us to hook ALL keys then that's where this signals it 02321 bool alternate_message = false; // send as WM_USER+0x100 instead of WM_KEYDOWN 02322 02323 if (!nopass) { 02324 // hook only certain keys Windows is likely to act on by itself. 02325 02326 // FIXME: Hooking the keyboard does NOT prevent Fn+SPACE (zoom) from triggering screen resolution 02327 // changes in Windows 10! How do we stop that? 02328 02329 // FIXME: It might be nice to let the user decide whether or not Print Screen is intercepted. 02330 02331 // TODO: We do not hook the volume up/down/mute keys. This is to be kind to the user. They may 02332 // appreciate the ability to dial down the volume if a loud DOS program comes up. But 02333 // if the user WANTS us to, we should allow hooking those keys. 02334 02335 // TODO: Allow (if instructed) hooking the VK_SLEEP key so pushing the sleep key (the 02336 // one with the icon of the moon on Microsoft keyboards) can be sent instead to the 02337 // guest OS. Also add code where if we're not hooking the key, then we should listen 02338 // for signals the guest OS is suspending or hibernating and auto-disconnect the 02339 // mouse capture and keyboard hook. 02340 02341 switch (st_hook->vkCode) { 02342 case VK_LWIN: // left Windows key (normally triggers Start menu) 02343 case VK_RWIN: // right Windows key (normally triggers Start menu) 02344 case VK_APPS: // Application key (normally open to the user, but just in case) 02345 case VK_PAUSE: // pause key 02346 case VK_SNAPSHOT: // print screen 02347 case VK_TAB: // try to catch ALT+TAB too (not blocking VK_TAB will allow host OS to switch tasks) 02348 case VK_ESCAPE: // try to catch CTRL+ESC as well (so Windows 95 Start Menu is accessible) 02349 case VK_SPACE: // and space (catching VK_ZOOM isn't enough to prevent Windows 10 from changing res) 02350 // these keys have no meaning to DOSBox-X and so we hook them by default to allow the guest OS to use them 02351 case VK_BROWSER_BACK: // Browser Back key 02352 case VK_BROWSER_FORWARD: // Browser Forward key 02353 case VK_BROWSER_REFRESH: // Browser Refresh key 02354 case VK_BROWSER_STOP: // Browser Stop key 02355 case VK_BROWSER_SEARCH: // Browser Search key 02356 case VK_BROWSER_FAVORITES: // Browser Favorites key 02357 case VK_BROWSER_HOME: // Browser Start and Home key 02358 case VK_MEDIA_NEXT_TRACK: // Next Track key 02359 case VK_MEDIA_PREV_TRACK: // Previous Track key 02360 case VK_MEDIA_STOP: // Stop Media key 02361 case VK_MEDIA_PLAY_PAUSE: // Play / Pause Media key 02362 case VK_LAUNCH_MAIL: // Start Mail key 02363 case VK_LAUNCH_MEDIA_SELECT: // Select Media key 02364 case VK_LAUNCH_APP1: // Start Application 1 key 02365 case VK_LAUNCH_APP2: // Start Application 2 key 02366 case VK_PLAY: // Play key 02367 case VK_ZOOM: // Zoom key (the (+) magnifying glass keyboard shortcut laptops have these days on the spacebar?) 02368 nopass = true; 02369 break; 02370 02371 // IME Hiragana key, otherwise inaccessible to us 02372 case 0xF2: 02373 nopass = true; // FIXME: This doesn't (yet) cause a SDL key event. 02374 break; 02375 02376 // we allow hooking Num/Scroll/Caps Lock keys so that pressing them does not toggle the LED. 02377 // we then take Num/Scroll/Caps LED state from the guest and let THAT control the LED state. 02378 case VK_CAPITAL: 02379 case VK_NUMLOCK: 02380 case VK_SCROLL: 02381 nopass = enable_hook_lock_toggle_keys; 02382 alternate_message = true; 02383 break; 02384 } 02385 } 02386 02387 if (nopass) { 02388 // convert WM_KEYDOWN/WM_KEYUP if obfuscating the message to distinguish between real and injected events 02389 if (alternate_message) { 02390 if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) 02391 wParam = WM_USER + 0x100; 02392 else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) 02393 wParam = WM_USER + 0x101; 02394 } 02395 02396 DWORD lParam = 02397 (st_hook->scanCode << 8U) + 02398 ((st_hook->flags & LLKHF_EXTENDED) ? 0x01000000 : 0) + 02399 ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) ? 0xC0000000 : 0); 02400 02401 // catch the keystroke, post it to ourself, do not pass it on 02402 PostMessage(myHwnd, (UINT)wParam, st_hook->vkCode, lParam); 02403 return TRUE; 02404 } 02405 } 02406 } 02407 } 02408 } 02409 02410 return CallNextHookEx(exthook_winhook, nCode, wParam, lParam); 02411 } 02412 02413 // Microsoft doesn't have an outright "set toggle key state" call, they expect you 02414 // to know the state and then fake input to toggle. Blegh. Fine. 02415 void WinSetKeyToggleState(unsigned int vkCode, bool state) { 02416 bool curState = (GetKeyState(vkCode) & 1) ? true : false; 02417 INPUT inps; 02418 02419 // if we're already in that state, then there is nothing to do. 02420 if (curState == state) return; 02421 02422 // fake keyboard input. 02423 memset(&inps, 0, sizeof(inps)); 02424 inps.type = INPUT_KEYBOARD; 02425 inps.ki.wVk = vkCode; 02426 inps.ki.dwFlags = KEYEVENTF_EXTENDEDKEY; // pressed, use wVk. 02427 SendInput(1, &inps, sizeof(INPUT)); 02428 02429 memset(&inps, 0, sizeof(inps)); 02430 inps.type = INPUT_KEYBOARD; 02431 inps.ki.wVk = vkCode; 02432 inps.ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; // release, use wVk. 02433 SendInput(1, &inps, sizeof(INPUT)); 02434 } 02435 #endif 02436 02437 Bitu Keyboard_Guest_LED_State(); 02438 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */); 02439 02440 void UpdateKeyboardLEDState(Bitu led_state/* in the same bitfield arrangement as using command 0xED on PS/2 keyboards */) { 02441 (void)led_state;//POSSIBLY UNUSED 02442 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) /* Microsoft Windows */ 02443 if (exthook_enabled) { // ONLY if ext hook is enabled, else we risk infinite loops with keyboard events 02444 //WinSetKeyToggleState(VK_NUMLOCK, !!(led_state & 2)); 02445 //WinSetKeyToggleState(VK_SCROLL, !!(led_state & 1)); 02446 //WinSetKeyToggleState(VK_CAPITAL, !!(led_state & 4)); 02447 } 02448 #endif 02449 } 02450 02451 void DoExtendedKeyboardHook(bool enable) { 02452 if (exthook_enabled == enable) 02453 return; 02454 02455 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 02456 if (enable) { 02457 if (!exthook_winhook) { 02458 exthook_winhook = SetWindowsHookEx(WH_KEYBOARD_LL, WinExtHookKeyboardHookProc, GetModuleHandle(NULL), 0); 02459 if (exthook_winhook == NULL) return; 02460 } 02461 02462 // it's on 02463 exthook_enabled = enable; 02464 02465 // flush out and handle pending keyboard I/O 02466 { 02467 MSG msg; 02468 02469 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 02470 TranslateMessage(&msg); 02471 DispatchMessage(&msg); 02472 } 02473 } 02474 02475 #if !defined(__MINGW32__) 02476 // Enable the SDL hack for Win32 to handle Num/Scroll/Caps 02477 SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(1); 02478 #endif 02479 02480 // if hooking Num/Scroll/Caps Lock then record the toggle state of those keys. 02481 // then read from the keyboard emulation the LED state set by the guest and apply it to the host keyboard. 02482 if (enable_hook_lock_toggle_keys) { 02483 // record state 02484 on_capture_num_lock_was_on = (GetKeyState(VK_NUMLOCK) & 1) ? true : false; 02485 on_capture_scroll_lock_was_on = (GetKeyState(VK_SCROLL) & 1) ? true : false; 02486 on_capture_caps_lock_was_on = (GetKeyState(VK_CAPITAL) & 1) ? true : false; 02487 // change to guest state (FIXME: Read emulated keyboard state and apply!) 02488 UpdateKeyboardLEDState(Keyboard_Guest_LED_State()); 02489 } 02490 } 02491 else { 02492 if (exthook_winhook) { 02493 if (enable_hook_lock_toggle_keys) { 02494 // restore state 02495 //WinSetKeyToggleState(VK_NUMLOCK, on_capture_num_lock_was_on); 02496 //WinSetKeyToggleState(VK_SCROLL, on_capture_scroll_lock_was_on); 02497 //WinSetKeyToggleState(VK_CAPITAL, on_capture_caps_lock_was_on); 02498 } 02499 02500 { 02501 MSG msg; 02502 02503 // before we disable the SDL hack make sure we flush out and handle any pending keyboard events. 02504 // if we don't do this the posted Num/Scroll/Caps events will stay in the queue and will be handled 02505 // by SDL after turning off the toggle key hack. 02506 Sleep(1); // make sure Windows posts the keystrokes 02507 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { 02508 TranslateMessage(&msg); 02509 DispatchMessage(&msg); 02510 } 02511 } 02512 02513 #if !defined(__MINGW32__) 02514 // Disable the SDL hack for Win32 to handle Num/Scroll/Caps 02515 SDL_DOSBox_X_Hack_Set_Toggle_Key_WM_USER_Hack(0); 02516 #endif 02517 02518 UnhookWindowsHookEx(exthook_winhook); 02519 exthook_winhook = NULL; 02520 } 02521 02522 exthook_enabled = enable; 02523 } 02524 #endif 02525 } 02526 02527 void GFX_ReleaseMouse(void) { 02528 if (sdl.mouse.locked) 02529 GFX_CaptureMouse(); 02530 } 02531 02532 void GFX_CaptureMouse(void) { 02533 GFX_CaptureMouse(!sdl.mouse.locked); 02534 } 02535 02536 void GFX_CaptureMouse(bool capture) { 02537 sdl.mouse.locked=capture; 02538 if (sdl.mouse.locked) { 02539 #if defined(C_SDL2) 02540 SDL_SetRelativeMouseMode(SDL_TRUE); 02541 #else 02542 SDL_WM_GrabInput(SDL_GRAB_ON); 02543 #endif 02544 if (enable_hook_special_keys) DoExtendedKeyboardHook(true); 02545 SDL_ShowCursor(SDL_DISABLE); 02546 } else { 02547 DoExtendedKeyboardHook(false); 02548 #if defined(C_SDL2) 02549 SDL_SetRelativeMouseMode(SDL_FALSE); 02550 #else 02551 SDL_WM_GrabInput(SDL_GRAB_OFF); 02552 #endif 02553 if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); 02554 } 02555 mouselocked=sdl.mouse.locked; 02556 02557 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 02558 if (sdl.mouse.locked) { 02559 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 02560 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 02561 02562 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 02563 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 02564 } 02565 #endif 02566 02567 /* keep the menu updated (it might not exist yet) */ 02568 if (mainMenu.item_exists("mapper_capmouse")) 02569 mainMenu.get_item("mapper_capmouse").check(sdl.mouse.locked).refresh_item(mainMenu); 02570 } 02571 02572 void GFX_UpdateSDLCaptureState(void) { 02573 if (sdl.mouse.locked) { 02574 #if defined(C_SDL2) 02575 SDL_SetRelativeMouseMode(SDL_TRUE); 02576 #else 02577 SDL_WM_GrabInput(SDL_GRAB_ON); 02578 #endif 02579 if (enable_hook_special_keys) DoExtendedKeyboardHook(true); 02580 SDL_ShowCursor(SDL_DISABLE); 02581 } else { 02582 DoExtendedKeyboardHook(false); 02583 #if defined(C_SDL2) 02584 SDL_SetRelativeMouseMode(SDL_FALSE); 02585 #else 02586 SDL_WM_GrabInput(SDL_GRAB_OFF); 02587 #endif 02588 if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); 02589 } 02590 CPU_Reset_AutoAdjust(); 02591 GFX_SetTitle(-1,-1,-1,false); 02592 } 02593 02594 #if WIN32 02595 void CaptureMouseNotifyWin32(bool lck) 02596 { 02597 switch (sdl.mouse.autolock_feedback) 02598 { 02599 case AUTOLOCK_FEEDBACK_NONE: break; 02600 case AUTOLOCK_FEEDBACK_BEEP: 02601 { 02602 const auto lo = 1000; 02603 const auto hi = 2000; 02604 const auto t1 = 50; 02605 const auto t2 = 25; 02606 const auto f1 = lck ? hi : lo; 02607 const auto f2 = lck ? lo : hi; 02608 const auto tt = lck ? t1 : t2; 02609 Beep(f1, tt); 02610 Beep(f2, tt); 02611 } 02612 break; 02613 case AUTOLOCK_FEEDBACK_FLASH: 02614 { 02615 # if !defined(HX_DOS) 02616 const auto cnt = lck ? 4 : 2; 02617 const auto tim = lck ? 80 : 40; 02618 const auto wnd = GetHWND(); 02619 if (wnd != nullptr) 02620 { 02621 FLASHWINFO fi; 02622 fi.cbSize = sizeof(FLASHWINFO); 02623 fi.hwnd = wnd; 02624 fi.dwFlags = FLASHW_CAPTION; 02625 fi.uCount = cnt; 02626 fi.dwTimeout = tim; 02627 FlashWindowEx(&fi); 02628 } 02629 # endif 02630 break; 02631 } 02632 default: ; 02633 } 02634 } 02635 #endif 02636 02637 void CaptureMouseNotify() 02638 { 02639 CaptureMouseNotify(sdl.mouse.locked); 02640 } 02641 02642 void CaptureMouseNotify(bool capture) 02643 { 02644 #if WIN32 02645 CaptureMouseNotifyWin32(capture); 02646 #else 02647 (void)capture; 02648 // TODO 02649 #endif 02650 } 02651 02652 static void CaptureMouse(bool pressed) { 02653 if (!pressed) 02654 return; 02655 02656 CaptureMouseNotify(); 02657 GFX_CaptureMouse(); 02658 } 02659 02660 #if defined (WIN32) 02661 STICKYKEYS stick_keys = {sizeof(STICKYKEYS), 0}; 02662 void sticky_keys(bool restore){ 02663 static bool inited = false; 02664 if (!inited){ 02665 inited = true; 02666 SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0); 02667 } 02668 if (restore) { 02669 SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &stick_keys, 0); 02670 return; 02671 } 02672 //Get current sticky keys layout: 02673 STICKYKEYS s = {sizeof(STICKYKEYS), 0}; 02674 SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0); 02675 if ( !(s.dwFlags & SKF_STICKYKEYSON)) { //Not on already 02676 s.dwFlags &= ~SKF_HOTKEYACTIVE; 02677 SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &s, 0); 02678 } 02679 } 02680 #else 02681 #define sticky_keys(a) 02682 #endif 02683 02684 void GetDesktopResolution(int* width, int* height) 02685 { 02686 #ifdef WIN32 02687 RECT rDdesk; 02688 auto hDesk = GetDesktopWindow(); 02689 GetWindowRect(hDesk, &rDdesk); 02690 *width = rDdesk.right - rDdesk.left; 02691 *height = rDdesk.bottom - rDdesk.top; 02692 #elif defined(LINUX) 02693 void Linux_GetDesktopResolution(int *width,int *height); 02694 Linux_GetDesktopResolution(width,height); /* this is MESSY but there's too much namespace collision going on here */ 02695 #else 02696 *width = 1024; // guess 02697 *height = 768; 02698 #endif 02699 } 02700 02701 void res_init(void) { 02702 Section * sec = control->GetSection("sdl"); 02703 Section_prop * section=static_cast<Section_prop *>(sec); 02704 sdl.desktop.full.fixed=false; 02705 const char* fullresolution=section->Get_string("fullresolution"); 02706 sdl.desktop.full.width = 0; sdl.desktop.full.height = 0; 02707 if(fullresolution && *fullresolution) { 02708 char res[100]; 02709 safe_strncpy( res, fullresolution, sizeof( res )); 02710 fullresolution = lowcase (res);//so x and X are allowed 02711 if (strcmp(fullresolution,"original")) { 02712 sdl.desktop.full.fixed = true; 02713 if (strcmp(fullresolution,"desktop")) { //desktop = 0x0 02714 char* height = const_cast<char*>(strchr(fullresolution,'x')); 02715 if(height && * height) { 02716 *height = 0; 02717 sdl.desktop.full.height = atoi(height+1); 02718 sdl.desktop.full.width = atoi(res); 02719 } 02720 } 02721 } 02722 } 02723 02724 sdl.desktop.window.width = 0; 02725 sdl.desktop.window.height = 0; 02726 const char* windowresolution=section->Get_string("windowresolution"); 02727 if(windowresolution && *windowresolution) { 02728 //if(sdl.desktop.type==SCREEN_SURFACE) return; 02729 char res[100]; 02730 safe_strncpy( res,windowresolution, sizeof( res )); 02731 windowresolution = lowcase (res);//so x and X are allowed 02732 if(strcmp(windowresolution,"original")) { 02733 char* height = const_cast<char*>(strchr(windowresolution,'x')); 02734 if(height && *height) { 02735 *height = 0; 02736 sdl.desktop.window.height = (Bit16u)atoi(height+1); 02737 sdl.desktop.window.width = (Bit16u)atoi(res); 02738 } 02739 } 02740 } 02741 sdl.desktop.doublebuf=section->Get_bool("fulldouble"); 02742 02743 int width = 1024; 02744 int height = 768; 02745 02746 // fullresolution == desktop -> get/set desktop size 02747 auto sdlSection = control->GetSection("sdl"); 02748 auto sdlSectionProp = static_cast<Section_prop*>(sdlSection); 02749 auto fullRes = sdlSectionProp->Get_string("fullresolution"); 02750 if (!strcmp(fullRes, "desktop")) GetDesktopResolution(&width, &height); 02751 02752 if (!sdl.desktop.full.width) { 02753 sdl.desktop.full.width=width; 02754 } 02755 if (!sdl.desktop.full.height) { 02756 sdl.desktop.full.height=height; 02757 } 02758 if(sdl.desktop.type==SCREEN_SURFACE && !sdl.desktop.fullscreen) return; 02759 else { 02760 GFX_Stop(); 02761 if (sdl.draw.callback) 02762 (sdl.draw.callback)( GFX_CallBackReset ); 02763 GFX_Start(); 02764 } 02765 } 02766 02767 void res_input(bool type, const char * res) { 02768 Section* sec = control->GetSection("sdl"); 02769 02770 if(sec) { 02771 char win_res[11]; 02772 strcpy(win_res,res); 02773 if(type) { 02774 std::string tmp("windowresolution="); tmp.append(win_res); 02775 sec->HandleInputline(tmp); 02776 } else { 02777 std::string tmp("fullresolution="); tmp.append(win_res); 02778 sec->HandleInputline(tmp); 02779 } 02780 02781 res_init(); 02782 } 02783 } 02784 02785 void change_output(int output) { 02786 GFX_Stop(); 02787 Section * sec = control->GetSection("sdl"); 02788 Section_prop * section=static_cast<Section_prop *>(sec); 02789 sdl.overscan_width=(unsigned int)section->Get_int("overscan"); 02790 UpdateOverscanMenu(); 02791 02792 switch (output) { 02793 case 0: 02794 OUTPUT_SURFACE_Select(); 02795 break; 02796 case 1: 02797 OUTPUT_SURFACE_Select(); 02798 break; 02799 case 2: /* do nothing */ 02800 break; 02801 case 3: 02802 #if C_OPENGL 02803 change_output(2); 02804 OUTPUT_OPENGL_Select(); 02805 sdl_opengl.bilinear = true; 02806 #endif 02807 break; 02808 case 4: 02809 #if C_OPENGL 02810 change_output(2); 02811 OUTPUT_OPENGL_Select(); 02812 sdl_opengl.bilinear = false; //NB 02813 #endif 02814 break; 02815 #if C_DIRECT3D 02816 case 5: 02817 OUTPUT_DIRECT3D_Select(); 02818 break; 02819 #endif 02820 case 6: 02821 break; 02822 case 7: 02823 // do not set want_type 02824 break; 02825 case 8: 02826 #if C_DIRECT3D 02827 if (sdl.desktop.want_type == SCREEN_DIRECT3D) 02828 OUTPUT_DIRECT3D_Select(); 02829 #endif 02830 break; 02831 02832 default: 02833 LOG_MSG("SDL:Unsupported output device %d, switching back to surface",output); 02834 OUTPUT_SURFACE_Select(); 02835 break; 02836 } 02837 02838 const char* windowresolution=section->Get_string("windowresolution"); 02839 if (windowresolution && *windowresolution) 02840 { 02841 char res[100]; 02842 safe_strncpy( res,windowresolution, sizeof( res )); 02843 windowresolution = lowcase (res);//so x and X are allowed 02844 if (strcmp(windowresolution,"original")) 02845 { 02846 if (output == 0) 02847 { 02848 std::string tmp("windowresolution=original"); 02849 sec->HandleInputline(tmp); 02850 } 02851 } 02852 } 02853 res_init(); 02854 02855 if (sdl.draw.callback) 02856 (sdl.draw.callback)( GFX_CallBackReset ); 02857 02858 GFX_SetTitle((Bit32s)CPU_CycleMax,-1,-1,false); 02859 GFX_LogSDLState(); 02860 02861 UpdateWindowDimensions(); 02862 } 02863 02864 #if !defined(HX_DOS) && defined(SDL_DOSBOX_X_SPECIAL) 02865 extern "C" void SDL_hax_SetFSWindowPosition(int x,int y,int w,int h); 02866 #endif 02867 02868 void GFX_SwitchFullScreen(void) 02869 { 02870 #if !defined(HX_DOS) 02871 if (sdl.desktop.prevent_fullscreen) 02872 return; 02873 02874 if (!sdl.desktop.fullscreen) {/*is GOING fullscreen*/ 02875 UpdateWindowDimensions(); 02876 02877 if (screen_size_info.screen_dimensions_pixels.width != 0 && screen_size_info.screen_dimensions_pixels.height != 0) { 02878 if (sdl.desktop.full.width_auto) 02879 sdl.desktop.full.width = (unsigned int)screen_size_info.screen_dimensions_pixels.width; 02880 if (sdl.desktop.full.height_auto) 02881 sdl.desktop.full.height = (unsigned int)screen_size_info.screen_dimensions_pixels.height; 02882 02883 #if !defined(C_SDL2) && defined(MACOSX) 02884 /* Mac OS X has this annoying problem with their API where the System Preferences app, display settings panel 02885 allows setting 720p and 1080i/1080p modes on monitors who's native resolution is less than 1920x1080 but 02886 supports 1920x1080. 02887 02888 This is a problem with HDTV sets made in the late 2000s early 2010s when "HD" apparently meant LCD displays 02889 with 1368x768 resolution that will nonetheless accept 1080i (and later, 1080p) and downscale on display. 02890 02891 The problem is that with these monitors, Mac OS X's display API will NOT list 1920x1080 as one of the 02892 display modes even when the freaking desktop is obviously set to 1920x1080 on that monitor! 02893 02894 If the screen reporting code says 1920x1080 and we try to go fullscreen, SDL1 will intervene and say 02895 "hey wait there's no 1920x1080 in the mode list" and then fail the call. 02896 02897 So to work around this, we have to go check SDL's mode list before using the screen size returned by the 02898 API. 02899 02900 Oh and for extra fun, Mac OS X is one of those modern systems where "setting the video mode" apparently 02901 means NOT setting the video hardware mode but just changing how the GPU scales the display... EXCEPT when 02902 talking to these older displays where if the user set it to 1080i/1080p, our request to set 1368x768 02903 actually DOES change the video mode. This is just wonderful considering the old HDTV set I bought back in 02904 2008 takes 1-2 seconds to adjust to the mode change on it's HDMI input. 02905 02906 Frankly I wish I knew how to fix the SDL1 Quartz code to use whatever abracadabra magic code is required 02907 to enumerate these extra HDTV modes so this hack isn't necessary, except that experience says this hack is 02908 always necesary because it might not always work. 02909 02910 This magic hidden super secret API bullshit is annoying. You're worse than Microsoft with this stuff, Apple --J.C. */ 02911 { 02912 SDL_Rect **ls = SDLCALL SDL_ListModes(NULL, SDL_FULLSCREEN); 02913 if (ls != NULL) { 02914 unsigned int maxwidth = 0,maxheight = 0; 02915 02916 for (size_t i=0;ls[i] != NULL;i++) { 02917 unsigned int w = ls[i]->w; 02918 unsigned int h = ls[i]->h; 02919 02920 if (maxwidth < w || maxheight < h) { 02921 maxwidth = w; 02922 maxheight = h; 02923 } 02924 } 02925 02926 if (maxwidth != 0 && maxheight != 0) { 02927 LOG_MSG("OS X: Actual maximum screen resolution is %d x %d\n",maxwidth,maxheight); 02928 02929 if (sdl.desktop.full.width_auto) { 02930 if (sdl.desktop.full.width > maxwidth) 02931 sdl.desktop.full.width = maxwidth; 02932 } 02933 if (sdl.desktop.full.height_auto) { 02934 if (sdl.desktop.full.height > maxheight) 02935 sdl.desktop.full.height = maxheight; 02936 } 02937 } 02938 } 02939 } 02940 #endif 02941 02942 #if !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL) 02943 SDL_hax_SetFSWindowPosition( 02944 (int)screen_size_info.screen_position_pixels.x, (int)screen_size_info.screen_position_pixels.y, 02945 (int)screen_size_info.screen_dimensions_pixels.width, (int)screen_size_info.screen_dimensions_pixels.height); 02946 #endif 02947 } 02948 else { 02949 #if !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL) 02950 SDL_hax_SetFSWindowPosition(0,0,0,0); 02951 #endif 02952 } 02953 } 02954 02955 menu.resizeusing = true; 02956 02957 sdl.desktop.fullscreen = !sdl.desktop.fullscreen; 02958 02959 auto full = sdl.desktop.fullscreen; 02960 02961 // if we're going fullscreen and current scaler exceeds screen size, 02962 // cancel the fullscreen change -> fixes scaler crashes 02963 // TODO this will need further changes to accomodate different outputs (e.g. stretched) 02964 if (full) 02965 { 02966 int width, height; 02967 GetDesktopResolution(&width, &height); 02968 auto width1 = sdl.draw.width; 02969 auto height1 = sdl.draw.height; 02970 if ((unsigned int)width < width1 || (unsigned int)height < height1) { 02971 sdl.desktop.fullscreen = false; 02972 LOG_MSG("WARNING: full screen canceled, surface size (%ix%i) exceeds screen size (%ix%i).", 02973 width1, height1, width, height); 02974 return; 02975 } 02976 } 02977 02978 LOG_MSG("INFO: switched to %s mode", full ? "full screen" : "window"); 02979 02980 #if !defined(C_SDL2) 02981 // (re-)assign menu to window 02982 void DOSBox_SetSysMenu(void); 02983 DOSBox_SetSysMenu(); 02984 #endif 02985 02986 // ensure mouse capture when fullscreen || (re-)capture if user said so when windowed 02987 auto locked = sdl.mouse.locked; 02988 if ((full && !locked) || (!full && locked)) GFX_CaptureMouse(); 02989 02990 // disable/enable sticky keys for fullscreen/desktop 02991 #if defined (WIN32) 02992 sticky_keys(!full); 02993 #endif 02994 02995 GFX_ResetScreen(); 02996 02997 // set vsync to host 02998 // NOTE why forcing ??? 02999 #ifdef WIN32 03000 if (menu.startup) // NOTE should be always true I suppose ??? 03001 { 03002 auto vsyncProp = static_cast<Section_prop *>(control->GetSection("vsync")); 03003 if (vsyncProp) 03004 { 03005 auto vsyncMode = vsyncProp->Get_string("vsyncmode"); 03006 if (!strcmp(vsyncMode, "host")) SetVal("vsync", "vsyncmode", "host"); 03007 } 03008 } 03009 #endif 03010 #endif 03011 } 03012 03013 static void SwitchFullScreen(bool pressed) { 03014 if (!pressed) 03015 return; 03016 03017 GFX_LosingFocus(); 03018 if (sdl.desktop.lazy_fullscreen) { 03019 LOG_MSG("GFX LF: fullscreen switching not supported"); 03020 } else { 03021 GFX_SwitchFullScreen(); 03022 } 03023 } 03024 03025 void GFX_SwitchLazyFullscreen(bool lazy) { 03026 sdl.desktop.lazy_fullscreen=lazy; 03027 sdl.desktop.lazy_fullscreen_req=false; 03028 } 03029 03030 void GFX_SwitchFullscreenNoReset(void) { 03031 sdl.desktop.fullscreen=!sdl.desktop.fullscreen; 03032 } 03033 03034 bool GFX_LazyFullscreenRequested(void) { 03035 if (sdl.desktop.lazy_fullscreen) return sdl.desktop.lazy_fullscreen_req; 03036 return false; 03037 } 03038 03039 bool GFX_GetPreventFullscreen(void) { 03040 return sdl.desktop.prevent_fullscreen; 03041 } 03042 03043 #if defined(WIN32) && !defined(C_SDL2) 03044 extern "C" unsigned char SDL1_hax_RemoveMinimize; 03045 #endif 03046 03047 void GFX_PreventFullscreen(bool lockout) { 03048 if (sdl.desktop.prevent_fullscreen != lockout) { 03049 sdl.desktop.prevent_fullscreen = lockout; 03050 #if defined(WIN32) && !defined(C_SDL2) 03051 void DOSBox_SetSysMenu(void); 03052 int Reflect_Menu(void); 03053 03054 SDL1_hax_RemoveMinimize = lockout ? 1 : 0; 03055 03056 DOSBox_SetSysMenu(); 03057 Reflect_Menu(); 03058 #endif 03059 } 03060 } 03061 03062 void GFX_RestoreMode(void) { 03063 if (sdl.draw.width == 0 || sdl.draw.height == 0) 03064 return; 03065 03066 GFX_SetSize(sdl.draw.width,sdl.draw.height,sdl.draw.flags,sdl.draw.scalex,sdl.draw.scaley,sdl.draw.callback); 03067 GFX_UpdateSDLCaptureState(); 03068 GFX_ResetScreen(); 03069 } 03070 03071 #if !defined(C_SDL2) 03072 static bool GFX_GetSurfacePtrLock = false; 03073 03074 unsigned char *GFX_GetSurfacePtr(size_t *pitch, unsigned int x, unsigned int y) { 03075 if (sdl.surface->pixels == NULL) { 03076 if (!GFX_GetSurfacePtrLock) { 03077 if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface)) 03078 return NULL; 03079 03080 GFX_GetSurfacePtrLock = true; 03081 } 03082 } 03083 03084 *pitch = sdl.surface->pitch; 03085 if (sdl.surface->pixels != NULL) { 03086 unsigned char *p = (unsigned char*)(sdl.surface->pixels); 03087 p += y * sdl.surface->pitch; 03088 p += x * ((unsigned int)sdl.surface->format->BitsPerPixel >> 3U); 03089 return p; 03090 } 03091 03092 return NULL; 03093 } 03094 03095 void GFX_ReleaseSurfacePtr(void) { 03096 if (GFX_GetSurfacePtrLock) { 03097 if (SDL_MUSTLOCK(sdl.surface)) 03098 SDL_UnlockSurface(sdl.surface); 03099 03100 GFX_GetSurfacePtrLock = false; 03101 } 03102 } 03103 #endif 03104 03105 bool GFX_StartUpdate(Bit8u* &pixels,Bitu &pitch) 03106 { 03107 if (!sdl.active || sdl.updating) 03108 return false; 03109 03110 switch (sdl.desktop.type) 03111 { 03112 case SCREEN_SURFACE: 03113 return OUTPUT_SURFACE_StartUpdate(pixels, pitch); 03114 03115 #if C_OPENGL 03116 case SCREEN_OPENGL: 03117 return OUTPUT_OPENGL_StartUpdate(pixels, pitch); 03118 #endif 03119 03120 #if C_DIRECT3D 03121 case SCREEN_DIRECT3D: 03122 return OUTPUT_DIRECT3D_StartUpdate(pixels, pitch); 03123 #endif 03124 03125 default: 03126 break; 03127 } 03128 03129 return false; 03130 } 03131 03132 void GFX_OpenGLRedrawScreen(void) { 03133 #if C_OPENGL 03134 if (OpenGL_using()) { 03135 if (sdl_opengl.clear_countdown > 0) { 03136 sdl_opengl.clear_countdown--; 03137 glClearColor (0.0, 0.0, 0.0, 1.0); 03138 glClear(GL_COLOR_BUFFER_BIT); 03139 } 03140 03141 if (sdl_opengl.pixel_buffer_object) { 03142 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT); 03143 glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture); 03144 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0); 03145 glCallList(sdl_opengl.displaylist); 03146 } else { 03147 glBindTexture(GL_TEXTURE_2D, sdl_opengl.texture); 03148 glCallList(sdl_opengl.displaylist); 03149 } 03150 } 03151 #endif 03152 } 03153 03154 void GFX_EndUpdate(const Bit16u *changedLines) { 03155 #if C_EMSCRIPTEN 03156 emscripten_sleep_with_yield(0); 03157 #endif 03158 03159 /* don't present our output if 3Dfx is in OpenGL mode */ 03160 if (sdl.desktop.prevent_fullscreen) 03161 return; 03162 03163 #if C_DIRECT3D 03164 // we may have to do forced update in D3D case 03165 if (d3d && d3d->getForceUpdate()); 03166 else 03167 #endif 03168 if (!sdl.updating) 03169 return; 03170 03171 sdl.updating = false; 03172 switch (sdl.desktop.type) 03173 { 03174 case SCREEN_SURFACE: 03175 OUTPUT_SURFACE_EndUpdate(changedLines); 03176 break; 03177 03178 #if C_OPENGL 03179 case SCREEN_OPENGL: 03180 OUTPUT_OPENGL_EndUpdate(changedLines); 03181 break; 03182 #endif 03183 03184 #if C_DIRECT3D 03185 case SCREEN_DIRECT3D: 03186 OUTPUT_DIRECT3D_EndUpdate(changedLines); 03187 break; 03188 #endif 03189 03190 default: 03191 break; 03192 } 03193 03194 if (changedLines != NULL) 03195 { 03196 sdl.must_redraw_all = false; 03197 03198 #if !defined(C_SDL2) && defined(SDL_DOSBOX_X_SPECIAL) 03199 sdl.surface->flags &= ~((unsigned int)SDL_HAX_NOREFRESH); 03200 #endif 03201 03202 if (changedLines != NULL && sdl.deferred_resize) 03203 { 03204 sdl.deferred_resize = false; 03205 #if !defined(C_SDL2) 03206 void GFX_RedrawScreen(Bit32u nWidth, Bit32u nHeight); 03207 GFX_RedrawScreen(sdl.draw.width, sdl.draw.height); 03208 #endif 03209 } 03210 else if (sdl.gfx_force_redraw_count > 0) 03211 { 03212 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 03213 RENDER_CallBack(GFX_CallBackRedraw); 03214 sdl.gfx_force_redraw_count--; 03215 } 03216 } 03217 } 03218 03219 void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries) { 03220 (void)start; 03221 (void)count; 03222 (void)entries; 03223 #if !defined(C_SDL2) 03224 /* I should probably not change the GFX_PalEntry :) */ 03225 if (sdl.surface->flags & SDL_HWPALETTE) { 03226 if (!SDL_SetPalette(sdl.surface,SDL_PHYSPAL,(SDL_Color *)entries,(int)start,(int)count)) { 03227 E_Exit("SDL:Can't set palette"); 03228 } 03229 } else { 03230 if (!SDL_SetPalette(sdl.surface,SDL_LOGPAL,(SDL_Color *)entries,(int)start,(int)count)) { 03231 E_Exit("SDL:Can't set palette"); 03232 } 03233 } 03234 #endif 03235 } 03236 03237 Bitu GFX_GetRGB(Bit8u red, Bit8u green, Bit8u blue) { 03238 switch (sdl.desktop.type) { 03239 case SCREEN_SURFACE: 03240 return SDL_MapRGB(sdl.surface->format, red, green, blue); 03241 03242 #if C_OPENGL 03243 case SCREEN_OPENGL: 03244 # if SDL_BYTEORDER == SDL_LIL_ENDIAN && defined(MACOSX) /* Mac OS X Intel builds use a weird RGBA order (alpha in the low 8 bits) */ 03245 //USE BGRA 03246 return (((unsigned long)blue << 24ul) | ((unsigned long)green << 16ul) | ((unsigned long)red << 8ul)) | (255ul << 0ul); 03247 # else 03248 //USE ARGB 03249 return (((unsigned long)blue << 0ul) | ((unsigned long)green << 8ul) | ((unsigned long)red << 16ul)) | (255ul << 24ul); 03250 # endif 03251 #endif 03252 03253 #if C_DIRECT3D 03254 case SCREEN_DIRECT3D: 03255 return SDL_MapRGB(sdl.surface->format, red, green, blue); 03256 #endif 03257 03258 default: 03259 break; 03260 } 03261 return 0; 03262 } 03263 03264 void GFX_Stop() { 03265 if (sdl.updating) 03266 GFX_EndUpdate( 0 ); 03267 sdl.active=false; 03268 } 03269 03270 void GFX_Start() { 03271 sdl.active=true; 03272 } 03273 03274 static void GUI_ShutDown(Section * /*sec*/) { 03275 GFX_Stop(); 03276 if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop ); 03277 if (sdl.mouse.locked) GFX_CaptureMouse(); 03278 if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); 03279 switch (sdl.desktop.type) 03280 { 03281 case SCREEN_SURFACE: 03282 OUTPUT_SURFACE_Shutdown(); 03283 break; 03284 03285 #if C_OPENGL 03286 case SCREEN_OPENGL: 03287 OUTPUT_OPENGL_Shutdown(); 03288 break; 03289 #endif 03290 03291 #if C_DIRECT3D 03292 case SCREEN_DIRECT3D: 03293 OUTPUT_DIRECT3D_Shutdown(); 03294 break; 03295 #endif 03296 03297 default: 03298 break; 03299 } 03300 } 03301 03302 static void SetPriority(PRIORITY_LEVELS level) { 03303 03304 #if C_SET_PRIORITY 03305 // Do nothing if priorties are not the same and not root, else the highest 03306 // priority can not be set as users can only lower priority (not restore it) 03307 03308 if((sdl.priority.focus != sdl.priority.nofocus ) && 03309 (getuid()!=0) ) return; 03310 03311 #endif 03312 switch (level) { 03313 #ifdef WIN32 03314 case PRIORITY_LEVEL_PAUSE: // if DOSBox-X is paused, assume idle priority 03315 case PRIORITY_LEVEL_LOWEST: 03316 SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS); 03317 break; 03318 case PRIORITY_LEVEL_LOWER: 03319 SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS); 03320 break; 03321 case PRIORITY_LEVEL_NORMAL: 03322 SetPriorityClass(GetCurrentProcess(),NORMAL_PRIORITY_CLASS); 03323 break; 03324 case PRIORITY_LEVEL_HIGHER: 03325 SetPriorityClass(GetCurrentProcess(),ABOVE_NORMAL_PRIORITY_CLASS); 03326 break; 03327 case PRIORITY_LEVEL_HIGHEST: 03328 SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS); 03329 break; 03330 #elif C_SET_PRIORITY 03331 /* Linux use group as dosbox-x has mulitple threads under linux */ 03332 case PRIORITY_LEVEL_PAUSE: // if DOSBox-X is paused, assume idle priority 03333 case PRIORITY_LEVEL_LOWEST: 03334 setpriority (PRIO_PGRP, 0,PRIO_MAX); 03335 break; 03336 case PRIORITY_LEVEL_LOWER: 03337 setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/3)); 03338 break; 03339 case PRIORITY_LEVEL_NORMAL: 03340 setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/2)); 03341 break; 03342 case PRIORITY_LEVEL_HIGHER: 03343 setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/5) ); 03344 break; 03345 case PRIORITY_LEVEL_HIGHEST: 03346 setpriority (PRIO_PGRP, 0,PRIO_MAX-((3*PRIO_TOTAL)/4) ); 03347 break; 03348 #endif 03349 default: 03350 break; 03351 } 03352 } 03353 03354 extern Bit8u int10_font_14[256 * 14]; 03355 static void OutputString(Bitu x,Bitu y,const char * text,Bit32u color,Bit32u color2,SDL_Surface * output_surface) { 03356 Bit32u * draw=(Bit32u*)(((Bit8u *)output_surface->pixels)+((y)*output_surface->pitch))+x; 03357 while (*text) { 03358 Bit8u * font=&int10_font_14[(*text)*14]; 03359 Bitu i,j; 03360 Bit32u * draw_line=draw; 03361 for (i=0;i<14;i++) { 03362 Bit8u map=*font++; 03363 for (j=0;j<8;j++) { 03364 if (map & 0x80) *((Bit32u*)(draw_line+j))=color; else *((Bit32u*)(draw_line+j))=color2; 03365 map<<=1; 03366 } 03367 draw_line+=output_surface->pitch/4; 03368 } 03369 text++; 03370 draw+=8; 03371 } 03372 } 03373 03374 void ResetSystem(bool pressed) { 03375 if (!pressed) return; 03376 03377 if (is_paused) { 03378 is_paused = false; 03379 mainMenu.get_item("mapper_pause").check(false).refresh_item(mainMenu); 03380 } 03381 if (pausewithinterrupts_enable) { 03382 pausewithinterrupts_enable = false; 03383 mainMenu.get_item("mapper_pauseints").check(false).refresh_item(mainMenu); 03384 } 03385 03386 throw int(3); 03387 } 03388 03389 bool has_GUI_StartUp = false; 03390 03391 static void GUI_StartUp() { 03392 DOSBoxMenu::item *item; 03393 03394 if (has_GUI_StartUp) return; 03395 has_GUI_StartUp = true; 03396 03397 LOG(LOG_GUI,LOG_DEBUG)("Starting GUI"); 03398 03399 #if defined(C_SDL2) 03400 LOG(LOG_GUI,LOG_DEBUG)("This version compiled against SDL 2.x"); 03401 #else 03402 LOG(LOG_GUI,LOG_DEBUG)("This version compiled against SDL 1.x"); 03403 #endif 03404 03405 #if defined(C_SDL2) 03406 /* while we're here, SDL 2.0.5 has some issues with Linux/X11, encourage the user to update SDL2. */ 03407 { 03408 SDL_version v; 03409 SDL_GetVersion(&v); 03410 LOG(LOG_GUI,LOG_DEBUG)("SDL2 version %u.%u.%u",v.major,v.minor,v.patch); 03411 03412 # if defined(LINUX) 03413 /* Linux/X11 2.0.5 has window positioning issues i.e. with XFCE */ 03414 if (v.major == 2 && v.minor == 0 && v.patch == 5) 03415 LOG_MSG("WARNING: Your SDL2 library is known to have some issues with Linux/X11, please update your SDL2 library"); 03416 # endif 03417 } 03418 #endif 03419 03420 AddExitFunction(AddExitFunctionFuncPair(GUI_ShutDown)); 03421 GUI_LoadFonts(); 03422 03423 sdl.active=false; 03424 sdl.updating=false; 03425 #if defined(C_SDL2) 03426 sdl.update_window=true; 03427 #endif 03428 03429 GFX_SetIcon(); 03430 03431 sdl.desktop.lazy_fullscreen=false; 03432 sdl.desktop.lazy_fullscreen_req=false; 03433 sdl.desktop.prevent_fullscreen=false; 03434 03435 Section_prop * section=static_cast<Section_prop *>(control->GetSection("sdl")); 03436 assert(section != NULL); 03437 03438 sdl.desktop.fullscreen=section->Get_bool("fullscreen"); 03439 sdl.wait_on_error=section->Get_bool("waitonerror"); 03440 03441 Prop_multival* p=section->Get_multival("priority"); 03442 std::string focus = p->GetSection()->Get_string("active"); 03443 std::string notfocus = p->GetSection()->Get_string("inactive"); 03444 03445 if (focus == "lowest") { sdl.priority.focus = PRIORITY_LEVEL_LOWEST; } 03446 else if (focus == "lower") { sdl.priority.focus = PRIORITY_LEVEL_LOWER; } 03447 else if (focus == "normal") { sdl.priority.focus = PRIORITY_LEVEL_NORMAL; } 03448 else if (focus == "higher") { sdl.priority.focus = PRIORITY_LEVEL_HIGHER; } 03449 else if (focus == "highest") { sdl.priority.focus = PRIORITY_LEVEL_HIGHEST; } 03450 03451 if (notfocus == "lowest") { sdl.priority.nofocus=PRIORITY_LEVEL_LOWEST; } 03452 else if (notfocus == "lower") { sdl.priority.nofocus=PRIORITY_LEVEL_LOWER; } 03453 else if (notfocus == "normal") { sdl.priority.nofocus=PRIORITY_LEVEL_NORMAL; } 03454 else if (notfocus == "higher") { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHER; } 03455 else if (notfocus == "highest") { sdl.priority.nofocus=PRIORITY_LEVEL_HIGHEST; } 03456 else if (notfocus == "pause") { 03457 /* we only check for pause here, because it makes no sense 03458 * for DOSBox-X to be paused while it has focus 03459 */ 03460 sdl.priority.nofocus=PRIORITY_LEVEL_PAUSE; 03461 } 03462 03463 SetPriority(sdl.priority.focus); //Assume focus on startup 03464 sdl.mouse.locked=false; 03465 mouselocked=false; //Global for mapper 03466 sdl.mouse.requestlock=false; 03467 sdl.desktop.full.fixed=false; 03468 const char* fullresolution=section->Get_string("fullresolution"); 03469 sdl.desktop.full.width = 0; 03470 sdl.desktop.full.height = 0; 03471 if(fullresolution && *fullresolution) { 03472 char res[100]; 03473 safe_strncpy(res, fullresolution, sizeof(res)); 03474 fullresolution = lowcase (res);//so x and X are allowed 03475 if (strcmp(fullresolution,"original")) { 03476 sdl.desktop.full.fixed = true; 03477 if (strcmp(fullresolution,"desktop")) { //desktop = 0x0 03478 char* height = const_cast<char*>(strchr(fullresolution,'x')); 03479 if (height && * height) { 03480 *height = 0; 03481 sdl.desktop.full.height = (Bit16u)atoi(height+1); 03482 sdl.desktop.full.width = (Bit16u)atoi(res); 03483 } 03484 } 03485 } 03486 } 03487 03488 sdl.desktop.window.width = 0; 03489 sdl.desktop.window.height = 0; 03490 const char* windowresolution=section->Get_string("windowresolution"); 03491 if(windowresolution && *windowresolution) { 03492 char res[100]; 03493 safe_strncpy(res, windowresolution, sizeof(res)); 03494 windowresolution = lowcase (res);//so x and X are allowed 03495 if(strcmp(windowresolution,"original")) { 03496 char* height = const_cast<char*>(strchr(windowresolution,'x')); 03497 if(height && *height) { 03498 *height = 0; 03499 sdl.desktop.window.height = (Bit16u)atoi(height+1); 03500 sdl.desktop.window.width = (Bit16u)atoi(res); 03501 } 03502 } 03503 } 03504 sdl.desktop.doublebuf=section->Get_bool("fulldouble"); 03505 #if defined(C_SDL2) 03506 { 03507 SDL_DisplayMode dm; 03508 if (SDL_GetDesktopDisplayMode(0/*FIXME display index*/,&dm) == 0) { 03509 if (sdl.desktop.full.width == 0) { 03510 sdl.desktop.full.width_auto = true; 03511 sdl.desktop.full.width = dm.w; 03512 } 03513 if (sdl.desktop.full.height == 0) { 03514 sdl.desktop.full.height_auto = true; 03515 sdl.desktop.full.height = dm.h; 03516 } 03517 LOG_MSG("SDL2 reports desktop display mode %u x %u",dm.w,dm.h); 03518 } 03519 else { 03520 LOG_MSG("SDL2 unable to determine desktop display mode, error %s",SDL_GetError()); 03521 } 03522 } 03523 #endif 03524 #if !defined(C_SDL2) 03525 #if SDL_VERSION_ATLEAST(1, 2, 10) 03526 #ifdef WIN32 03527 /* NTS: This should not print any warning whatsoever because Windows builds by default will use 03528 * the Windows API to disable DPI scaling of the main window, unless the user modifies the 03529 * setting through dosbox-x.conf or the command line. */ 03530 /* NTS: Mac OS X has high DPI scaling too, though Apple is wise to enable it by default only for 03531 * Macbooks with "Retina" displays. On Mac OS X, unless otherwise wanted by the user, it is 03532 * wise to let Mac OS X scale up the DOSBox-X window by 2x so that the DOS prompt is not 03533 * a teeny tiny window on the screen. */ 03534 const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo(); 03535 if (vidinfo) { 03536 int sdl_w = vidinfo->current_w; 03537 int sdl_h = vidinfo->current_h; 03538 int win_w = GetSystemMetrics(SM_CXSCREEN); 03539 int win_h = GetSystemMetrics(SM_CYSCREEN); 03540 if (sdl_w != win_w && sdl_h != win_h) 03541 LOG_MSG("Windows DPI/blurry apps scaling detected as it might be a large screen.\n" 03542 "Please see the DOSBox-X documentation for more details.\n"); 03543 } 03544 #else 03545 if (!sdl.desktop.full.width || !sdl.desktop.full.height){ 03546 //Can only be done on the very first call! Not restartable. 03547 //On windows don't use it as SDL returns the values without taking in account the dpi scaling 03548 const SDL_VideoInfo* vidinfo = SDL_GetVideoInfo(); 03549 if (vidinfo) { 03550 if (sdl.desktop.full.width == 0) { 03551 sdl.desktop.full.width_auto = true; 03552 sdl.desktop.full.width = vidinfo->current_w; 03553 } 03554 if (sdl.desktop.full.height == 0) { 03555 sdl.desktop.full.height_auto = true; 03556 sdl.desktop.full.height = vidinfo->current_h; 03557 } 03558 03559 LOG_MSG("SDL1 auto-detected desktop as %u x %u", 03560 (unsigned int)sdl.desktop.full.width, 03561 (unsigned int)sdl.desktop.full.height); 03562 } 03563 } 03564 #endif 03565 #endif 03566 #endif 03567 03568 if (!sdl.desktop.full.width) { 03569 int width=1024; 03570 sdl.desktop.full.width_auto = true; 03571 sdl.desktop.full.width=width; 03572 } 03573 if (!sdl.desktop.full.height) { 03574 int height=768; 03575 sdl.desktop.full.height_auto = true; 03576 sdl.desktop.full.height=height; 03577 } 03578 sdl.mouse.autoenable=section->Get_bool("autolock"); 03579 if (!sdl.mouse.autoenable) SDL_ShowCursor(SDL_DISABLE); 03580 sdl.mouse.autolock=false; 03581 03582 const std::string feedback = section->Get_string("autolock_feedback"); 03583 if (feedback == "none") 03584 sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_NONE; 03585 else if (feedback == "beep") 03586 sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_BEEP; 03587 else if (feedback == "flash") 03588 sdl.mouse.autolock_feedback = AUTOLOCK_FEEDBACK_FLASH; 03589 03590 modifier = section->Get_string("clip_key_modifier"); 03591 paste_speed = (unsigned int)section->Get_int("clip_paste_speed"); 03592 wheel_key = (unsigned int)section->Get_int("mouse_wheel_key"); 03593 03594 Prop_multival* p3 = section->Get_multival("sensitivity"); 03595 sdl.mouse.xsensitivity = p3->GetSection()->Get_int("xsens"); 03596 sdl.mouse.ysensitivity = p3->GetSection()->Get_int("ysens"); 03597 std::string output=section->Get_string("output"); 03598 03599 const std::string emulation = section->Get_string("mouse_emulation"); 03600 if (emulation == "always") 03601 sdl.mouse.emulation = MOUSE_EMULATION_ALWAYS; 03602 else if (emulation == "locked") 03603 sdl.mouse.emulation = MOUSE_EMULATION_LOCKED; 03604 else if (emulation == "integration") 03605 sdl.mouse.emulation = MOUSE_EMULATION_INTEGRATION; 03606 else if (emulation == "never") 03607 sdl.mouse.emulation = MOUSE_EMULATION_NEVER; 03608 03609 /* Setup Mouse correctly if fullscreen */ 03610 if(sdl.desktop.fullscreen) GFX_CaptureMouse(); 03611 03612 #if C_XBRZ 03613 // initialize xBRZ parameters and check output type for compatibility 03614 xBRZ_Initialize(); 03615 03616 if (sdl_xbrz.enable) { 03617 // xBRZ requirements 03618 if ((output != "surface") && (output != "direct3d") && (output != "opengl") && (output != "openglhq") && (output != "openglnb")) 03619 output = "surface"; 03620 } 03621 #endif 03622 03623 // output type selection 03624 // "overlay" was removed, pre-map to Direct3D or OpenGL or surface 03625 if (output == "overlay") 03626 { 03627 #if C_DIRECT3D 03628 output = "direct3d"; 03629 #elif C_OPENGL 03630 output = "opengl"; 03631 #else 03632 output = "surface"; 03633 #endif 03634 } 03635 03636 if (output == "surface") 03637 { 03638 OUTPUT_SURFACE_Select(); 03639 } 03640 else if (output == "ddraw") 03641 { 03642 OUTPUT_SURFACE_Select(); 03643 #if C_OPENGL 03644 } 03645 else if (output == "opengl" || output == "openglhq") 03646 { 03647 OUTPUT_OPENGL_Select(); 03648 sdl_opengl.bilinear = true; 03649 } 03650 else if (output == "openglnb") 03651 { 03652 OUTPUT_OPENGL_Select(); 03653 sdl_opengl.bilinear = false; 03654 #endif 03655 #if C_DIRECT3D 03656 } 03657 else if (output == "direct3d") 03658 { 03659 OUTPUT_DIRECT3D_Select(); 03660 #if LOG_D3D 03661 LOG_MSG("SDL:Direct3D activated"); 03662 #endif 03663 #endif 03664 } 03665 else 03666 { 03667 LOG_MSG("SDL:Unsupported output device %s, switching back to surface",output.c_str()); 03668 OUTPUT_SURFACE_Select(); // should not reach there anymore 03669 } 03670 03671 sdl.overscan_width=(unsigned int)section->Get_int("overscan"); 03672 // sdl.overscan_color=section->Get_int("overscancolor"); 03673 03674 #if defined(C_SDL2) 03675 /* Initialize screen for first time */ 03676 GFX_SetResizeable(true); 03677 if (!GFX_SetSDLSurfaceWindow(640,400)) 03678 E_Exit("Could not initialize video: %s",SDL_GetError()); 03679 sdl.surface = SDL_GetWindowSurface(sdl.window); 03680 // SDL_Rect splash_rect=GFX_GetSDLSurfaceSubwindowDims(640,400); 03681 sdl.desktop.pixelFormat = SDL_GetWindowPixelFormat(sdl.window); 03682 LOG_MSG("SDL:Current window pixel format: %s", SDL_GetPixelFormatName(sdl.desktop.pixelFormat)); 03683 sdl.desktop.bpp=8*SDL_BYTESPERPIXEL(sdl.desktop.pixelFormat); 03684 if (SDL_BITSPERPIXEL(sdl.desktop.pixelFormat) == 24) 03685 LOG_MSG("SDL: You are running in 24 bpp mode, this will slow down things!"); 03686 #else 03687 /* Initialize screen for first time */ 03688 sdl.surface=SDL_SetVideoMode(640,400,0,SDL_RESIZABLE); 03689 if (sdl.surface == NULL) E_Exit("Could not initialize video: %s",SDL_GetError()); 03690 sdl.deferred_resize = false; 03691 sdl.must_redraw_all = true; 03692 sdl.desktop.bpp=sdl.surface->format->BitsPerPixel; 03693 if (sdl.desktop.bpp==24) 03694 LOG_MSG("SDL:You are running in 24 bpp mode, this will slow down things!"); 03695 #endif 03696 03697 GFX_LogSDLState(); 03698 GFX_Stop(); 03699 03700 #if defined(C_SDL2) 03701 SDL_SetWindowTitle(sdl.window,"DOSBox-X"); 03702 #else 03703 SDL_WM_SetCaption("DOSBox-X",VERSION); 03704 #endif 03705 03706 /* Please leave the Splash screen stuff in working order in DOSBox-X. We spend a lot of time making DOSBox-X. */ 03707 //ShowSplashScreen(); /* I will keep the splash screen alive. But now, the BIOS will do it --J.C. */ 03708 03709 /* Get some Event handlers */ 03710 MAPPER_AddHandler(ResetSystem, MK_r, MMODHOST, "reset", "Reset", &item); /* Host+R (Host+CTRL+R acts funny on my Linux system) */ 03711 item->set_text("Reset guest system"); 03712 03713 #if !defined(C_EMSCRIPTEN)//FIXME: Shutdown causes problems with Emscripten 03714 MAPPER_AddHandler(KillSwitch,MK_f9,MMOD1,"shutdown","ShutDown", &item); /* KEEP: Most DOSBox-X users may have muscle memory for this */ 03715 item->set_text("Quit"); 03716 #endif 03717 03718 MAPPER_AddHandler(CaptureMouse,MK_f10,MMOD1,"capmouse","Cap Mouse", &item); /* KEEP: Most DOSBox-X users may have muscle memory for this */ 03719 item->set_text("Capture mouse"); 03720 03721 MAPPER_AddHandler(SwitchFullScreen,MK_f,MMODHOST,"fullscr","Fullscreen", &item); 03722 item->set_text("Toggle fullscreen"); 03723 03724 MAPPER_AddHandler(PasteClipboard, MK_nothing, 0, "paste", "Paste Clipboard"); //end emendelson 03725 #if C_DEBUG 03726 /* Pause binds with activate-debugger */ 03727 MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD1, "pause", "Pause"); 03728 #else 03729 MAPPER_AddHandler(&PauseDOSBox, MK_pause, MMOD2, "pause", "Pause"); 03730 #endif 03731 03732 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU 03733 pause_menu_item_tag = mainMenu.get_item("mapper_pause").get_master_id() + DOSBoxMenu::nsMenuMinimumID; 03734 #endif 03735 03736 MAPPER_AddHandler(&GUI_Run, MK_nothing, 0, "gui", "ShowGUI", &item); 03737 item->set_text("Configuration GUI"); 03738 03739 MAPPER_AddHandler(&GUI_ResetResize, MK_nothing, 0, "resetsize", "ResetSize", &item); 03740 item->set_text("Reset window size"); 03741 03742 UpdateWindowDimensions(); 03743 } 03744 03745 void Mouse_AutoLock(bool enable) { 03746 if (sdl.mouse.autolock == enable) 03747 return; 03748 03749 sdl.mouse.autolock=enable; 03750 if (sdl.mouse.autoenable) sdl.mouse.requestlock=enable; 03751 else { 03752 SDL_ShowCursor(enable?SDL_DISABLE:SDL_ENABLE); 03753 sdl.mouse.requestlock=false; 03754 } 03755 } 03756 03757 bool Mouse_IsLocked() 03758 { 03759 return sdl.mouse.locked; 03760 } 03761 03762 static void RedrawScreen(Bit32u nWidth, Bit32u nHeight) { 03763 (void)nWidth;//UNUSED 03764 (void)nHeight;//UNUSED 03765 // int width; 03766 // int height; 03767 #ifdef __WIN32__ 03768 // width=sdl.clip.w; 03769 // height=sdl.clip.h; 03770 #else 03771 // width=sdl.draw.width; 03772 // height=sdl.draw.height; 03773 #endif 03774 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 03775 #if 0 03776 while (sdl.desktop.fullscreen) { 03777 int temp_size; 03778 temp_size=render.scale.size; 03779 if(!sdl.desktop.fullscreen) { render.scale.size=temp_size; RENDER_CallBack( GFX_CallBackReset); return; } 03780 } 03781 #endif 03782 #ifdef WIN32 03783 if(menu.resizeusing) { 03784 RENDER_CallBack( GFX_CallBackReset); 03785 return; 03786 } 03787 #endif 03788 #if 0 /* FIXME: This code misbehaves when doublescan=false on Linux/X11 */ 03789 if((Bitu)nWidth == (Bitu)width && (Bitu)nHeight == (Bitu)height) { 03790 RENDER_CallBack( GFX_CallBackReset); 03791 return; 03792 } 03793 Section_prop * section=static_cast<Section_prop *>(control->GetSection("sdl")); 03794 if ((!strcmp(section->Get_string("windowresolution"),"original") || (!strcmp(section->Get_string("windowresolution"),"desktop"))) && (render.src.dblw && render.src.dblh)) { 03795 switch (render.scale.op) { 03796 case scalerOpNormal: 03797 if(!render.scale.hardware) { 03798 if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) { 03799 if (render.scale.size <= 4 && render.scale.size >=1) ++render.scale.size; break; 03800 } else { 03801 if (render.scale.size <= 5 && render.scale.size >= 2) --render.scale.size; break; 03802 } 03803 } else { 03804 if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) { 03805 if (render.scale.size == 1) { render.scale.size=4; break; } 03806 if (render.scale.size == 4) { render.scale.size=6; break; } 03807 if (render.scale.size == 6) { render.scale.size=8; break; } 03808 if (render.scale.size == 8) { render.scale.size=10; break; } 03809 } 03810 if((Bitu)nWidth<(Bitu)width || (Bitu)nHeight<(Bitu)height) { 03811 if (render.scale.size == 10) { render.scale.size=8; break; } 03812 if (render.scale.size == 8) { render.scale.size=6; break; } 03813 if (render.scale.size == 6) { render.scale.size=4; break; } 03814 if (render.scale.size == 4) { render.scale.size=1; break; } 03815 } 03816 } 03817 break; 03818 case scalerOpAdvMame: 03819 case scalerOpHQ: 03820 case scalerOpAdvInterp: 03821 case scalerOpTV: 03822 case scalerOpRGB: 03823 case scalerOpScan: 03824 if((Bitu)nWidth>(Bitu)width || (Bitu)nHeight>(Bitu)height) { if (render.scale.size == 2) ++render.scale.size; } 03825 if((Bitu)nWidth<(Bitu)width || (Bitu)nHeight<(Bitu)height) { if (render.scale.size == 3) --render.scale.size; } 03826 break; 03827 case scalerOpSaI: 03828 case scalerOpSuperSaI: 03829 case scalerOpSuperEagle: 03830 default: // other scalers 03831 break; 03832 } 03833 } 03834 #endif 03835 RENDER_CallBack( GFX_CallBackReset); 03836 } 03837 03838 void GFX_RedrawScreen(Bit32u nWidth, Bit32u nHeight) { 03839 RedrawScreen(nWidth, nHeight); 03840 } 03841 03842 bool GFX_MustActOnResize() { 03843 if (!GFX_IsFullscreen()) 03844 return false; 03845 03846 return true; 03847 } 03848 03849 #if defined(C_SDL2) 03850 void GFX_HandleVideoResize(int width, int height) { 03851 /* Maybe a screen rotation has just occurred, so we simply resize. 03852 There may be a different cause for a forced resized, though. */ 03853 if (sdl.desktop.full.display_res && IsFullscreen()) { 03854 /* Note: We should not use GFX_ObtainDisplayDimensions 03855 (SDL_GetDisplayBounds) on Android after a screen rotation: 03856 The older values from application startup are returned. */ 03857 sdl.desktop.full.width = width; 03858 sdl.desktop.full.height = height; 03859 } 03860 03861 /* assume the resize comes from user preference UNLESS the window 03862 * is fullscreen or maximized */ 03863 if (!menu.maxwindow && !sdl.desktop.fullscreen && !sdl.init_ignore && NonUserResizeCounter == 0 && !window_was_maximized) { 03864 UpdateWindowDimensions(); 03865 UpdateWindowDimensions((unsigned int)width, (unsigned int)height); 03866 03867 /* if the dimensions actually changed from our surface dimensions, then 03868 assume it's the user's input. Linux/X11 is good at doing this anyway, 03869 but the Windows SDL 1.x support will return us a resize event for the 03870 window size change resulting from SDL mode set. */ 03871 if (width != sdl.surface->w || height != sdl.surface->h) { 03872 userResizeWindowWidth = (unsigned int)width; 03873 userResizeWindowHeight = (unsigned int)height; 03874 } 03875 } 03876 else { 03877 UpdateWindowDimensions(); 03878 } 03879 03880 /* TODO: Only if FULLSCREEN_DESKTOP */ 03881 if (screen_size_info.screen_dimensions_pixels.width != 0 && screen_size_info.screen_dimensions_pixels.height != 0) { 03882 sdl.desktop.full.width = (Bit16u)screen_size_info.screen_dimensions_pixels.width; 03883 sdl.desktop.full.height = (Bit16u)screen_size_info.screen_dimensions_pixels.height; 03884 } 03885 else { 03886 SDL_DisplayMode dm; 03887 if (SDL_GetDesktopDisplayMode(0/*FIXME display index*/,&dm) == 0) { 03888 sdl.desktop.full.width = dm.w; 03889 sdl.desktop.full.height = dm.h; 03890 LOG_MSG("SDL2 reports desktop display mode %u x %u",dm.w,dm.h); 03891 } 03892 else { 03893 LOG_MSG("SDL2 unable to determine desktop display mode, error %s",SDL_GetError()); 03894 } 03895 } 03896 03897 window_was_maximized = menu.maxwindow; 03898 if (NonUserResizeCounter > 0) 03899 NonUserResizeCounter--; 03900 03901 /* Even if the new window's dimensions are actually the desired ones 03902 * we may still need to re-obtain a new window surface or do 03903 * a different thing. So we basically call GFX_SetSize, but without 03904 * touching the window itself (or else we may end in an infinite loop). 03905 * 03906 * Furthermore, if the new dimensions are *not* the desired ones, we 03907 * don't fight it. Rather than attempting to resize it back, we simply 03908 * keep the window as-is and disable screen updates. This is done 03909 * in SDL_SetSDLWindowSurface by setting sdl.update_display_contents 03910 * to false. 03911 */ 03912 sdl.update_window = false; 03913 GFX_ResetScreen(); 03914 sdl.update_window = true; 03915 } 03916 #else 03917 static void HandleVideoResize(void * event) { 03918 if(sdl.desktop.fullscreen) return; 03919 03920 /* don't act on resize events if we made the window non-resizeable. 03921 * especially if 3Dfx voodoo emulation is active. */ 03922 if (!(sdl.surface->flags & SDL_RESIZABLE)) return; 03923 03924 /* don't act if 3Dfx OpenGL emulation is active */ 03925 if (GFX_GetPreventFullscreen()) return; 03926 03927 SDL_ResizeEvent* ResizeEvent = (SDL_ResizeEvent*)event; 03928 03929 /* assume the resize comes from user preference UNLESS the window 03930 * is fullscreen or maximized */ 03931 if (!menu.maxwindow && !sdl.desktop.fullscreen && !sdl.init_ignore && NonUserResizeCounter == 0 && !window_was_maximized) { 03932 UpdateWindowDimensions(); 03933 UpdateWindowDimensions((unsigned int)ResizeEvent->w, (unsigned int)ResizeEvent->h); 03934 03935 /* if the dimensions actually changed from our surface dimensions, then 03936 assume it's the user's input. Linux/X11 is good at doing this anyway, 03937 but the Windows SDL 1.x support will return us a resize event for the 03938 window size change resulting from SDL mode set. */ 03939 if (ResizeEvent->w != sdl.surface->w || ResizeEvent->h != sdl.surface->h) { 03940 userResizeWindowWidth = (unsigned int)ResizeEvent->w; 03941 userResizeWindowHeight = (unsigned int)ResizeEvent->h; 03942 } 03943 } 03944 else { 03945 UpdateWindowDimensions(); 03946 } 03947 03948 window_was_maximized = menu.maxwindow; 03949 if (NonUserResizeCounter > 0) 03950 NonUserResizeCounter--; 03951 03952 if (sdl.updating && !GFX_MustActOnResize()) { 03953 /* act on resize when updating is complete */ 03954 sdl.deferred_resize = true; 03955 } 03956 else { 03957 sdl.deferred_resize = false; 03958 RedrawScreen((unsigned int)ResizeEvent->w, (unsigned int)ResizeEvent->h); 03959 } 03960 #ifdef WIN32 03961 menu.resizeusing=false; 03962 #endif 03963 } 03964 #endif 03965 03966 extern unsigned int mouse_notify_mode; 03967 03968 bool user_cursor_locked = false; 03969 MOUSE_EMULATION user_cursor_emulation = MOUSE_EMULATION_NEVER; 03970 int user_cursor_x = 0,user_cursor_y = 0; 03971 int user_cursor_sw = 640,user_cursor_sh = 480; 03972 03973 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 03974 DOSBoxMenu::item_handle_t DOSBoxMenu::displaylist::itemFromPoint(DOSBoxMenu &menu,int x,int y) { 03975 for (auto &id : disp_list) { 03976 DOSBoxMenu::item &item = menu.get_item(id); 03977 if (x >= item.screenBox.x && y >= item.screenBox.y) { 03978 int sx = x - item.screenBox.x; 03979 int sy = y - item.screenBox.y; 03980 int adj = (this != &menu.display_list && item.get_type() == DOSBoxMenu::submenu_type_id) ? 2 : 0; 03981 if (sx < (item.screenBox.w+adj) && sy < item.screenBox.h) 03982 return id; 03983 } 03984 } 03985 03986 return unassigned_item_handle; 03987 } 03988 03989 void DOSBoxMenu::item::updateScreenFromItem(DOSBoxMenu &menu) { 03990 (void)menu;//UNUSED 03991 if (!OpenGL_using()) { 03992 SDL_Rect uprect = screenBox; 03993 03994 SDL_rect_cliptoscreen(uprect); 03995 03996 #if defined(C_SDL2) 03997 SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1); 03998 #else 03999 SDL_UpdateRects( sdl.surface, 1, &uprect ); 04000 #endif 04001 } 04002 } 04003 04004 void DOSBoxMenu::item::updateScreenFromPopup(DOSBoxMenu &menu) { 04005 (void)menu;//UNUSED 04006 if (!OpenGL_using()) { 04007 SDL_Rect uprect = popupBox; 04008 04009 uprect.w += DOSBoxMenu::dropshadowX; 04010 uprect.h += DOSBoxMenu::dropshadowY; 04011 SDL_rect_cliptoscreen(uprect); 04012 04013 #if defined(C_SDL2) 04014 SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1); 04015 #else 04016 SDL_UpdateRects( sdl.surface, 1, &uprect ); 04017 #endif 04018 } 04019 } 04020 04021 void DOSBoxMenu::item::drawBackground(DOSBoxMenu &menu) { 04022 (void)menu;//UNUSED 04023 Bitu bordercolor = GFX_GetRGB(31, 31, 31); 04024 Bitu bgcolor = GFX_GetRGB(63, 63, 63); 04025 04026 if (popupBox.w <= 1 || popupBox.h <= 1) 04027 return; 04028 04029 MenuDrawRect(popupBox.x, popupBox.y, popupBox.w, popupBox.h, bgcolor); 04030 04031 if (borderTop) 04032 MenuDrawRect(popupBox.x, popupBox.y, popupBox.w, 1, bordercolor); 04033 04034 MenuDrawRect(popupBox.x, popupBox.y + popupBox.h - 1, popupBox.w, 1, bordercolor); 04035 04036 MenuDrawRect(popupBox.x, popupBox.y, 1, popupBox.h, bordercolor); 04037 MenuDrawRect(popupBox.x + popupBox.w - 1, popupBox.y, 1, popupBox.h, bordercolor); 04038 04039 if (type == DOSBoxMenu::submenu_type_id) { 04040 MenuShadeRect((int)popupBox.x + (int)popupBox.w, (int)popupBox.y + (int)DOSBoxMenu::dropshadowY, 04041 (int)DOSBoxMenu::dropshadowX, (int)popupBox.h); 04042 MenuShadeRect((int)popupBox.x + (int)DOSBoxMenu::dropshadowX, (int)popupBox.y + (int)popupBox.h, 04043 (int)popupBox.w - (int)DOSBoxMenu::dropshadowX, (int)DOSBoxMenu::dropshadowY); 04044 } 04045 } 04046 #endif 04047 04048 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 04049 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id) { 04050 (void)menu;//UNUSED 04051 if (mainMenu.menuUserHoverAt != item_id) { 04052 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) { 04053 auto &item = mainMenu.get_item(mainMenu.menuUserHoverAt); 04054 item.setHover(mainMenu,false); 04055 if (item.checkResetRedraw()) { 04056 item.drawMenuItem(mainMenu); 04057 item.updateScreenFromItem(mainMenu); 04058 } 04059 } 04060 04061 mainMenu.menuUserHoverAt = item_id; 04062 04063 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) { 04064 auto &item = mainMenu.get_item(mainMenu.menuUserHoverAt); 04065 item.setHover(mainMenu,true); 04066 if (item.checkResetRedraw()) { 04067 item.drawMenuItem(mainMenu); 04068 item.updateScreenFromItem(mainMenu); 04069 } 04070 } 04071 04072 if (OpenGL_using()) 04073 mainMenu.setRedraw(); 04074 } 04075 } 04076 04077 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id) { 04078 (void)menu;//UNUSED 04079 if (mainMenu.menuUserAttentionAt != item_id) { 04080 if (mainMenu.menuUserAttentionAt != DOSBoxMenu::unassigned_item_handle) { 04081 auto &item = mainMenu.get_item(mainMenu.menuUserAttentionAt); 04082 item.setHilight(mainMenu,false); 04083 if (item.checkResetRedraw()) { 04084 item.drawMenuItem(mainMenu); 04085 item.updateScreenFromItem(mainMenu); 04086 } 04087 } 04088 04089 mainMenu.menuUserAttentionAt = item_id; 04090 04091 if (mainMenu.menuUserAttentionAt != DOSBoxMenu::unassigned_item_handle) { 04092 auto &item = mainMenu.get_item(mainMenu.menuUserAttentionAt); 04093 item.setHilight(mainMenu,true); 04094 if (item.checkResetRedraw()) { 04095 item.drawMenuItem(mainMenu); 04096 item.updateScreenFromItem(mainMenu); 04097 } 04098 } 04099 04100 if (OpenGL_using()) 04101 mainMenu.setRedraw(); 04102 } 04103 } 04104 #endif 04105 04106 uint8_t Mouse_GetButtonState(void); 04107 04108 bool GFX_CursorInOrNearScreen(int wx,int wy) { 04109 int minx = sdl.clip.x - (sdl.clip.w / 10); 04110 int miny = sdl.clip.y - (sdl.clip.h / 10); 04111 int maxx = sdl.clip.x + sdl.clip.w + (sdl.clip.w / 10); 04112 int maxy = sdl.clip.y + sdl.clip.h + (sdl.clip.h / 10); 04113 04114 return (wx >= minx && wx < maxx) && (wy >= miny && wy < maxy); 04115 } 04116 04117 static void HandleMouseMotion(SDL_MouseMotionEvent * motion) { 04118 bool inputToScreen = false; 04119 04120 /* limit mouse input to whenever the cursor is on the screen, or near the edge of the screen. */ 04121 if (is_paused) 04122 inputToScreen = false; 04123 else if (sdl.mouse.locked || Mouse_GetButtonState() != 0) 04124 inputToScreen = true; 04125 else { 04126 inputToScreen = GFX_CursorInOrNearScreen(motion->x,motion->y); 04127 #if defined (WIN32) 04128 if (mouse_start_x >= 0 && mouse_start_y >= 0) { 04129 if (fx>=0 && fy>=0) 04130 Restore_Text(mouse_start_x-sdl.clip.x,mouse_start_y-sdl.clip.y,fx-sdl.clip.x,fy-sdl.clip.y,(int)(currentWindowWidth-sdl.clip.x),(int)(currentWindowHeight-sdl.clip.y)); 04131 Mouse_Select(mouse_start_x-sdl.clip.x,mouse_start_y-sdl.clip.y,motion->x-sdl.clip.x,motion->y-sdl.clip.y,(int)(currentWindowWidth-sdl.clip.x),(int)(currentWindowHeight-sdl.clip.y)); 04132 fx=motion->x; 04133 fy=motion->y; 04134 } 04135 #endif 04136 } 04137 04138 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 04139 if (GFX_GetPreventFullscreen()) { 04140 /* do NOT draw SDL menu in OpenGL mode when 3Dfx emulation is using OpenGL */ 04141 } 04142 else if (!sdl.mouse.locked && !sdl.desktop.fullscreen && mainMenu.isVisible() && motion->y < mainMenu.menuBox.h && Mouse_GetButtonState() == 0) { 04143 GFX_SDLMenuTrackHover(mainMenu,mainMenu.display_list.itemFromPoint(mainMenu,motion->x,motion->y)); 04144 SDL_ShowCursor(SDL_ENABLE); 04145 04146 if (OpenGL_using() && mainMenu.needsRedraw()) { 04147 #if C_OPENGL 04148 sdl_opengl.menudraw_countdown = 2; // two GL buffers 04149 GFX_OpenGLRedrawScreen(); 04150 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 04151 # if defined(C_SDL2) 04152 SDL_GL_SwapWindow(sdl.window); 04153 # else 04154 SDL_GL_SwapBuffers(); 04155 # endif 04156 #endif 04157 } 04158 04159 return; 04160 } 04161 else { 04162 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 04163 04164 if (OpenGL_using() && mainMenu.needsRedraw()) { 04165 #if C_OPENGL 04166 sdl_opengl.menudraw_countdown = 2; // two GL buffers 04167 GFX_OpenGLRedrawScreen(); 04168 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 04169 # if defined(C_SDL2) 04170 SDL_GL_SwapWindow(sdl.window); 04171 # else 04172 SDL_GL_SwapBuffers(); 04173 # endif 04174 #endif 04175 } 04176 } 04177 #endif 04178 04179 if (!inputToScreen) { 04180 #if defined(C_SDL2) 04181 if (!sdl.mouse.locked) 04182 #else 04183 /* SDL1 has some sort of weird mouse warping bug in fullscreen mode no matter whether the mouse is captured or not (Windows, Linux/X11) */ 04184 if (!sdl.mouse.locked && !sdl.desktop.fullscreen) 04185 #endif 04186 SDL_ShowCursor(SDL_ENABLE); 04187 04188 return; 04189 } 04190 04191 user_cursor_x = motion->x - sdl.clip.x; 04192 user_cursor_y = motion->y - sdl.clip.y; 04193 user_cursor_locked = sdl.mouse.locked; 04194 user_cursor_emulation = sdl.mouse.emulation; 04195 user_cursor_sw = sdl.clip.w; 04196 user_cursor_sh = sdl.clip.h; 04197 04198 auto xrel = static_cast<float>(motion->xrel) * sdl.mouse.xsensitivity / 100.0f; 04199 auto yrel = static_cast<float>(motion->yrel) * sdl.mouse.ysensitivity / 100.0f; 04200 auto x = static_cast<float>(motion->x - sdl.clip.x) / (sdl.clip.w - 1) * sdl.mouse.xsensitivity / 100.0f; 04201 auto y = static_cast<float>(motion->y - sdl.clip.y) / (sdl.clip.h - 1) * sdl.mouse.ysensitivity / 100.0f; 04202 auto emu = sdl.mouse.locked; 04203 04204 const auto inside = 04205 motion->x >= sdl.clip.x && motion->x < sdl.clip.x + sdl.clip.w && 04206 motion->y >= sdl.clip.y && motion->y < sdl.clip.y + sdl.clip.h; 04207 04208 if (mouse_notify_mode != 0) 04209 { 04210 /* for mouse integration driver */ 04211 if (!sdl.mouse.locked) 04212 xrel = yrel = x = y = 0.0f; 04213 04214 emu = sdl.mouse.locked; 04215 const auto isdown = Mouse_GetButtonState() != 0; 04216 04217 #if defined(C_SDL2) 04218 if (!sdl.mouse.locked) 04219 #else 04220 /* SDL1 has some sort of weird mouse warping bug in fullscreen mode no matter whether the mouse is captured or not (Windows, Linux/X11) */ 04221 if (!sdl.mouse.locked && !sdl.desktop.fullscreen) 04222 #endif 04223 SDL_ShowCursor((isdown || inside) ? SDL_DISABLE : SDL_ENABLE); 04224 } 04225 else if (!user_cursor_locked) 04226 { 04227 extern bool MOUSE_HasInterruptSub(); 04228 extern bool MOUSE_IsBeingPolled(); 04229 extern bool MOUSE_IsHidden(); 04230 /* Show only when DOS app is not using mouse */ 04231 04232 #if defined(C_SDL2) 04233 if (!sdl.mouse.locked) 04234 #else 04235 /* SDL1 has some sort of weird mouse warping bug in fullscreen mode no matter whether the mouse is captured or not (Windows, Linux/X11) */ 04236 if (!sdl.mouse.locked && !sdl.desktop.fullscreen) 04237 #endif 04238 SDL_ShowCursor(((!inside) || ((MOUSE_IsHidden()) && !(MOUSE_IsBeingPolled() || MOUSE_HasInterruptSub()))) ? SDL_ENABLE : SDL_DISABLE); 04239 } 04240 Mouse_CursorMoved(xrel, yrel, x, y, emu); 04241 } 04242 04243 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 04244 void MenuFullScreenRedraw(void) { 04245 #if defined(C_SDL2) 04246 SDL_UpdateWindowSurface(sdl.window); 04247 #else 04248 SDL_Flip(sdl.surface); 04249 #endif 04250 } 04251 04252 static struct { 04253 unsigned char* bmp = NULL; 04254 unsigned int stride = 0,height = 0; 04255 } menuSavedScreen; 04256 04257 void MenuSaveScreen(void) { 04258 if (!OpenGL_using()) { 04259 if (menuSavedScreen.bmp == NULL) { 04260 menuSavedScreen.height = (unsigned int)sdl.surface->h; 04261 menuSavedScreen.stride = (unsigned int)sdl.surface->pitch; 04262 menuSavedScreen.bmp = new unsigned char[menuSavedScreen.height * menuSavedScreen.stride]; 04263 } 04264 04265 if (SDL_MUSTLOCK(sdl.surface)) 04266 SDL_LockSurface(sdl.surface); 04267 04268 memcpy(menuSavedScreen.bmp, sdl.surface->pixels, menuSavedScreen.height * menuSavedScreen.stride); 04269 04270 if (SDL_MUSTLOCK(sdl.surface)) 04271 SDL_UnlockSurface(sdl.surface); 04272 } 04273 } 04274 04275 void MenuRestoreScreen(void) { 04276 if (!OpenGL_using()) { 04277 if (menuSavedScreen.bmp == NULL) 04278 return; 04279 04280 if (SDL_MUSTLOCK(sdl.surface)) 04281 SDL_LockSurface(sdl.surface); 04282 04283 memcpy(sdl.surface->pixels, menuSavedScreen.bmp, menuSavedScreen.height * menuSavedScreen.stride); 04284 04285 if (SDL_MUSTLOCK(sdl.surface)) 04286 SDL_UnlockSurface(sdl.surface); 04287 } 04288 } 04289 04290 void MenuFreeScreen(void) { 04291 if (menuSavedScreen.bmp == NULL) 04292 return; 04293 04294 delete[] menuSavedScreen.bmp; 04295 menuSavedScreen.bmp = NULL; 04296 } 04297 #endif 04298 04299 static void HandleMouseButton(SDL_MouseButtonEvent * button, SDL_MouseMotionEvent * motion) { 04300 #if !defined(WIN32) 04301 (void)motion; 04302 #endif 04303 bool inputToScreen = false; 04304 bool inMenu = false; 04305 04306 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW /* SDL drawn menus */ 04307 if (GFX_GetPreventFullscreen()) { 04308 /* do NOT draw SDL menu in OpenGL mode when 3Dfx emulation is using OpenGL */ 04309 mainMenu.menuUserHoverAt = DOSBoxMenu::unassigned_item_handle; 04310 } 04311 else if (!sdl.mouse.locked && !sdl.desktop.fullscreen && mainMenu.isVisible() && button->y < mainMenu.menuBox.h) { 04312 GFX_SDLMenuTrackHover(mainMenu,mainMenu.display_list.itemFromPoint(mainMenu,button->x,button->y)); 04313 inMenu = true; 04314 } 04315 else { 04316 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 04317 } 04318 04319 if (button->button == SDL_BUTTON_LEFT) { 04320 if (button->state == SDL_PRESSED) { 04321 GFX_SDLMenuTrackHilight(mainMenu,mainMenu.menuUserHoverAt); 04322 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) { 04323 std::vector<DOSBoxMenu::item_handle_t> popup_stack; 04324 DOSBoxMenu::item_handle_t choice_item; 04325 DOSBoxMenu::item_handle_t psel_item; 04326 DOSBoxMenu::item_handle_t sel_item; 04327 bool button_holding=true; 04328 bool redrawAll=false; 04329 bool resized=false; 04330 bool runloop=true; 04331 SDL_Rect uprect; 04332 SDL_Event event; 04333 04334 psel_item = DOSBoxMenu::unassigned_item_handle; 04335 choice_item = mainMenu.menuUserHoverAt = mainMenu.menuUserAttentionAt; 04336 04337 popup_stack.push_back(mainMenu.menuUserAttentionAt); 04338 04339 #if C_DIRECT3D 04340 if (sdl.desktop.want_type == SCREEN_DIRECT3D) { 04341 /* In output=direct3d mode, SDL still has a surface but this code ignores SDL 04342 * and draws directly to a Direct3D9 backbuffer which is presented to the window 04343 * client area. However, GDI output to the window still works, and this code 04344 * uses the SDL surface still. Therefore, for menus to draw correctly atop the 04345 * Direct3D output, this code copies the Direct3D backbuffer to the SDL surface 04346 * first. 04347 * 04348 * WARNING: This happens to work with Windows (even Windows 10 build 18xx as of 04349 * 2018/05/21) because Windows appears to permit mixing Direct3D and GDI rendering 04350 * to the window. 04351 * 04352 * Someday, if Microsoft should break that ability, this code will need to be 04353 * revised to send screen "updates" to the Direct3D backbuffer first, then 04354 * Present to the window client area. */ 04355 if (d3d) d3d->UpdateRectToSDLSurface(0, 0, sdl.surface->w, sdl.surface->h); 04356 } 04357 #endif 04358 04359 if (OpenGL_using()) { 04360 #if C_OPENGL 04361 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,false); 04362 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,false); 04363 04364 /* show the menu */ 04365 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,true); 04366 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,true); 04367 04368 glClearColor (0.0, 0.0, 0.0, 1.0); 04369 glClear(GL_COLOR_BUFFER_BIT); 04370 04371 GFX_OpenGLRedrawScreen(); 04372 04373 /* give the menu bar a drop shadow */ 04374 MenuShadeRect( 04375 (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX, 04376 (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h, 04377 (int)mainMenu.menuBox.w, 04378 (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/); 04379 04380 mainMenu.setRedraw(); 04381 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 04382 04383 for (auto i=popup_stack.begin();i!=popup_stack.end();i++) { 04384 if (mainMenu.get_item(*i).get_type() == DOSBoxMenu::submenu_type_id) { 04385 mainMenu.get_item(*i).drawBackground(mainMenu); 04386 mainMenu.get_item(*i).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false); 04387 } 04388 } 04389 04390 # if defined(C_SDL2) 04391 SDL_GL_SwapWindow(sdl.window); 04392 # else 04393 SDL_GL_SwapBuffers(); 04394 # endif 04395 #endif 04396 } 04397 else { 04398 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,false); 04399 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,false); 04400 mainMenu.get_item(mainMenu.menuUserAttentionAt).drawMenuItem(mainMenu); 04401 MenuSaveScreen(); 04402 04403 /* give the menu bar a drop shadow */ 04404 MenuShadeRect( 04405 (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX, 04406 (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h, 04407 (int)mainMenu.menuBox.w, 04408 (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/); 04409 04410 uprect.x = 0; 04411 uprect.y = mainMenu.menuBox.y + mainMenu.menuBox.h; 04412 uprect.w = mainMenu.menuBox.w; 04413 uprect.h = DOSBoxMenu::dropshadowY; 04414 #if defined(C_SDL2) 04415 SDL_UpdateWindowSurfaceRects(sdl.window, &uprect, 1); 04416 #else 04417 SDL_UpdateRects( sdl.surface, 1, &uprect ); 04418 #endif 04419 04420 /* show the menu */ 04421 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHilight(mainMenu,true); 04422 mainMenu.get_item(mainMenu.menuUserAttentionAt).setHover(mainMenu,true); 04423 mainMenu.get_item(mainMenu.menuUserAttentionAt).drawBackground(mainMenu); 04424 mainMenu.get_item(mainMenu.menuUserAttentionAt).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false); 04425 mainMenu.get_item(mainMenu.menuUserAttentionAt).updateScreenFromPopup(mainMenu); 04426 } 04427 04428 /* hack */ 04429 mainMenu.menuUserAttentionAt = DOSBoxMenu::unassigned_item_handle; 04430 04431 /* fall into another loop to process the menu */ 04432 while (runloop) { 04433 #if C_EMSCRIPTEN 04434 emscripten_sleep_with_yield(0); 04435 if (!SDL_PollEvent(&event)) continue; 04436 #else 04437 if (!SDL_WaitEvent(&event)) break; 04438 #endif 04439 04440 #if defined(C_SDL2) && !defined(IGNORE_TOUCHSCREEN) 04441 switch (event.type) { 04442 case SDL_FINGERDOWN: 04443 if (touchscreen_finger_lock == no_finger_id && 04444 touchscreen_touch_lock == no_touch_id) { 04445 touchscreen_finger_lock = event.tfinger.fingerId; 04446 touchscreen_touch_lock = event.tfinger.touchId; 04447 Sint32 x,y; 04448 04449 x = (Sint32)(event.tfinger.x * currentWindowWidth); 04450 y = (Sint32)(event.tfinger.y * currentWindowHeight); 04451 04452 memset(&event.button,0,sizeof(event.button)); 04453 event.type = SDL_MOUSEBUTTONDOWN; 04454 event.button.x = x; 04455 event.button.y = y; 04456 } 04457 else { 04458 event.type = -1; 04459 } 04460 break; 04461 case SDL_FINGERUP: 04462 if (touchscreen_finger_lock == event.tfinger.fingerId && 04463 touchscreen_touch_lock == event.tfinger.touchId) { 04464 touchscreen_finger_lock = no_finger_id; 04465 touchscreen_touch_lock = no_touch_id; 04466 Sint32 x,y; 04467 04468 x = (Sint32)(event.tfinger.x * currentWindowWidth); 04469 y = (Sint32)(event.tfinger.y * currentWindowHeight); 04470 04471 memset(&event.button,0,sizeof(event.button)); 04472 event.type = SDL_MOUSEBUTTONUP; 04473 event.button.x = x; 04474 event.button.y = y; 04475 } 04476 else { 04477 event.type = -1; 04478 } 04479 break; 04480 case SDL_FINGERMOTION: 04481 if (touchscreen_finger_lock == event.tfinger.fingerId && 04482 touchscreen_touch_lock == event.tfinger.touchId) { 04483 Sint32 x,y; 04484 04485 x = (Sint32)(event.tfinger.x * currentWindowWidth); 04486 y = (Sint32)(event.tfinger.y * currentWindowHeight); 04487 04488 memset(&event.button,0,sizeof(event.button)); 04489 event.type = SDL_MOUSEMOTION; 04490 event.button.x = x; 04491 event.button.y = y; 04492 } 04493 else if (touchscreen_finger_lock != no_finger_id || 04494 touchscreen_touch_lock != no_touch_id) { 04495 event.type = -1; 04496 } 04497 break; 04498 } 04499 #endif 04500 04501 switch (event.type) { 04502 case SDL_QUIT: 04503 throw(0); 04504 break; 04505 case SDL_KEYUP: 04506 if (event.key.keysym.sym == SDLK_ESCAPE) { 04507 choice_item = DOSBoxMenu::unassigned_item_handle; 04508 runloop = false; 04509 } 04510 break; 04511 #if defined(C_SDL2) 04512 case SDL_WINDOWEVENT: 04513 switch (event.window.event) { 04514 case SDL_WINDOWEVENT_RESIZED: 04515 GFX_HandleVideoResize(event.window.data1, event.window.data2); 04516 runloop = false; 04517 resized = true; 04518 break; 04519 default: 04520 break; 04521 } 04522 #endif 04523 #if !defined(C_SDL2) 04524 case SDL_VIDEORESIZE: 04525 UpdateWindowDimensions(); // FIXME: Use SDL window dimensions, except that on Windows, SDL won't tell us our actual dimensions 04526 HandleVideoResize(&event.resize); 04527 04528 runloop = false; 04529 resized = true; 04530 break; 04531 #endif 04532 case SDL_MOUSEBUTTONDOWN: 04533 button_holding=true; 04534 choice_item = mainMenu.menuUserHoverAt; 04535 if (choice_item != DOSBoxMenu::unassigned_item_handle) { 04536 DOSBoxMenu::item &item = mainMenu.get_item(choice_item); 04537 item.setHilight(mainMenu,true); 04538 item.drawMenuItem(mainMenu); 04539 if (OpenGL_using()) 04540 redrawAll = true; 04541 else 04542 item.updateScreenFromItem(mainMenu); 04543 } 04544 else { 04545 /* clicking on nothing should dismiss */ 04546 runloop = false; 04547 } 04548 break; 04549 case SDL_MOUSEBUTTONUP: 04550 button_holding=false; 04551 choice_item = mainMenu.menuUserHoverAt; 04552 if (choice_item != DOSBoxMenu::unassigned_item_handle) { 04553 if (choice_item == psel_item) { /* clicking something twice should dismiss */ 04554 runloop = false; 04555 } 04556 else { 04557 DOSBoxMenu::item &item = mainMenu.get_item(choice_item); 04558 if (item.get_type() == DOSBoxMenu::item_type_id && item.is_enabled()) 04559 runloop = false; 04560 } 04561 04562 psel_item = choice_item; 04563 } 04564 else { 04565 /* not selecting anything counts as a reason to exit */ 04566 runloop = false; 04567 } 04568 break; 04569 case SDL_MOUSEMOTION: 04570 { 04571 sel_item = DOSBoxMenu::unassigned_item_handle; 04572 04573 auto search = popup_stack.end(); 04574 if (search != popup_stack.begin()) { 04575 do { 04576 search--; 04577 04578 sel_item = mainMenu.get_item(*search).display_list.itemFromPoint(mainMenu,event.button.x,event.button.y); 04579 if (sel_item != DOSBoxMenu::unassigned_item_handle) { 04580 assert(search != popup_stack.end()); 04581 search++; 04582 break; 04583 } 04584 } while (search != popup_stack.begin()); 04585 } 04586 04587 if (sel_item == DOSBoxMenu::unassigned_item_handle) 04588 sel_item = mainMenu.display_list.itemFromPoint(mainMenu,event.button.x,event.button.y); 04589 04590 /* at this point: 04591 * sel_item = item under cursor, or unassigned if no item 04592 * search = iterator just past the item's level (to remove items if changing) */ 04593 04594 if (mainMenu.menuUserHoverAt != sel_item) { 04595 bool noRedrawNew = false,noRedrawOld = false; 04596 04597 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle) { 04598 mainMenu.get_item(mainMenu.menuUserHoverAt).setHover(mainMenu,false); 04599 if (mainMenu.get_item(mainMenu.menuUserHoverAt).get_type() == DOSBoxMenu::item_type_id) 04600 mainMenu.get_item(mainMenu.menuUserHoverAt).setHilight(mainMenu,false); 04601 else if (mainMenu.get_item(mainMenu.menuUserHoverAt).get_type() == DOSBoxMenu::submenu_type_id) { 04602 if (mainMenu.get_item(mainMenu.menuUserHoverAt).isHilight()) { 04603 noRedrawOld = true; 04604 } 04605 } 04606 } 04607 04608 if (sel_item != DOSBoxMenu::unassigned_item_handle) { 04609 if (mainMenu.get_item(sel_item).get_type() == DOSBoxMenu::submenu_type_id) { 04610 if (!mainMenu.get_item(sel_item).isHilight()) { 04611 /* use a copy of the iterator to scan forward and un-hilight the menu items. 04612 * then use the original iterator to erase from the vector. */ 04613 for (auto ss=search;ss != popup_stack.end();ss++) { 04614 for (auto &id : mainMenu.get_item(*ss).display_list.get_disp_list()) 04615 mainMenu.get_item(id).setHilight(mainMenu,false).setHover(mainMenu,false); 04616 04617 mainMenu.get_item(*ss).setHilight(mainMenu,false).setHover(mainMenu,false); 04618 } 04619 04620 popup_stack.erase(search,popup_stack.end()); 04621 mainMenu.get_item(sel_item).setHilight(mainMenu,true).setHover(mainMenu,true); 04622 popup_stack.push_back(sel_item); 04623 redrawAll = true; 04624 } 04625 else { 04626 /* no change in item state, don't bother redrawing */ 04627 noRedrawNew = true; 04628 } 04629 } 04630 else { 04631 /* use a copy of the iterator to scan forward and un-hilight the menu items. 04632 * then use the original iterator to erase from the vector. */ 04633 for (auto ss=search;ss != popup_stack.end();ss++) { 04634 for (auto &id : mainMenu.get_item(*ss).display_list.get_disp_list()) 04635 mainMenu.get_item(id).setHilight(mainMenu,false).setHover(mainMenu,false); 04636 04637 mainMenu.get_item(*ss).setHilight(mainMenu,false).setHover(mainMenu,false); 04638 redrawAll = true; 04639 } 04640 04641 popup_stack.erase(search,popup_stack.end()); 04642 } 04643 04644 if (OpenGL_using()) 04645 redrawAll = true; 04646 04647 mainMenu.get_item(sel_item).setHover(mainMenu,true); 04648 if (mainMenu.get_item(sel_item).get_type() == DOSBoxMenu::item_type_id && button_holding) 04649 mainMenu.get_item(sel_item).setHilight(mainMenu,true); 04650 } 04651 else { 04652 if (OpenGL_using()) 04653 redrawAll = true; 04654 } 04655 04656 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle && !OpenGL_using() && !redrawAll && !noRedrawOld) { 04657 if (mainMenu.get_item(mainMenu.menuUserHoverAt).checkResetRedraw()) { 04658 mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu); 04659 mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu); 04660 } 04661 } 04662 04663 mainMenu.menuUserHoverAt = sel_item; 04664 04665 if (mainMenu.menuUserHoverAt != DOSBoxMenu::unassigned_item_handle && !OpenGL_using() && !redrawAll && !noRedrawNew) { 04666 if (mainMenu.get_item(mainMenu.menuUserHoverAt).checkResetRedraw()) { 04667 mainMenu.get_item(mainMenu.menuUserHoverAt).drawMenuItem(mainMenu); 04668 mainMenu.get_item(mainMenu.menuUserHoverAt).updateScreenFromItem(mainMenu); 04669 } 04670 } 04671 } 04672 } 04673 break; 04674 } 04675 04676 if (redrawAll) { 04677 redrawAll = false; 04678 04679 #if 0/*DEBUG*/ 04680 LOG_MSG("Redraw %u",(unsigned int)SDL_GetTicks()); 04681 #endif 04682 04683 if (OpenGL_using()) { 04684 #if C_OPENGL 04685 glClearColor (0.0, 0.0, 0.0, 1.0); 04686 glClear(GL_COLOR_BUFFER_BIT); 04687 04688 GFX_OpenGLRedrawScreen(); 04689 04690 mainMenu.setRedraw(); 04691 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 04692 #endif 04693 } 04694 else { 04695 MenuRestoreScreen(); 04696 mainMenu.display_list.DrawDisplayList(mainMenu,/*updateScreen*/false); 04697 } 04698 04699 /* give the menu bar a drop shadow */ 04700 MenuShadeRect( 04701 (int)mainMenu.menuBox.x + (int)DOSBoxMenu::dropshadowX, 04702 (int)mainMenu.menuBox.y + (int)mainMenu.menuBox.h, 04703 (int)mainMenu.menuBox.w, 04704 (int)DOSBoxMenu::dropshadowY - 1/*menubar border*/); 04705 04706 for (auto i=popup_stack.begin();i!=popup_stack.end();i++) { 04707 if (mainMenu.get_item(*i).get_type() == DOSBoxMenu::submenu_type_id) { 04708 mainMenu.get_item(*i).drawBackground(mainMenu); 04709 mainMenu.get_item(*i).display_list.DrawDisplayList(mainMenu,/*updateScreen*/false); 04710 } 04711 } 04712 04713 #if C_OPENGL 04714 if (OpenGL_using()) { 04715 # if defined(C_SDL2) 04716 SDL_GL_SwapWindow(sdl.window); 04717 # else 04718 SDL_GL_SwapBuffers(); 04719 # endif 04720 } 04721 else 04722 #endif 04723 MenuFullScreenRedraw(); 04724 } 04725 } 04726 04727 #if defined(C_SDL2) 04728 /* force touchscreen mapping to let go */ 04729 touchscreen_finger_lock = no_finger_id; 04730 touchscreen_touch_lock = no_touch_id; 04731 #endif 04732 04733 /* then return */ 04734 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 04735 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 04736 if (!resized) { 04737 MenuRestoreScreen(); 04738 if (!OpenGL_using()) 04739 MenuFullScreenRedraw(); 04740 } 04741 MenuFreeScreen(); 04742 04743 while (!popup_stack.empty()) { 04744 DOSBoxMenu::item &item = mainMenu.get_item(popup_stack.back()); 04745 04746 for (auto &id : item.display_list.get_disp_list()) { 04747 mainMenu.get_item(id).setHilight(mainMenu,false); 04748 mainMenu.get_item(id).setHover(mainMenu,false); 04749 } 04750 04751 item.setHilight(mainMenu,false); 04752 item.setHover(mainMenu,false); 04753 popup_stack.pop_back(); 04754 } 04755 04756 if (OpenGL_using()) { 04757 #if C_OPENGL 04758 glClearColor (0.0, 0.0, 0.0, 1.0); 04759 glClear(GL_COLOR_BUFFER_BIT); 04760 04761 GFX_OpenGLRedrawScreen(); 04762 04763 mainMenu.setRedraw(); 04764 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 04765 04766 # if defined(C_SDL2) 04767 SDL_GL_SwapWindow(sdl.window); 04768 # else 04769 SDL_GL_SwapBuffers(); 04770 # endif 04771 04772 sdl_opengl.clear_countdown = 2; 04773 sdl_opengl.menudraw_countdown = 2; // two GL buffers 04774 #endif 04775 } 04776 04777 /* action! */ 04778 if (!resized && choice_item != DOSBoxMenu::unassigned_item_handle) { 04779 DOSBoxMenu::item &item = mainMenu.get_item(choice_item); 04780 04781 if (item.get_type() == DOSBoxMenu::item_type_id && item.is_enabled()) 04782 mainMenu.dispatchItemCommand(item); 04783 } 04784 04785 return; 04786 } 04787 } 04788 else { 04789 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 04790 } 04791 } 04792 #endif 04793 04794 /* limit mouse input to whenever the cursor is on the screen, or near the edge of the screen. */ 04795 if (is_paused) 04796 inputToScreen = false; 04797 else if (sdl.mouse.locked) 04798 inputToScreen = true; 04799 else if (!inMenu) 04800 inputToScreen = GFX_CursorInOrNearScreen(button->x, button->y); 04801 04802 switch (button->state) { 04803 case SDL_PRESSED: 04804 if (inMenu || !inputToScreen) return; 04805 #if defined(WIN32) 04806 if (!sdl.mouse.locked && button->button == SDL_BUTTON_LEFT && !strcmp(modifier,"none") && mouse_start_x >= 0 && mouse_start_y >= 0 && fx >= 0 && fy >= 0) { 04807 Restore_Text(mouse_start_x-sdl.clip.x,mouse_start_y-sdl.clip.y,fx-sdl.clip.x,fy-sdl.clip.y,(int)(currentWindowWidth-sdl.clip.x),(int)(currentWindowHeight-sdl.clip.y)); 04808 mouse_start_x = -1; 04809 mouse_start_y = -1; 04810 mouse_end_x = -1; 04811 mouse_end_y = -1; 04812 fx = -1; 04813 fy = -1; 04814 } 04815 if (!sdl.mouse.locked && button->button == SDL_BUTTON_RIGHT && (!strcmp(modifier,"none") 04816 || (!strcmp(modifier,"alt") || !strcmp(modifier,"lalt")) && sdl.laltstate==SDL_KEYDOWN || (!strcmp(modifier,"alt") || !strcmp(modifier,"ralt")) && sdl.raltstate==SDL_KEYDOWN 04817 || (!strcmp(modifier,"ctrl") || !strcmp(modifier,"lctrl")) && sdl.lctrlstate==SDL_KEYDOWN || (!strcmp(modifier,"ctrl") || !strcmp(modifier,"rctrl")) && sdl.rctrlstate==SDL_KEYDOWN 04818 || (!strcmp(modifier,"shift") || !strcmp(modifier,"lshift")) && sdl.lshiftstate==SDL_KEYDOWN || (!strcmp(modifier,"shift") || !strcmp(modifier,"rshift")) && sdl.rshiftstate==SDL_KEYDOWN 04819 )) { 04820 mouse_start_x=motion->x; 04821 mouse_start_y=motion->y; 04822 break; 04823 } else 04824 #endif 04825 if (sdl.mouse.requestlock && !sdl.mouse.locked && mouse_notify_mode == 0) { 04826 CaptureMouseNotify(); 04827 GFX_CaptureMouse(); 04828 // Don't pass click to mouse handler 04829 break; 04830 } 04831 if (!sdl.mouse.autoenable && sdl.mouse.autolock && mouse_notify_mode == 0 && button->button == SDL_BUTTON_MIDDLE) { 04832 GFX_CaptureMouse(); 04833 break; 04834 } 04835 switch (button->button) { 04836 case SDL_BUTTON_LEFT: 04837 Mouse_ButtonPressed(0); 04838 break; 04839 case SDL_BUTTON_RIGHT: 04840 Mouse_ButtonPressed(1); 04841 break; 04842 case SDL_BUTTON_MIDDLE: 04843 Mouse_ButtonPressed(2); 04844 break; 04845 #if !defined(C_SDL2) 04846 case SDL_BUTTON_WHEELUP: /* Ick, really SDL? */ 04847 if (wheel_key) { 04848 #if defined(WIN32) && !defined(HX_DOS) 04849 INPUT ip = {0}; 04850 ip.type = INPUT_KEYBOARD; 04851 ip.ki.wScan = wheel_key==2?75:(wheel_key==3?73:72); 04852 ip.ki.time = 0; 04853 ip.ki.dwExtraInfo = 0; 04854 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY; 04855 SendInput(1, &ip, sizeof(INPUT)); 04856 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY; 04857 SendInput(1, &ip, sizeof(INPUT)); 04858 #else 04859 std::vector<std::string> sequence; 04860 sequence.push_back(std::string(wheel_key==2?"left":(wheel_key==3?"pageup":"up"))); 04861 MAPPER_AutoType(sequence, 1/*ms*/, 0); 04862 #endif 04863 } else 04864 Mouse_ButtonPressed(100-1); 04865 break; 04866 case SDL_BUTTON_WHEELDOWN: /* Ick, really SDL? */ 04867 if (wheel_key) { 04868 #if defined(WIN32) && !defined(HX_DOS) 04869 INPUT ip = {0}; 04870 ip.type = INPUT_KEYBOARD; 04871 ip.ki.wScan = wheel_key==2?77:(wheel_key==3?81:80); 04872 ip.ki.time = 0; 04873 ip.ki.dwExtraInfo = 0; 04874 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY; 04875 SendInput(1, &ip, sizeof(INPUT)); 04876 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY; 04877 SendInput(1, &ip, sizeof(INPUT)); 04878 #else 04879 std::vector<std::string> sequence; 04880 sequence.push_back(std::string(wheel_key==2?"right":(wheel_key==3?"pagedown":"down"))); 04881 MAPPER_AutoType(sequence, 1/*ms*/, 0); 04882 #endif 04883 } else 04884 Mouse_ButtonPressed(100+1); 04885 break; 04886 #endif 04887 } 04888 break; 04889 case SDL_RELEASED: 04890 #if defined(WIN32) 04891 if (!sdl.mouse.locked && button->button == SDL_BUTTON_RIGHT && mouse_start_x >= 0 && mouse_start_y >= 0) { 04892 mouse_end_x=motion->x; 04893 mouse_end_y=motion->y; 04894 if (mouse_start_x == mouse_end_x && mouse_start_y == mouse_end_y) 04895 PasteClipboard(true); 04896 else { 04897 if (fx >= 0 && fy >= 0) 04898 Restore_Text(mouse_start_x-sdl.clip.x,mouse_start_y-sdl.clip.y,fx-sdl.clip.x,fy-sdl.clip.y,(int)(currentWindowWidth-sdl.clip.x),(int)(currentWindowHeight-sdl.clip.y)); 04899 if (abs(mouse_end_x - mouse_start_x) + abs(mouse_end_y - mouse_start_y)<5) { 04900 PasteClipboard(true); 04901 } else 04902 CopyClipboard(); 04903 } 04904 mouse_start_x = -1; 04905 mouse_start_y = -1; 04906 mouse_end_x = -1; 04907 mouse_end_y = -1; 04908 fx = -1; 04909 fy = -1; 04910 break; 04911 } 04912 #endif 04913 switch (button->button) { 04914 case SDL_BUTTON_LEFT: 04915 Mouse_ButtonReleased(0); 04916 break; 04917 case SDL_BUTTON_RIGHT: 04918 Mouse_ButtonReleased(1); 04919 break; 04920 case SDL_BUTTON_MIDDLE: 04921 Mouse_ButtonReleased(2); 04922 break; 04923 #if !defined(C_SDL2) 04924 case SDL_BUTTON_WHEELUP: /* Ick, really SDL? */ 04925 Mouse_ButtonReleased(100-1); 04926 break; 04927 case SDL_BUTTON_WHEELDOWN: /* Ick, really SDL? */ 04928 Mouse_ButtonReleased(100+1); 04929 break; 04930 #endif 04931 } 04932 break; 04933 } 04934 } 04935 04936 void GFX_LosingFocus(void) { 04937 sdl.laltstate=SDL_KEYUP; 04938 sdl.raltstate=SDL_KEYUP; 04939 sdl.lctrlstate=SDL_KEYUP; 04940 sdl.rctrlstate=SDL_KEYUP; 04941 sdl.lshiftstate=SDL_KEYUP; 04942 sdl.rshiftstate=SDL_KEYUP; 04943 MAPPER_LosingFocus(); 04944 DoExtendedKeyboardHook(false); 04945 } 04946 04947 static bool PasteClipboardNext(); // added emendelson from dbDOS 04948 04949 bool GFX_IsFullscreen(void) { 04950 return sdl.desktop.fullscreen; 04951 } 04952 04953 void* GetSetSDLValue(int isget, std::string& target, void* setval) { 04954 if (target == "wait_on_error") { 04955 if (isget) return (void*) sdl.wait_on_error; 04956 else sdl.wait_on_error = setval; 04957 } 04958 else if (target == "opengl.bilinear") { 04959 #if C_OPENGL 04960 if (isget) return (void*) sdl_opengl.bilinear; 04961 else sdl_opengl.bilinear = setval; 04962 #else 04963 if (isget) return (void*) 0; 04964 #endif 04965 /* 04966 } else if (target == "draw.callback") { 04967 if (isget) return (void*) sdl.draw.callback; 04968 else sdl.draw.callback = *static_cast<GFX_CallBack_t*>(setval); 04969 } else if (target == "desktop.full.width") { 04970 if (isget) return (void*) sdl.desktop.full.width; 04971 else sdl.desktop.full.width = *static_cast<Bit16u*>(setval); 04972 } else if (target == "desktop.full.height") { 04973 if (isget) return (void*) sdl.desktop.full.height; 04974 else sdl.desktop.full.height = *static_cast<Bit16u*>(setval); 04975 } else if (target == "desktop.full.fixed") { 04976 if (isget) return (void*) sdl.desktop.full.fixed; 04977 else sdl.desktop.full.fixed = setval; 04978 } else if (target == "desktop.window.width") { 04979 if (isget) return (void*) sdl.desktop.window.width; 04980 else sdl.desktop.window.width = *static_cast<Bit16u*>(setval); 04981 } else if (target == "desktop.window.height") { 04982 if (isget) return (void*) sdl.desktop.window.height; 04983 else sdl.desktop.window.height = *static_cast<Bit16u*>(setval); 04984 */ 04985 } else if (target == "desktop.fullscreen") { 04986 if (isget) return (void*) sdl.desktop.fullscreen; 04987 else sdl.desktop.fullscreen = setval; 04988 } else if (target == "desktop.doublebuf") { 04989 if (isget) return (void*) sdl.desktop.doublebuf; 04990 else sdl.desktop.doublebuf = setval; 04991 /* 04992 } else if (target == "desktop.type") { 04993 if (isget) return (void*) sdl.desktop.type; 04994 else sdl.desktop.type = *static_cast<SCREEN_TYPES*>(setval); 04995 */ 04996 } else if (target == "desktop.want_type") { 04997 if (isget) return (void*) sdl.desktop.want_type; 04998 else sdl.desktop.want_type = *static_cast<SCREEN_TYPES*>(setval); 04999 /* 05000 } else if (target == "surface") { 05001 if (isget) return (void*) sdl.surface; 05002 else sdl.surface = static_cast<SDL_Surface*>(setval); 05003 } else if (target == "overlay") { 05004 if (isget) return (void*) sdl.overlay; 05005 else sdl.overlay = static_cast<SDL_Overlay*>(setval); 05006 */ 05007 } else if (target == "mouse.autoenable") { 05008 if (isget) return (void*) sdl.mouse.autoenable; 05009 else sdl.mouse.autoenable = setval; 05010 /* 05011 } else if (target == "overscan_width") { 05012 if (isget) return (void*) sdl.overscan_width; 05013 else sdl.overscan_width = *static_cast<Bitu*>(setval); 05014 */ 05015 #if defined (WIN32) 05016 } else if (target == "using_windib") { 05017 if (isget) return (void*) sdl.using_windib; 05018 else sdl.using_windib = setval; 05019 #endif 05020 } 05021 05022 return NULL; 05023 } 05024 05025 #if defined(C_SDL2) && !defined(IGNORE_TOUCHSCREEN) 05026 static void FingerToFakeMouseMotion(SDL_TouchFingerEvent * finger) { 05027 SDL_MouseMotionEvent fake; 05028 05029 memset(&fake,0,sizeof(fake)); 05030 /* NTS: Windows versions of SDL2 do normalize the coordinates */ 05031 fake.x = (Sint32)(finger->x * currentWindowWidth); 05032 fake.y = (Sint32)(finger->y * currentWindowHeight); 05033 fake.xrel = (Sint32)finger->dx; 05034 fake.yrel = (Sint32)finger->dy; 05035 HandleMouseMotion(&fake); 05036 05037 if (finger->type == SDL_FINGERDOWN || finger->type == SDL_FINGERUP) { 05038 SDL_MouseButtonEvent fakeb; 05039 05040 memset(&fakeb,0,sizeof(fakeb)); 05041 05042 fakeb.state = (finger->type == SDL_FINGERDOWN) ? SDL_PRESSED : SDL_RELEASED; 05043 fakeb.button = SDL_BUTTON_LEFT; 05044 fakeb.x = fake.x; 05045 fakeb.y = fake.y; 05046 HandleMouseButton(&fakeb,&fake); 05047 } 05048 } 05049 05050 static void HandleTouchscreenFinger(SDL_TouchFingerEvent * finger) { 05051 /* Now that SDL2 can tell my mouse from my laptop touchscreen, let's 05052 * map tap events to the left mouse button. Now I can use my laptop 05053 * touchscreen with Windows 3.11 again! --J.C. */ 05054 /* Now let's handle The Finger (har har) */ 05055 05056 /* NTS: This code is written to map ONLY one finger to the mouse. 05057 * If multiple fingers are touching the screen, this code will 05058 * only respond to the first finger that touched the screen. */ 05059 05060 if (finger->type == SDL_FINGERDOWN) { 05061 if (touchscreen_finger_lock == no_finger_id && 05062 touchscreen_touch_lock == no_touch_id) { 05063 touchscreen_finger_lock = finger->fingerId; 05064 touchscreen_touch_lock = finger->touchId; 05065 FingerToFakeMouseMotion(finger); 05066 } 05067 } 05068 else if (finger->type == SDL_FINGERUP) { 05069 if (touchscreen_finger_lock == finger->fingerId && 05070 touchscreen_touch_lock == finger->touchId) { 05071 touchscreen_finger_lock = no_finger_id; 05072 touchscreen_touch_lock = no_touch_id; 05073 FingerToFakeMouseMotion(finger); 05074 } 05075 } 05076 else if (finger->type == SDL_FINGERMOTION) { 05077 if (touchscreen_finger_lock == finger->fingerId && 05078 touchscreen_touch_lock == finger->touchId) { 05079 FingerToFakeMouseMotion(finger); 05080 } 05081 } 05082 } 05083 #endif 05084 05085 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 05086 void MSG_WM_COMMAND_handle(SDL_SysWMmsg &Message); 05087 #endif 05088 05089 struct mouse_pos 05090 { 05091 long x = 0; 05092 long y = 0; 05093 } mouse_pos; 05094 05095 bool mouse_inside = false; 05096 05097 void GFX_EventsMouseProcess(const long x, const long y, const long rx, const long ry) 05098 { 05099 const auto x1 = sdl.clip.x; 05100 const auto x2 = x1 + sdl.clip.w - 1; 05101 const auto y1 = sdl.clip.y; 05102 const auto y2 = y1 + sdl.clip.h - 1; 05103 const auto in = x >= x1 && x <= x2 && y >= y1 && y <= y2; 05104 05105 if (mouse_inside && !in) 05106 { 05107 const auto x3 = max((int)x1, min((int)x2, (int)x)); 05108 const auto y3 = max((int)y1, min((int)y2, (int)y)); 05109 SDL_Event evt; 05110 evt.type = SDL_MOUSEMOTION; 05111 evt.motion.state = 0; 05112 evt.motion.which = 0; 05113 evt.motion.x = x3; 05114 evt.motion.y = y3; 05115 evt.motion.xrel = (Sint16)((rx >= 0) ? min(rx, 32767l) : max(rx, -32768l)); 05116 evt.motion.yrel = (Sint16)((ry >= 0) ? min(ry, 32767l) : max(ry, -32768l)); 05117 SDL_PushEvent(&evt); 05118 } 05119 05120 mouse_inside = in; 05121 } 05122 05123 #if defined(WIN32) 05124 void GFX_EventsMouseWin32() 05125 { 05126 /* Compute relative mouse movement */ 05127 05128 POINT point; 05129 05130 if (!GetCursorPos(&point)) 05131 return; 05132 05133 const auto hwnd = GetSurfaceHWND(); 05134 05135 if (hwnd == nullptr || !ScreenToClient(hwnd, &point)) 05136 return; 05137 05138 const auto x = point.x; 05139 const auto y = point.y; 05140 const auto rx = x - mouse_pos.x; 05141 const auto ry = y - mouse_pos.y; 05142 05143 mouse_pos.x = x; 05144 mouse_pos.y = y; 05145 05146 /* Let the method do the heavy uplifting */ 05147 GFX_EventsMouseProcess(x, y, rx, ry); 05148 } 05149 #endif 05150 05157 void GFX_EventsMouse() 05158 { 05159 if (sdl.desktop.fullscreen || sdl.mouse.locked) 05160 return; 05161 05162 #if WIN32 05163 GFX_EventsMouseWin32(); 05164 #else 05165 // TODO 05166 #endif 05167 } 05168 05169 /* DOSBox SVN revision 4176:4177: For Linux/X11, Xorg 1.20.1 05170 * will make spurious focus gain and loss events when locking the mouse in windowed mode. 05171 * 05172 * This has not been tested with DOSBox-X yet becaus I do not run Xorg 1.20.1, yet */ 05173 #if defined(LINUX) 05174 #define SDL_XORG_FIX 1 05175 #else 05176 #define SDL_XORG_FIX 0 05177 #endif 05178 /* end patch fragment */ 05179 05180 bool gfx_in_mapper = false; 05181 05182 #if defined(MACOSX) 05183 #define DB_POLLSKIP 3 05184 #else 05185 //Not used yet, see comment below 05186 #define DB_POLLSKIP 1 05187 #endif 05188 05189 void GFX_Events() { 05190 CheckMapperKeyboardLayout(); 05191 #if defined(C_SDL2) /* SDL 2.x---------------------------------- */ 05192 //Don't poll too often. This can be heavy on the OS, especially Macs. 05193 //In idle mode 3000-4000 polls are done per second without this check. 05194 //Macs, with this code, max 250 polls per second. (non-macs unused default max 500) 05195 //Currently not implemented for all platforms, given the ALT-TAB stuff for WIN32. 05196 #if defined (MACOSX) 05197 static int last_check = 0; 05198 int current_check = GetTicks(); 05199 if (current_check - last_check <= DB_POLLSKIP) return; 05200 last_check = current_check; 05201 #endif 05202 05203 SDL_Event event; 05204 #if defined (REDUCE_JOYSTICK_POLLING) 05205 static int poll_delay = 0; 05206 int time = GetTicks(); 05207 if (time - poll_delay > 20) { 05208 poll_delay = time; 05209 if (sdl.num_joysticks > 0) 05210 { 05211 SDL_JoystickUpdate(); 05212 MAPPER_UpdateJoysticks(); 05213 } 05214 } 05215 #endif 05216 05217 GFX_EventsMouse(); 05218 05219 #if C_EMSCRIPTEN 05220 emscripten_sleep_with_yield(0); 05221 #endif 05222 05223 while (SDL_PollEvent(&event)) { 05224 switch (event.type) { 05225 case SDL_WINDOWEVENT: 05226 switch (event.window.event) { 05227 case SDL_WINDOWEVENT_RESTORED: 05228 GFX_ResetScreen(); 05229 continue; 05230 case SDL_WINDOWEVENT_RESIZED: 05231 GFX_HandleVideoResize(event.window.data1, event.window.data2); 05232 continue; 05233 case SDL_WINDOWEVENT_EXPOSED: 05234 if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw ); 05235 continue; 05236 case SDL_WINDOWEVENT_LEAVE: 05237 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 05238 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05239 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05240 05241 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 05242 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 05243 05244 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 05245 #endif 05246 break; 05247 case SDL_WINDOWEVENT_FOCUS_GAINED: 05248 if (IsFullscreen() && !sdl.mouse.locked) 05249 GFX_CaptureMouse(); 05250 SetPriority(sdl.priority.focus); 05251 CPU_Disable_SkipAutoAdjust(); 05252 break; 05253 case SDL_WINDOWEVENT_FOCUS_LOST: 05254 if (sdl.mouse.locked) { 05255 CaptureMouseNotify(); 05256 GFX_CaptureMouse(); 05257 } 05258 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 05259 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05260 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05261 05262 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 05263 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 05264 05265 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 05266 #endif 05267 SetPriority(sdl.priority.nofocus); 05268 GFX_LosingFocus(); 05269 CPU_Enable_SkipAutoAdjust(); 05270 break; 05271 default: 05272 ; 05273 } 05274 05275 /* Non-focus priority is set to pause; check to see if we've lost window or input focus 05276 * i.e. has the window been minimised or made inactive? 05277 */ 05278 if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) { 05279 if ((event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (event.window.event == SDL_WINDOWEVENT_MINIMIZED)) { 05280 /* Window has lost focus, pause the emulator. 05281 * This is similar to what PauseDOSBox() does, but the exit criteria is different. 05282 * Instead of waiting for the user to hit Alt-Break, we wait for the window to 05283 * regain window or input focus. 05284 */ 05285 bool paused = true; 05286 SDL_Event ev; 05287 05288 GFX_SetTitle(-1,-1,-1,true); 05289 KEYBOARD_ClrBuffer(); 05290 // SDL_Delay(500); 05291 // while (SDL_PollEvent(&ev)) { 05292 // flush event queue. 05293 // } 05294 05295 while (paused) { 05296 #if C_EMSCRIPTEN 05297 emscripten_sleep_with_yield(0); 05298 SDL_PollEvent(&ev); 05299 #else 05300 // WaitEvent waits for an event rather than polling, so CPU usage drops to zero 05301 SDL_WaitEvent(&ev); 05302 #endif 05303 05304 switch (ev.type) { 05305 case SDL_QUIT: 05306 throw(0); 05307 break; // a bit redundant at linux at least as the active events gets before the quit event. 05308 case SDL_WINDOWEVENT: // wait until we get window focus back 05309 if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_LOST) || (ev.window.event == SDL_WINDOWEVENT_MINIMIZED) || (ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) { 05310 // We've got focus back, so unpause and break out of the loop 05311 if ((ev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) || (ev.window.event == SDL_WINDOWEVENT_RESTORED) || (ev.window.event == SDL_WINDOWEVENT_EXPOSED)) { 05312 paused = false; 05313 GFX_SetTitle(-1,-1,-1,false); 05314 } 05315 05316 /* Now poke a "release ALT" command into the keyboard buffer 05317 * we have to do this, otherwise ALT will 'stick' and cause 05318 * problems with the app running in the DOSBox-X. 05319 */ 05320 KEYBOARD_AddKey(KBD_leftalt, false); 05321 KEYBOARD_AddKey(KBD_rightalt, false); 05322 if (ev.window.event == SDL_WINDOWEVENT_RESTORED) { 05323 // We may need to re-create a texture and more 05324 GFX_ResetScreen(); 05325 } 05326 } 05327 break; 05328 } 05329 } 05330 } 05331 } 05332 break; 05333 case SDL_MOUSEMOTION: 05334 #if defined(C_SDL2) 05335 if (touchscreen_finger_lock == no_finger_id && 05336 touchscreen_touch_lock == no_touch_id && 05337 event.motion.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */ 05338 HandleMouseMotion(&event.motion); 05339 } 05340 #else 05341 HandleMouseMotion(&event.motion); 05342 #endif 05343 break; 05344 case SDL_MOUSEBUTTONDOWN: 05345 case SDL_MOUSEBUTTONUP: 05346 #if defined(C_SDL2) 05347 if (touchscreen_finger_lock == no_finger_id && 05348 touchscreen_touch_lock == no_touch_id && 05349 event.button.which != SDL_TOUCH_MOUSEID) { /* don't handle mouse events faked by touchscreen */ 05350 HandleMouseButton(&event.button,&event.motion); 05351 } 05352 #else 05353 HandleMouseButton(&event.button,&event.motion); 05354 #endif 05355 break; 05356 #if !defined(IGNORE_TOUCHSCREEN) 05357 case SDL_FINGERDOWN: 05358 case SDL_FINGERUP: 05359 case SDL_FINGERMOTION: 05360 HandleTouchscreenFinger(&event.tfinger); 05361 break; 05362 #endif 05363 case SDL_QUIT: 05364 throw(0); 05365 break; 05366 case SDL_MOUSEWHEEL: 05367 if (wheel_key) { 05368 if(event.wheel.y > 0) { 05369 #if defined (WIN32) && !defined(HX_DOS) 05370 INPUT ip = {0}; 05371 ip.type = INPUT_KEYBOARD; 05372 ip.ki.wScan = wheel_key==2?75:(wheel_key==3?73:72); 05373 ip.ki.time = 0; 05374 ip.ki.dwExtraInfo = 0; 05375 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY; 05376 SendInput(1, &ip, sizeof(INPUT)); 05377 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY; 05378 SendInput(1, &ip, sizeof(INPUT)); 05379 #else 05380 std::vector<std::string> sequence; 05381 sequence.push_back(std::string(wheel_key==2?"left":(wheel_key==3?"pageup":"up"))); 05382 MAPPER_AutoType(sequence, 1/*ms*/, 0); 05383 #endif 05384 } else if(event.wheel.y < 0) { 05385 #if defined (WIN32) && !defined(HX_DOS) 05386 INPUT ip = {0}; 05387 ip.type = INPUT_KEYBOARD; 05388 ip.ki.wScan = wheel_key==2?77:(wheel_key==3?81:80); 05389 ip.ki.time = 0; 05390 ip.ki.dwExtraInfo = 0; 05391 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_EXTENDEDKEY; 05392 SendInput(1, &ip, sizeof(INPUT)); 05393 ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY; 05394 SendInput(1, &ip, sizeof(INPUT)); 05395 #else 05396 std::vector<std::string> sequence; 05397 sequence.push_back(std::string(wheel_key==2?"right":(wheel_key==3?"pagedown":"down"))); 05398 MAPPER_AutoType(sequence, 1/*ms*/, 0); 05399 #endif 05400 } 05401 } 05402 break; 05403 #if defined (WIN32) 05404 case SDL_KEYDOWN: 05405 case SDL_KEYUP: 05406 if (event.key.keysym.sym==SDLK_LALT) sdl.laltstate = event.key.type; 05407 if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type; 05408 if (event.key.keysym.sym==SDLK_LCTRL) sdl.lctrlstate = event.key.type; 05409 if (event.key.keysym.sym==SDLK_RCTRL) sdl.rctrlstate = event.key.type; 05410 if (event.key.keysym.sym==SDLK_LSHIFT) sdl.lshiftstate = event.key.type; 05411 if (event.key.keysym.sym==SDLK_RSHIFT) sdl.rshiftstate = event.key.type; 05412 #endif 05413 #if defined (MACOSX) 05414 case SDL_KEYDOWN: 05415 case SDL_KEYUP: 05416 /* On macs CMD-Q is the default key to close an application */ 05417 if (event.key.keysym.sym == SDLK_q && 05418 (event.key.keysym.mod == KMOD_RGUI || 05419 event.key.keysym.mod == KMOD_LGUI) 05420 ) { 05421 KillSwitch(true); 05422 break; 05423 } 05424 #endif 05425 default: 05426 gfx_in_mapper = true; 05427 void MAPPER_CheckEvent(SDL_Event * event); 05428 MAPPER_CheckEvent(&event); 05429 gfx_in_mapper = false; 05430 } 05431 } 05432 #else /* SDL 1.x---------------------------------- */ 05433 SDL_Event event; 05434 #if defined (REDUCE_JOYSTICK_POLLING) 05435 static uint32_t poll_delay=0; 05436 uint32_t time=GetTicks(); 05437 if ((int32_t)(time-poll_delay)>20) { 05438 poll_delay=time; 05439 if (sdl.num_joysticks>0) 05440 { 05441 SDL_JoystickUpdate(); 05442 MAPPER_UpdateJoysticks(); 05443 } 05444 } 05445 #endif 05446 05447 GFX_EventsMouse(); 05448 05449 #if C_EMSCRIPTEN 05450 emscripten_sleep_with_yield(0); 05451 #endif 05452 05453 while (SDL_PollEvent(&event)) { 05454 /* DOSBox SVN revision 4176:4177: For Linux/X11, Xorg 1.20.1 05455 * will make spurious focus gain and loss events when locking the mouse in windowed mode. 05456 * 05457 * This has not been tested with DOSBox-X yet becaus I do not run Xorg 1.20.1, yet */ 05458 #if SDL_XORG_FIX 05459 // Special code for broken SDL with Xorg 1.20.1, where pairs of inputfocus gain and loss events are generated 05460 // when locking the mouse in windowed mode. 05461 if (event.type == SDL_ACTIVEEVENT && event.active.state == SDL_APPINPUTFOCUS && event.active.gain == 0) { 05462 SDL_Event test; //Check if the next event would undo this one. 05463 if (SDL_PeepEvents(&test,1,SDL_PEEKEVENT,SDL_ACTIVEEVENTMASK) == 1 && test.active.state == SDL_APPINPUTFOCUS && test.active.gain == 1) { 05464 // Skip both events. 05465 SDL_PeepEvents(&test,1,SDL_GETEVENT,SDL_ACTIVEEVENTMASK); 05466 continue; 05467 } 05468 } 05469 #endif 05470 /* end patch fragment */ 05471 05472 switch (event.type) { 05473 #ifdef __WIN32__ 05474 case SDL_SYSWMEVENT : { 05475 switch( event.syswm.msg->msg ) { 05476 #if !defined(HX_DOS) 05477 case WM_COMMAND: 05478 MSG_WM_COMMAND_handle(/*&*/(*event.syswm.msg)); 05479 break; 05480 #endif 05481 case WM_SYSCOMMAND: 05482 switch (event.syswm.msg->wParam) { 05483 case 0xF032: // FIXME: What is this? 05484 case SC_MAXIMIZE: 05485 userResizeWindowWidth = 0; 05486 userResizeWindowHeight = 0; 05487 menu.maxwindow = true; 05488 break; 05489 case 0xF122: // FIXME: What is this? 05490 case SC_RESTORE: 05491 if (sdl.desktop.fullscreen) 05492 GFX_SwitchFullScreen(); 05493 menu.maxwindow = false; 05494 UpdateWindowDimensions(); 05495 RENDER_Reset(); 05496 if (OpenGL_using()) { 05497 UpdateWindowDimensions(); 05498 RENDER_Reset(); 05499 } 05500 break; 05501 case ID_WIN_SYSMENU_RESTOREMENU: 05502 /* prevent removing the menu in 3Dfx mode */ 05503 if (!GFX_GetPreventFullscreen()) { 05504 DOSBox_SetMenu(); 05505 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu); 05506 } 05507 break; 05508 case ID_WIN_SYSMENU_TOGGLEMENU: 05509 /* prevent removing the menu in 3Dfx mode */ 05510 if (!GFX_GetPreventFullscreen()) 05511 { 05512 if (menu.toggle) DOSBox_NoMenu(); else DOSBox_SetMenu(); 05513 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu); 05514 } 05515 break; 05516 #if !defined(HX_DOS) 05517 case ID_WIN_SYSMENU_MAPPER: 05518 extern void MAPPER_Run(bool pressed); 05519 MAPPER_Run(false); 05520 break; 05521 case ID_WIN_SYSMENU_CFG_GUI: 05522 extern void GUI_Run(bool pressed); 05523 GUI_Run(false); 05524 break; 05525 case ID_WIN_SYSMENU_PAUSE: 05526 extern void PauseDOSBox(bool pressed); 05527 PauseDOSBox(true); 05528 break; 05529 #endif 05530 } 05531 default: 05532 break; 05533 } 05534 } 05535 #endif 05536 case SDL_ACTIVEEVENT: 05537 if (event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) { 05538 if (event.active.gain) { 05539 #ifdef WIN32 05540 if (!sdl.desktop.fullscreen) sdl.focus_ticks = GetTicks(); 05541 #endif 05542 if (sdl.desktop.fullscreen && !sdl.mouse.locked) 05543 GFX_CaptureMouse(); 05544 SetPriority(sdl.priority.focus); 05545 CPU_Disable_SkipAutoAdjust(); 05546 BIOS_SynchronizeNumLock(); 05547 BIOS_SynchronizeCapsLock(); 05548 BIOS_SynchronizeScrollLock(); 05549 } else { 05550 if (sdl.mouse.locked) 05551 { 05552 CaptureMouseNotify(); 05553 GFX_CaptureMouse(); 05554 } 05555 05556 #if defined(WIN32) 05557 if (sdl.desktop.fullscreen) 05558 GFX_ForceFullscreenExit(); 05559 #endif 05560 05561 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 05562 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05563 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05564 05565 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 05566 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 05567 #endif 05568 05569 SetPriority(sdl.priority.nofocus); 05570 GFX_LosingFocus(); 05571 CPU_Enable_SkipAutoAdjust(); 05572 } 05573 } 05574 05575 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 05576 if (event.active.state & SDL_APPMOUSEFOCUS) { 05577 if (!(event.active.gain & SDL_APPMOUSEFOCUS)) { 05578 /* losing focus or moving the mouse outside the window should un-hilight the currently selected menu item */ 05579 void GFX_SDLMenuTrackHover(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05580 void GFX_SDLMenuTrackHilight(DOSBoxMenu &menu,DOSBoxMenu::item_handle_t item_id); 05581 05582 GFX_SDLMenuTrackHover(mainMenu,DOSBoxMenu::unassigned_item_handle); 05583 GFX_SDLMenuTrackHilight(mainMenu,DOSBoxMenu::unassigned_item_handle); 05584 05585 } 05586 } 05587 05588 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 05589 #endif 05590 05591 /* Non-focus priority is set to pause; check to see if we've lost window or input focus 05592 * i.e. has the window been minimised or made inactive? 05593 */ 05594 if (sdl.priority.nofocus == PRIORITY_LEVEL_PAUSE) { 05595 if ((event.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) && (!event.active.gain)) { 05596 /* Window has lost focus, pause the emulator. 05597 * This is similar to what PauseDOSBox() does, but the exit criteria is different. 05598 * Instead of waiting for the user to hit Alt-Break, we wait for the window to 05599 * regain window or input focus. 05600 */ 05601 bool paused = true; 05602 SDL_Event ev; 05603 05604 GFX_SetTitle(-1,-1,-1,true); 05605 KEYBOARD_ClrBuffer(); 05606 // SDL_Delay(500); 05607 // while (SDL_PollEvent(&ev)) { 05608 // flush event queue. 05609 // } 05610 05611 while (paused) { 05612 #if C_EMSCRIPTEN 05613 emscripten_sleep_with_yield(0); 05614 SDL_PollEvent(&ev); 05615 #else 05616 // WaitEvent waits for an event rather than polling, so CPU usage drops to zero 05617 SDL_WaitEvent(&ev); 05618 #endif 05619 05620 switch (ev.type) { 05621 case SDL_QUIT: throw(0); break; // a bit redundant at linux at least as the active events gets before the quit event. 05622 case SDL_ACTIVEEVENT: // wait until we get window focus back 05623 if (ev.active.state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) { 05624 // We've got focus back, so unpause and break out of the loop 05625 if (ev.active.gain) { 05626 paused = false; 05627 GFX_SetTitle(-1,-1,-1,false); 05628 } 05629 05630 /* Now poke a "release ALT" command into the keyboard buffer 05631 * we have to do this, otherwise ALT will 'stick' and cause 05632 * problems with the app running in the DOSBox-X. 05633 */ 05634 KEYBOARD_AddKey(KBD_leftalt, false); 05635 KEYBOARD_AddKey(KBD_rightalt, false); 05636 } 05637 break; 05638 } 05639 } 05640 } 05641 } 05642 break; 05643 case SDL_MOUSEMOTION: 05644 HandleMouseMotion(&event.motion); 05645 break; 05646 case SDL_MOUSEBUTTONDOWN: 05647 case SDL_MOUSEBUTTONUP: 05648 HandleMouseButton(&event.button,&event.motion); 05649 break; 05650 case SDL_VIDEORESIZE: 05651 UpdateWindowDimensions(); // FIXME: Use SDL window dimensions, except that on Windows, SDL won't tell us our actual dimensions 05652 HandleVideoResize(&event.resize); 05653 break; 05654 case SDL_QUIT: 05655 throw(0); 05656 break; 05657 case SDL_VIDEOEXPOSE: 05658 if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw ); 05659 break; 05660 #ifdef WIN32 05661 case SDL_KEYDOWN: 05662 case SDL_KEYUP: 05663 // ignore event alt+tab 05664 if (event.key.keysym.sym==SDLK_LALT) sdl.laltstate = event.key.type; 05665 if (event.key.keysym.sym==SDLK_RALT) sdl.raltstate = event.key.type; 05666 if (event.key.keysym.sym==SDLK_LCTRL) sdl.lctrlstate = event.key.type; 05667 if (event.key.keysym.sym==SDLK_RCTRL) sdl.rctrlstate = event.key.type; 05668 if (event.key.keysym.sym==SDLK_LSHIFT) sdl.lshiftstate = event.key.type; 05669 if (event.key.keysym.sym==SDLK_RSHIFT) sdl.rshiftstate = event.key.type; 05670 if (((event.key.keysym.sym==SDLK_TAB)) && 05671 ((sdl.laltstate==SDL_KEYDOWN) || (sdl.raltstate==SDL_KEYDOWN))) { MAPPER_LosingFocus(); break; } 05672 // This can happen as well. 05673 if (((event.key.keysym.sym == SDLK_TAB )) && (event.key.keysym.mod & KMOD_ALT)) break; 05674 // ignore tab events that arrive just after regaining focus. (likely the result of alt-tab) 05675 if ((event.key.keysym.sym == SDLK_TAB) && (GetTicks() - sdl.focus_ticks < 2)) break; 05676 #endif 05677 #if defined (MACOSX) 05678 case SDL_KEYDOWN: 05679 case SDL_KEYUP: 05680 /* On macs CMD-Q is the default key to close an application */ 05681 if (event.key.keysym.sym == SDLK_q && (event.key.keysym.mod == KMOD_RMETA || event.key.keysym.mod == KMOD_LMETA) ) { 05682 KillSwitch(true); 05683 break; 05684 } 05685 #endif 05686 default: 05687 void MAPPER_CheckEvent(SDL_Event * event); 05688 MAPPER_CheckEvent(&event); 05689 } 05690 } 05691 #endif 05692 // start emendelson from dbDOS; improved by Wengier 05693 // Disabled multiple characters per dispatch b/c occasionally 05694 // keystrokes get lost in the spew. (Prob b/c of DI usage on Win32, sadly..) 05695 // while (PasteClipboardNext()); 05696 // Doesn't really matter though, it's fast enough as it is... 05697 if (paste_speed < 0) paste_speed = 20; 05698 05699 static Bitu iPasteTicker = 0; 05700 if (paste_speed && (iPasteTicker++ % paste_speed) == 0) // emendelson: was %2, %20 is good for WP51 05701 PasteClipboardNext(); // end added emendelson from dbDOS; improved by Wengier 05702 } 05703 05704 // added emendelson from dbDos; improved by Wengier 05705 #if defined(WIN32) && !defined(C_SDL2) && !defined(__MINGW32__) 05706 #include <cassert> 05707 05708 // Ripped from SDL's SDL_dx5events.c, since there's no API to access it... 05709 #define DIRECTINPUT_VERSION 0x0800 05710 #include <dinput.h> 05711 #ifndef DIK_PAUSE 05712 #define DIK_PAUSE 0xC5 05713 #endif 05714 #ifndef DIK_OEM_102 05715 #define DIK_OEM_102 0x56 /* < > | on UK/Germany keyboards */ 05716 #endif 05717 static SDLKey aryScanCodeToSDLKey[0xFF]; 05718 static bool bScanCodeMapInited = false; 05719 static void PasteInitMapSCToSDLKey() 05720 { 05721 /* Map the DIK scancodes to SDL keysyms */ 05722 for (int i = 0; i<SDL_arraysize(aryScanCodeToSDLKey); ++i) 05723 aryScanCodeToSDLKey[i] = SDLK_UNKNOWN; 05724 05725 /* Defined DIK_* constants */ 05726 aryScanCodeToSDLKey[DIK_ESCAPE] = SDLK_ESCAPE; 05727 aryScanCodeToSDLKey[DIK_1] = SDLK_1; 05728 aryScanCodeToSDLKey[DIK_2] = SDLK_2; 05729 aryScanCodeToSDLKey[DIK_3] = SDLK_3; 05730 aryScanCodeToSDLKey[DIK_4] = SDLK_4; 05731 aryScanCodeToSDLKey[DIK_5] = SDLK_5; 05732 aryScanCodeToSDLKey[DIK_6] = SDLK_6; 05733 aryScanCodeToSDLKey[DIK_7] = SDLK_7; 05734 aryScanCodeToSDLKey[DIK_8] = SDLK_8; 05735 aryScanCodeToSDLKey[DIK_9] = SDLK_9; 05736 aryScanCodeToSDLKey[DIK_0] = SDLK_0; 05737 aryScanCodeToSDLKey[DIK_MINUS] = SDLK_MINUS; 05738 aryScanCodeToSDLKey[DIK_EQUALS] = SDLK_EQUALS; 05739 aryScanCodeToSDLKey[DIK_BACK] = SDLK_BACKSPACE; 05740 aryScanCodeToSDLKey[DIK_TAB] = SDLK_TAB; 05741 aryScanCodeToSDLKey[DIK_Q] = SDLK_q; 05742 aryScanCodeToSDLKey[DIK_W] = SDLK_w; 05743 aryScanCodeToSDLKey[DIK_E] = SDLK_e; 05744 aryScanCodeToSDLKey[DIK_R] = SDLK_r; 05745 aryScanCodeToSDLKey[DIK_T] = SDLK_t; 05746 aryScanCodeToSDLKey[DIK_Y] = SDLK_y; 05747 aryScanCodeToSDLKey[DIK_U] = SDLK_u; 05748 aryScanCodeToSDLKey[DIK_I] = SDLK_i; 05749 aryScanCodeToSDLKey[DIK_O] = SDLK_o; 05750 aryScanCodeToSDLKey[DIK_P] = SDLK_p; 05751 aryScanCodeToSDLKey[DIK_LBRACKET] = SDLK_LEFTBRACKET; 05752 aryScanCodeToSDLKey[DIK_RBRACKET] = SDLK_RIGHTBRACKET; 05753 aryScanCodeToSDLKey[DIK_RETURN] = SDLK_RETURN; 05754 aryScanCodeToSDLKey[DIK_LCONTROL] = SDLK_LCTRL; 05755 aryScanCodeToSDLKey[DIK_A] = SDLK_a; 05756 aryScanCodeToSDLKey[DIK_S] = SDLK_s; 05757 aryScanCodeToSDLKey[DIK_D] = SDLK_d; 05758 aryScanCodeToSDLKey[DIK_F] = SDLK_f; 05759 aryScanCodeToSDLKey[DIK_G] = SDLK_g; 05760 aryScanCodeToSDLKey[DIK_H] = SDLK_h; 05761 aryScanCodeToSDLKey[DIK_J] = SDLK_j; 05762 aryScanCodeToSDLKey[DIK_K] = SDLK_k; 05763 aryScanCodeToSDLKey[DIK_L] = SDLK_l; 05764 aryScanCodeToSDLKey[DIK_SEMICOLON] = SDLK_SEMICOLON; 05765 aryScanCodeToSDLKey[DIK_APOSTROPHE] = SDLK_QUOTE; 05766 aryScanCodeToSDLKey[DIK_GRAVE] = SDLK_BACKQUOTE; 05767 aryScanCodeToSDLKey[DIK_LSHIFT] = SDLK_LSHIFT; 05768 aryScanCodeToSDLKey[DIK_BACKSLASH] = SDLK_BACKSLASH; 05769 aryScanCodeToSDLKey[DIK_OEM_102] = SDLK_LESS; 05770 aryScanCodeToSDLKey[DIK_Z] = SDLK_z; 05771 aryScanCodeToSDLKey[DIK_X] = SDLK_x; 05772 aryScanCodeToSDLKey[DIK_C] = SDLK_c; 05773 aryScanCodeToSDLKey[DIK_V] = SDLK_v; 05774 aryScanCodeToSDLKey[DIK_B] = SDLK_b; 05775 aryScanCodeToSDLKey[DIK_N] = SDLK_n; 05776 aryScanCodeToSDLKey[DIK_M] = SDLK_m; 05777 aryScanCodeToSDLKey[DIK_COMMA] = SDLK_COMMA; 05778 aryScanCodeToSDLKey[DIK_PERIOD] = SDLK_PERIOD; 05779 aryScanCodeToSDLKey[DIK_SLASH] = SDLK_SLASH; 05780 aryScanCodeToSDLKey[DIK_RSHIFT] = SDLK_RSHIFT; 05781 aryScanCodeToSDLKey[DIK_MULTIPLY] = SDLK_KP_MULTIPLY; 05782 aryScanCodeToSDLKey[DIK_LMENU] = SDLK_LALT; 05783 aryScanCodeToSDLKey[DIK_SPACE] = SDLK_SPACE; 05784 aryScanCodeToSDLKey[DIK_CAPITAL] = SDLK_CAPSLOCK; 05785 aryScanCodeToSDLKey[DIK_F1] = SDLK_F1; 05786 aryScanCodeToSDLKey[DIK_F2] = SDLK_F2; 05787 aryScanCodeToSDLKey[DIK_F3] = SDLK_F3; 05788 aryScanCodeToSDLKey[DIK_F4] = SDLK_F4; 05789 aryScanCodeToSDLKey[DIK_F5] = SDLK_F5; 05790 aryScanCodeToSDLKey[DIK_F6] = SDLK_F6; 05791 aryScanCodeToSDLKey[DIK_F7] = SDLK_F7; 05792 aryScanCodeToSDLKey[DIK_F8] = SDLK_F8; 05793 aryScanCodeToSDLKey[DIK_F9] = SDLK_F9; 05794 aryScanCodeToSDLKey[DIK_F10] = SDLK_F10; 05795 aryScanCodeToSDLKey[DIK_NUMLOCK] = SDLK_NUMLOCK; 05796 aryScanCodeToSDLKey[DIK_SCROLL] = SDLK_SCROLLOCK; 05797 aryScanCodeToSDLKey[DIK_NUMPAD7] = SDLK_KP7; 05798 aryScanCodeToSDLKey[DIK_NUMPAD8] = SDLK_KP8; 05799 aryScanCodeToSDLKey[DIK_NUMPAD9] = SDLK_KP9; 05800 aryScanCodeToSDLKey[DIK_SUBTRACT] = SDLK_KP_MINUS; 05801 aryScanCodeToSDLKey[DIK_NUMPAD4] = SDLK_KP4; 05802 aryScanCodeToSDLKey[DIK_NUMPAD5] = SDLK_KP5; 05803 aryScanCodeToSDLKey[DIK_NUMPAD6] = SDLK_KP6; 05804 aryScanCodeToSDLKey[DIK_ADD] = SDLK_KP_PLUS; 05805 aryScanCodeToSDLKey[DIK_NUMPAD1] = SDLK_KP1; 05806 aryScanCodeToSDLKey[DIK_NUMPAD2] = SDLK_KP2; 05807 aryScanCodeToSDLKey[DIK_NUMPAD3] = SDLK_KP3; 05808 aryScanCodeToSDLKey[DIK_NUMPAD0] = SDLK_KP0; 05809 aryScanCodeToSDLKey[DIK_DECIMAL] = SDLK_KP_PERIOD; 05810 aryScanCodeToSDLKey[DIK_F11] = SDLK_F11; 05811 aryScanCodeToSDLKey[DIK_F12] = SDLK_F12; 05812 05813 aryScanCodeToSDLKey[DIK_F13] = SDLK_F13; 05814 aryScanCodeToSDLKey[DIK_F14] = SDLK_F14; 05815 aryScanCodeToSDLKey[DIK_F15] = SDLK_F15; 05816 05817 aryScanCodeToSDLKey[DIK_NUMPADEQUALS] = SDLK_KP_EQUALS; 05818 aryScanCodeToSDLKey[DIK_NUMPADENTER] = SDLK_KP_ENTER; 05819 aryScanCodeToSDLKey[DIK_RCONTROL] = SDLK_RCTRL; 05820 aryScanCodeToSDLKey[DIK_DIVIDE] = SDLK_KP_DIVIDE; 05821 aryScanCodeToSDLKey[DIK_SYSRQ] = SDLK_PRINT; 05822 aryScanCodeToSDLKey[DIK_RMENU] = SDLK_RALT; 05823 aryScanCodeToSDLKey[DIK_PAUSE] = SDLK_PAUSE; 05824 aryScanCodeToSDLKey[DIK_HOME] = SDLK_HOME; 05825 aryScanCodeToSDLKey[DIK_UP] = SDLK_UP; 05826 aryScanCodeToSDLKey[DIK_PRIOR] = SDLK_PAGEUP; 05827 aryScanCodeToSDLKey[DIK_LEFT] = SDLK_LEFT; 05828 aryScanCodeToSDLKey[DIK_RIGHT] = SDLK_RIGHT; 05829 aryScanCodeToSDLKey[DIK_END] = SDLK_END; 05830 aryScanCodeToSDLKey[DIK_DOWN] = SDLK_DOWN; 05831 aryScanCodeToSDLKey[DIK_NEXT] = SDLK_PAGEDOWN; 05832 aryScanCodeToSDLKey[DIK_INSERT] = SDLK_INSERT; 05833 aryScanCodeToSDLKey[DIK_DELETE] = SDLK_DELETE; 05834 aryScanCodeToSDLKey[DIK_LWIN] = SDLK_LMETA; 05835 aryScanCodeToSDLKey[DIK_RWIN] = SDLK_RMETA; 05836 aryScanCodeToSDLKey[DIK_APPS] = SDLK_MENU; 05837 05838 bScanCodeMapInited = true; 05839 } 05840 05841 static std::string strPasteBuffer; 05842 // Just in case, to keep us from entering an unexpected KB state 05843 const size_t kPasteMinBufExtra = 4; 05845 static void GenKBStroke(const UINT uiScanCode, const bool bDepressed, const SDLMod keymods) 05846 { 05847 const SDLKey sdlkey = aryScanCodeToSDLKey[uiScanCode]; 05848 if (sdlkey == SDLK_UNKNOWN) 05849 return; 05850 05851 SDL_Event evntKeyStroke = { 0 }; 05852 evntKeyStroke.type = bDepressed ? SDL_KEYDOWN : SDL_KEYUP; 05853 evntKeyStroke.key.keysym.scancode = (unsigned char)LOBYTE(uiScanCode); 05854 evntKeyStroke.key.keysym.sym = sdlkey; 05855 evntKeyStroke.key.keysym.mod = keymods; 05856 evntKeyStroke.key.keysym.unicode = 0; 05857 evntKeyStroke.key.state = bDepressed ? SDL_PRESSED : SDL_RELEASED; 05858 SDL_PushEvent(&evntKeyStroke); 05859 } 05860 05861 static bool PasteClipboardNext() 05862 { 05863 if (strPasteBuffer.length() == 0) 05864 return false; 05865 05866 if (!bScanCodeMapInited) 05867 PasteInitMapSCToSDLKey(); 05868 05869 if (IS_PC98_ARCH) { 05870 BIOS_AddKeyToBuffer(strPasteBuffer[0]); 05871 strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length()); 05872 return true; 05873 } 05874 05875 const char cKey = strPasteBuffer[0]; 05876 SHORT shVirKey = VkKeyScan(cKey); // If it fails then MapVirtK will also fail, so no bail yet 05877 UINT uiScanCode = MapVirtualKey(LOBYTE(shVirKey), MAPVK_VK_TO_VSC); 05878 if (uiScanCode) 05879 { 05880 const bool bModShift = ((shVirKey & 0x0100) != 0); 05881 const bool bModCntrl = ((shVirKey & 0x0200) != 0); 05882 const bool bModAlt = ((shVirKey & 0x0400) != 0); 05883 const SDLMod sdlmModsOn = SDL_GetModState(); 05884 const bool bModShiftOn = ((sdlmModsOn & (KMOD_LSHIFT | KMOD_RSHIFT)) > 0); 05885 const bool bModCntrlOn = ((sdlmModsOn & (KMOD_LCTRL | KMOD_RCTRL)) > 0); 05886 const bool bModAltOn = ((sdlmModsOn & (KMOD_LALT | KMOD_RALT)) > 0); 05887 const UINT uiScanCodeShift = MapVirtualKey(VK_SHIFT, MAPVK_VK_TO_VSC); 05888 const UINT uiScanCodeCntrl = MapVirtualKey(VK_CONTROL, MAPVK_VK_TO_VSC); 05889 const UINT uiScanCodeAlt = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC); 05890 const SDLMod sdlmMods = (SDLMod)((sdlmModsOn & ~(KMOD_LSHIFT | KMOD_RSHIFT | 05891 KMOD_LCTRL | KMOD_RCTRL | 05892 KMOD_LALT | KMOD_RALT)) | 05893 (bModShiftOn ? KMOD_LSHIFT : 0) | 05894 (bModCntrlOn ? KMOD_LCTRL : 0) | 05895 (bModAltOn ? KMOD_LALT : 0)); 05896 05899 // Could be made more efficient, but would require tracking of more state, 05900 // so let's forgot that for now... 05901 size_t sStrokesRequired = 2; // At least the key & up/down 05902 if (bModShift != bModShiftOn) sStrokesRequired += 2; // To press/release Shift 05903 if (bModCntrl != bModCntrlOn) sStrokesRequired += 2; // To press/release Control 05904 if (bModAlt != bModAltOn) sStrokesRequired += 2; // To press/release Alt 05909 if (KEYBOARD_BufferSpaceAvail() < (sStrokesRequired + kPasteMinBufExtra)) 05910 return false; 05911 05912 if (bModShift != bModShiftOn) GenKBStroke(uiScanCodeShift, !bModShiftOn, sdlmMods); 05913 if (bModCntrl != bModCntrlOn) GenKBStroke(uiScanCodeCntrl, !bModCntrlOn, sdlmMods); 05914 if (bModAlt != bModAltOn) GenKBStroke(uiScanCodeAlt, !bModAltOn, sdlmMods); 05915 GenKBStroke(uiScanCode, true, sdlmMods); 05916 GenKBStroke(uiScanCode, false, sdlmMods); 05917 if (bModShift != bModShiftOn) GenKBStroke(uiScanCodeShift, bModShiftOn, sdlmMods); 05918 if (bModCntrl != bModCntrlOn) GenKBStroke(uiScanCodeCntrl, bModCntrlOn, sdlmMods); 05919 if (bModAlt != bModAltOn) GenKBStroke(uiScanCodeAlt, bModAltOn, sdlmMods); 05920 //putchar(cKey); // For debugging dropped strokes 05921 } else { 05922 if (KEYBOARD_BufferSpaceAvail() < (10+kPasteMinBufExtra)) // For simplicity, we just mimic Alt+<3 digits> 05923 return false; 05924 05925 const SDLMod sdlmModsOn = SDL_GetModState(); 05926 const UINT uiScanCodeAlt = MapVirtualKey(VK_MENU, MAPVK_VK_TO_VSC); 05927 const bool bModShiftOn = ((sdlmModsOn & (KMOD_LSHIFT|KMOD_RSHIFT)) > 0); 05928 const bool bModCntrlOn = ((sdlmModsOn & (KMOD_LCTRL|KMOD_RCTRL )) > 0); 05929 const bool bModAltOn = ((sdlmModsOn&(KMOD_LALT|KMOD_RALT)) > 0); 05930 const SDLMod sdlmMods = (SDLMod)((sdlmModsOn&~(KMOD_LSHIFT|KMOD_RSHIFT|KMOD_LCTRL|KMOD_RCTRL|KMOD_LALT|KMOD_RALT)) | 05931 (bModShiftOn ? KMOD_LSHIFT : 0) | 05932 (bModCntrlOn ? KMOD_LCTRL : 0) | 05933 (bModAltOn ? KMOD_LALT : 0)); 05934 05935 if (!bModAltOn) // Alt down if not already down 05936 GenKBStroke(uiScanCodeAlt, true, sdlmMods); 05937 05938 Bit8u ansiVal = cKey; 05939 for (int i = 100; i; i /= 10) 05940 { 05941 int numKey = ansiVal/i; // High digit of Alt+ASCII number combination 05942 ansiVal %= i; 05943 UINT uiScanCode = MapVirtualKey(numKey+VK_NUMPAD0, MAPVK_VK_TO_VSC); 05944 GenKBStroke(uiScanCode, true, sdlmMods); 05945 GenKBStroke(uiScanCode, false, sdlmMods); 05946 } 05947 GenKBStroke(uiScanCodeAlt, false, sdlmMods); // Alt up 05948 if (bModAltOn) // Alt down if is was already down 05949 GenKBStroke(uiScanCodeAlt, true, sdlmMods); 05950 } 05951 05952 // Pop head. Could be made more efficient, but this is neater. 05953 strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length()); // technically -1, but it clamps by itself anyways... 05954 return true; 05955 } 05956 05957 extern Bit8u* clipAscii; 05958 extern Bit32u clipSize; 05959 extern void Unicode2Ascii(const Bit16u* unicode); 05960 05961 void PasteClipboard(bool bPressed) 05962 { 05963 if (!bPressed) return; 05964 SDL_SysWMinfo wmiInfo; 05965 SDL_VERSION(&wmiInfo.version); 05966 05967 if (SDL_GetWMInfo(&wmiInfo) != 1||!OpenClipboard(wmiInfo.window)) return; 05968 if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {CloseClipboard();return;} 05969 05970 HANDLE hContents = GetClipboardData(CF_UNICODETEXT); 05971 if (!hContents) {CloseClipboard();return;} 05972 05973 Bit16u *szClipboard = (Bit16u *)GlobalLock(hContents); 05974 if (szClipboard) 05975 { 05976 clipSize=0; 05977 Unicode2Ascii(szClipboard); 05978 // Create a copy of the string, and filter out Linefeed characters (ASCII '10') 05979 char* szFilteredText = reinterpret_cast<char*>(alloca(clipSize + 1)); 05980 char* szFilterNextChar = szFilteredText; 05981 for (size_t i = 0; i < clipSize; ++i) 05982 if (clipAscii[i] != 0x0A) // Skip linefeeds 05983 { 05984 *szFilterNextChar = clipAscii[i]; 05985 ++szFilterNextChar; 05986 } 05987 *szFilterNextChar = '\0'; // Cap it. 05988 05989 strPasteBuffer.append(szFilteredText); 05990 GlobalUnlock(hContents); 05991 clipSize=0; 05992 } 05993 CloseClipboard(); 05994 } 05996 #else // end emendelson from dbDOS; improved by Wengier 05997 #if defined(WIN32) // SDL2, MinGW / Added by Wengier 05998 static std::string strPasteBuffer; 05999 extern Bit8u* clipAscii; 06000 extern Bit32u clipSize; 06001 extern void Unicode2Ascii(const Bit16u* unicode); 06002 void PasteClipboard(bool bPressed) { 06003 if (!bPressed||!OpenClipboard(NULL)) return; 06004 if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) {CloseClipboard();return;} 06005 HANDLE hContents = GetClipboardData(CF_UNICODETEXT); 06006 if (!hContents) {CloseClipboard();return;} 06007 Bit16u *szClipboard = (Bit16u *)GlobalLock(hContents); 06008 if (szClipboard) 06009 { 06010 clipSize=0; 06011 Unicode2Ascii(szClipboard); 06012 char* szFilteredText = reinterpret_cast<char*>(alloca(clipSize + 1)); 06013 char* szFilterNextChar = szFilteredText; 06014 for (size_t i = 0; i < clipSize; ++i) 06015 if (clipAscii[i] != 0x0A) // Skip linefeeds 06016 { 06017 *szFilterNextChar = clipAscii[i]; 06018 ++szFilterNextChar; 06019 } 06020 *szFilterNextChar = '\0'; // Cap it. 06021 06022 strPasteBuffer.append(szFilteredText); 06023 GlobalUnlock(hContents); 06024 clipSize=0; 06025 } 06026 CloseClipboard(); 06027 } 06028 06029 bool PasteClipboardNext() { 06030 if (strPasteBuffer.length() == 0) return false; 06031 BIOS_AddKeyToBuffer(strPasteBuffer[0]); 06032 strPasteBuffer = strPasteBuffer.substr(1, strPasteBuffer.length()); 06033 return true; 06034 } 06035 #else 06036 void PasteClipboard(bool bPressed) { 06037 (void)bPressed;//UNUSED 06038 // stub 06039 } 06040 06041 bool PasteClipboardNext() { 06042 // stub 06043 return false; 06044 } 06045 #endif 06046 #endif 06047 06048 #if defined (WIN32) 06049 extern Bit16u cpMap[256]; 06050 void CopyClipboard(void) { 06051 Bit16u len=0; 06052 const char* text = Mouse_GetSelected(mouse_start_x-sdl.clip.x,mouse_start_y-sdl.clip.y,mouse_end_x-sdl.clip.x,mouse_end_y-sdl.clip.y,(int)(currentWindowWidth-sdl.clip.x),(int)(currentWindowHeight-sdl.clip.y), &len); 06053 if (OpenClipboard(NULL)&&EmptyClipboard()) { 06054 HGLOBAL clipbuffer = GlobalAlloc(GMEM_DDESHARE, (len+1)*2); 06055 LPWSTR buffer = static_cast<LPWSTR>(GlobalLock(clipbuffer)); 06056 if (buffer!=NULL) { 06057 int reqsize = MultiByteToWideChar(dos.loaded_codepage, 0, text, len+1, NULL, 0); 06058 if (reqsize>0 && MultiByteToWideChar(dos.loaded_codepage, 0, text, len+1, buffer, reqsize)==reqsize) { 06059 GlobalUnlock(clipbuffer); 06060 SetClipboardData(CF_UNICODETEXT,clipbuffer); 06061 } 06062 } 06063 CloseClipboard(); 06064 } 06065 } 06066 06067 static BOOL WINAPI ConsoleEventHandler(DWORD event) { 06068 switch (event) { 06069 case CTRL_SHUTDOWN_EVENT: 06070 case CTRL_LOGOFF_EVENT: 06071 case CTRL_CLOSE_EVENT: 06072 case CTRL_BREAK_EVENT: 06073 raise(SIGTERM); 06074 return TRUE; 06075 case CTRL_C_EVENT: 06076 default: //pass to the next handler 06077 return FALSE; 06078 } 06079 } 06080 #endif 06081 06082 void Null_Init(Section *sec); 06083 06084 void SDL_OnSectionPropChange(Section *x) { 06085 (void)x;//UNUSED 06086 Section_prop * section = static_cast<Section_prop *>(control->GetSection("sdl")); 06087 06088 { 06089 bool cfg_want_menu = section->Get_bool("showmenu"); 06090 06091 /* -- -- decide whether to set menu */ 06092 if (menu_gui && !control->opt_nomenu && cfg_want_menu) 06093 DOSBox_SetMenu(); 06094 else 06095 DOSBox_NoMenu(); 06096 } 06097 } 06098 06099 void SDL_SetupConfigSection() { 06100 Section_prop * sdl_sec=control->AddSection_prop("sdl",&Null_Init); 06101 06102 Prop_bool* Pbool; 06103 Prop_string* Pstring; 06104 Prop_int* Pint; 06105 Prop_multival* Pmulti; 06106 06107 Pbool = sdl_sec->Add_bool("fullscreen",Property::Changeable::Always,false); 06108 Pbool->Set_help("Start DOSBox-X directly in fullscreen. (Press ALT-Enter to go back)"); 06109 06110 Pbool = sdl_sec->Add_bool("fulldouble",Property::Changeable::Always,false); 06111 Pbool->Set_help("Use double buffering in fullscreen. It can reduce screen flickering, but it can also result in a slow DOSBox-X."); 06112 06113 //Pbool = sdl_sec->Add_bool("sdlresize",Property::Changeable::Always,false); 06114 //Pbool->Set_help("Makes window resizable (depends on scalers)"); 06115 06116 Pstring = sdl_sec->Add_string("fullresolution",Property::Changeable::Always,"desktop"); 06117 Pstring->Set_help("What resolution to use for fullscreen: original, desktop or a fixed size (e.g. 1024x768).\n" 06118 " Using your monitor's native resolution with aspect=true might give the best results.\n" 06119 " If you end up with small window on a large screen, try an output different from surface."); 06120 06121 Pstring = sdl_sec->Add_string("windowresolution",Property::Changeable::Always,"original"); 06122 Pstring->Set_help("Scale the window to this size IF the output device supports hardware scaling.\n" 06123 " (output=surface does not!)"); 06124 06125 const char* outputs[] = { 06126 "surface", "overlay", 06127 #if C_OPENGL 06128 "opengl", "openglnb", "openglhq", 06129 #endif 06130 "ddraw", 06131 #if C_DIRECT3D 06132 "direct3d", 06133 #endif 06134 0 }; 06135 #ifdef __WIN32__ 06136 # if defined(HX_DOS) 06137 Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "surface"); /* HX DOS should stick to surface */ 06138 # elif defined(__MINGW32__) && !(C_DIRECT3D) && !defined(C_SDL2) 06139 /* NTS: OpenGL output never seems to work in VirtualBox under Windows XP */ 06140 Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, isVirtualBox ? "surface" : "opengl"); /* MinGW builds do not yet have Direct3D */ 06141 # else 06142 Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "direct3d"); 06143 # endif 06144 #elif defined(MACOSX) && defined(C_OPENGL) && !defined(C_SDL2) 06145 /* NTS: Lately, especially on Macbooks with Retina displays, OpenGL gives better performance 06146 than the CG bitmap-based "surface" output. 06147 06148 On my dev system, "top" shows a 20% CPU load doing 1:1 CG Bitmap output to the screen 06149 on a High DPI setup, while ignoring High DPI and rendering through Cocoa at 2x size 06150 pegs the CPU core DOSBox-X is running on at 100% and emulation stutters. 06151 06152 So for the best experience, default to OpenGL. 06153 06154 Note that "surface" yields good performance with SDL2 and OS X because SDL2 doesn't 06155 use the CGBitmap system, it uses OpenGL or Metal underneath automatically. */ 06156 Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "opengl"); 06157 #else 06158 Pstring = sdl_sec->Add_string("output", Property::Changeable::Always, "surface"); 06159 #endif 06160 Pstring->Set_help("What video system to use for output."); 06161 Pstring->Set_values(outputs); 06162 06163 Pbool = sdl_sec->Add_bool("autolock",Property::Changeable::Always, false); 06164 Pbool->Set_help("Mouse will automatically lock, if you click on the screen. (Press CTRL-F10 to unlock)"); 06165 06166 const char* feeds[] = { "none", "beep", "flash", nullptr}; 06167 Pstring = sdl_sec->Add_string("autolock_feedback", Property::Changeable::Always, feeds[1]); 06168 Pstring->Set_help("Autolock status feedback type, i.e. visual, auditive, none."); 06169 Pstring->Set_values(feeds); 06170 06171 const char* clipboardmodifier[] = { "none", "alt", "lalt", "ralt", "ctrl", "lctrl", "rctrl", "shift", "lshift", "rshift", "disabled", 0}; 06172 Pstring = sdl_sec->Add_string("clip_key_modifier",Property::Changeable::Always, "shift"); 06173 Pstring->Set_values(clipboardmodifier); 06174 Pstring->Set_help("Change the keyboard modifier for the Windows clipboard copy/paste function using the right mouse button.\n" 06175 "The default modifier is \"shift\". Set to \"none\" if no modifier is desired, or \"disabled\" to disable this feature."); 06176 06177 Pint = sdl_sec->Add_int("clip_paste_speed", Property::Changeable::WhenIdle, 20); 06178 Pint->Set_help("Set keyboard speed for pasting from the Windows clipboard.\n" 06179 "If the default setting of 20 causes lost keystrokes, increase the number.\n" 06180 "Or experiment with decreasing the number for applications that accept keystrokes quickly."); 06181 06182 Pmulti = sdl_sec->Add_multi("sensitivity",Property::Changeable::Always, ","); 06183 Pmulti->Set_help("Mouse sensitivity. The optional second parameter specifies vertical sensitivity (e.g. 100,-50)."); 06184 Pmulti->SetValue("100"); 06185 Pint = Pmulti->GetSection()->Add_int("xsens",Property::Changeable::Always,100); 06186 Pint->SetMinMax(-1000,1000); 06187 Pint = Pmulti->GetSection()->Add_int("ysens",Property::Changeable::Always,100); 06188 Pint->SetMinMax(-1000,1000); 06189 06190 const char * emulation[] = {"integration", "locked", "always", "never", nullptr}; 06191 Pstring = sdl_sec->Add_string("mouse_emulation", Property::Changeable::Always, emulation[1]); 06192 Pstring->Set_help( 06193 "When is mouse emulated ?\n" 06194 "integration: when not locked\n" 06195 "locked: when locked\n" 06196 "always: every time\n" 06197 "never: at no time\n" 06198 "If disabled, the mouse position in DOSBox-X is exactly where the host OS reports it.\n" 06199 "When using a high DPI mouse, the emulation of mouse movement can noticeably reduce the\n" 06200 "sensitiveness of your device, i.e. the mouse is slower but more precise."); 06201 Pstring->Set_values(emulation); 06202 06203 const char* wheelkeys[] = { "0", "1", "2", "3", 0 }; 06204 Pint = sdl_sec->Add_int("mouse_wheel_key", Property::Changeable::WhenIdle, 0); 06205 Pstring->Set_values(wheelkeys); 06206 Pint->Set_help("Convert mouse wheel movements into keyboard presses such as arrow keys.\n" 06207 "0: disabled; 1: up/down arrows; 2: left/right arrows; 3: PgUp/PgDn keys."); 06208 06209 Pbool = sdl_sec->Add_bool("waitonerror",Property::Changeable::Always, true); 06210 Pbool->Set_help("Wait before closing the console if DOSBox-X has an error."); 06211 06212 Pmulti = sdl_sec->Add_multi("priority", Property::Changeable::Always, ","); 06213 Pmulti->SetValue("higher,normal",/*init*/true); 06214 Pmulti->Set_help("Priority levels for DOSBox-X. Second entry behind the comma is for when DOSBox-X is not focused/minimized.\n" 06215 " pause is only valid for the second entry."); 06216 06217 const char* actt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0}; 06218 Pstring = Pmulti->GetSection()->Add_string("active",Property::Changeable::Always,"higher"); 06219 Pstring->Set_values(actt); 06220 06221 const char* inactt[] = { "lowest", "lower", "normal", "higher", "highest", "pause", 0}; 06222 Pstring = Pmulti->GetSection()->Add_string("inactive",Property::Changeable::Always,"normal"); 06223 Pstring->Set_values(inactt); 06224 06225 Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,MAPPERFILE_SDL1); 06226 Pstring->Set_help("File used to load/save the key/event mappings from. Resetmapper only works with the default value."); 06227 06228 Pstring = sdl_sec->Add_path("mapperfile_sdl2",Property::Changeable::Always,MAPPERFILE_SDL2); 06229 Pstring->Set_help("File used to load/save the key/event mappings from (SDL2 builds). Resetmapper only works with the default value."); 06230 06231 #if C_DIRECT3D && C_D3DSHADERS 06232 Pmulti = sdl_sec->Add_multi("pixelshader",Property::Changeable::Always," "); 06233 Pmulti->SetValue("none",/*init*/true); 06234 Pmulti->Set_help("Pixelshader program (effect file must be in Shaders subdirectory). If 'forced' is appended,\n" 06235 "then the shader will be used even if the result might not be desired."); 06236 06237 Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"none"); 06238 Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,""); 06239 #endif 06240 06241 Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,false); 06242 Pbool->Set_help("Avoid usage of symkeys, might not work on all operating systems."); 06243 06244 Pint = sdl_sec->Add_int("overscan",Property::Changeable::Always, 0); 06245 Pint->SetMinMax(0,10); 06246 Pint->Set_help("Width of overscan border (0 to 10). (works only if output=surface)"); 06247 06248 Pstring = sdl_sec->Add_string("titlebar", Property::Changeable::Always, ""); 06249 Pstring->Set_help("Change the string displayed in the DOSBox-X title bar."); 06250 06251 Pbool = sdl_sec->Add_bool("showmenu", Property::Changeable::Always, true); 06252 Pbool->Set_help("Whether to show the menu bar (if supported). Default true."); 06253 06254 // Pint = sdl_sec->Add_int("overscancolor",Property::Changeable::Always, 0); 06255 // Pint->SetMinMax(0,1000); 06256 // Pint->Set_help("Value of overscan color."); 06257 } 06258 06259 static void show_warning(char const * const message) { 06260 bool textonly = true; 06261 #ifdef WIN32 06262 textonly = false; 06263 if ( !sdl.inited && SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) < 0 ) textonly = true; 06264 sdl.inited = true; 06265 #endif 06266 LOG_MSG( "Warning: %s", message); 06267 if(textonly) return; 06268 #if defined(C_SDL2) 06269 if (!sdl.window) 06270 if (!GFX_SetSDLSurfaceWindow(640,400)) return; 06271 sdl.surface = SDL_GetWindowSurface(sdl.window); 06272 #else 06273 if(!sdl.surface) sdl.surface = SDL_SetVideoMode(640,400,0,SDL_RESIZABLE); 06274 sdl.deferred_resize = false; 06275 sdl.must_redraw_all = true; 06276 #endif 06277 if(!sdl.surface) return; 06278 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 06279 Bit32u rmask = 0xff000000; 06280 Bit32u gmask = 0x00ff0000; 06281 Bit32u bmask = 0x0000ff00; 06282 #else 06283 Bit32u rmask = 0x000000ff; 06284 Bit32u gmask = 0x0000ff00; 06285 Bit32u bmask = 0x00ff0000; 06286 #endif 06287 SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 400, 32, rmask, gmask, bmask, 0); 06288 if (!splash_surf) return; 06289 06290 int x = 120,y = 20; 06291 std::string m(message),m2; 06292 std::string::size_type a,b,c,d; 06293 06294 while(m.size()) { //Max 50 characters. break on space before or on a newline 06295 c = m.find('\n'); 06296 d = m.rfind(' ',50); 06297 if(c>d) a=b=d; else a=b=c; 06298 if( a != std::string::npos) b++; 06299 m2 = m.substr(0,a); m.erase(0,b); 06300 OutputString((unsigned int)x,(unsigned int)y,m2.c_str(),0xffffffffu,0,splash_surf); 06301 y += 20; 06302 } 06303 06304 SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL); 06305 #if defined(C_SDL2) 06306 SDL_UpdateWindowSurface(sdl.window); 06307 #else 06308 SDL_Flip(sdl.surface); 06309 #endif 06310 SDL_Delay(12000); 06311 } 06312 06313 static void launcheditor(std::string edit) { 06314 std::string path,file; 06315 Cross::CreatePlatformConfigDir(path); 06316 Cross::GetPlatformConfigName(file); 06317 path += file; 06318 FILE* f = fopen(path.c_str(),"r"); 06319 if(!f && !control->PrintConfig(path.c_str())) { 06320 printf("tried creating %s. but failed.\n",path.c_str()); 06321 exit(1); 06322 } 06323 if(f) fclose(f); 06324 06325 execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0); 06326 06327 //if you get here the launching failed! 06328 printf("can't find editor(s) specified at the command line.\n"); 06329 exit(1); 06330 } 06331 #if C_DEBUG 06332 extern void DEBUG_ShutDown(Section * /*sec*/); 06333 #endif 06334 06335 static void launchcaptures(std::string const& edit) { 06336 std::string path,file; 06337 struct stat cstat; 06338 Section* t = control->GetSection("dosbox"); 06339 if(t) file = t->GetPropValue("captures"); 06340 if(!t || file == NO_SUCH_PROPERTY) { 06341 printf("Config system messed up.\n"); 06342 exit(1); 06343 } 06344 path = "."; 06345 path += CROSS_FILESPLIT; 06346 path += file; 06347 06348 stat(path.c_str(),&cstat); 06349 if(cstat.st_mode & S_IFDIR) { 06350 execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0); 06351 //if you get here the launching failed! 06352 printf("can't find filemanager %s\n",edit.c_str()); 06353 exit(1); 06354 } else { 06355 path = ""; 06356 Cross::CreatePlatformConfigDir(path); 06357 path += file; 06358 Cross::CreateDir(path); 06359 stat(path.c_str(),&cstat); 06360 if((cstat.st_mode & S_IFDIR) == 0) { 06361 printf("%s doesn't exist or isn't a directory.\n",path.c_str()); 06362 exit(1); 06363 } 06364 execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0); 06365 //if you get here the launching failed! 06366 printf("can't find filemanager %s\n",edit.c_str()); 06367 exit(1); 06368 } 06369 } 06370 06371 static void launchsaves(std::string const& edit) { 06372 std::string path,file; 06373 struct stat cstat; 06374 file="SAVE"; 06375 path = "."; 06376 path += CROSS_FILESPLIT; 06377 path += file; 06378 stat(path.c_str(),&cstat); 06379 if(cstat.st_mode & S_IFDIR) { 06380 execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0); 06381 //if you get here the launching failed! 06382 printf("can't find filemanager %s\n",edit.c_str()); 06383 exit(1); 06384 } else { 06385 path = ""; 06386 Cross::CreatePlatformConfigDir(path); 06387 path += file; 06388 Cross::CreateDir(path); 06389 stat(path.c_str(),&cstat); 06390 if((cstat.st_mode & S_IFDIR) == 0) { 06391 printf("%s doesn't exists or isn't a directory.\n",path.c_str()); 06392 exit(1); 06393 } 06394 execlp(edit.c_str(),edit.c_str(),path.c_str(),(char*) 0); 06395 //if you get here the launching failed! 06396 printf("can't find filemanager %s\n",edit.c_str()); 06397 exit(1); 06398 } 06399 } 06400 06401 static void printconfiglocation() { 06402 std::string path,file; 06403 Cross::CreatePlatformConfigDir(path); 06404 Cross::GetPlatformConfigName(file); 06405 path += file; 06406 06407 FILE* f = fopen(path.c_str(),"r"); 06408 if(!f && !control->PrintConfig(path.c_str())) { 06409 printf("tried creating %s. but failed",path.c_str()); 06410 exit(1); 06411 } 06412 if(f) fclose(f); 06413 printf("%s\n",path.c_str()); 06414 exit(0); 06415 } 06416 06417 static void eraseconfigfile() { 06418 FILE* f = fopen("dosbox-x.conf","r"); 06419 if (!f) f = fopen("dosbox.conf","r"); 06420 if(f) { 06421 fclose(f); 06422 show_warning("Warning: dosbox-x.conf (or dosbox.conf) exists in current working directory.\nThis will override the configuration file at runtime.\n"); 06423 } 06424 std::string path,file; 06425 Cross::GetPlatformConfigDir(path); 06426 Cross::GetPlatformConfigName(file); 06427 path += file; 06428 f = fopen(path.c_str(),"r"); 06429 if(!f) exit(0); 06430 fclose(f); 06431 unlink(path.c_str()); 06432 exit(0); 06433 } 06434 06435 static void erasemapperfile() { 06436 FILE* g = fopen("dosbox-x.conf","r"); 06437 if (!g) g = fopen("dosbox.conf","r"); 06438 if(g) { 06439 fclose(g); 06440 show_warning("Warning: dosbox-x.conf (or dosbox.conf) exists in current working directory.\nKeymapping might not be properly reset.\n" 06441 "Please reset configuration as well and delete the dosbox-x.conf (or dosbox.conf).\n"); 06442 } 06443 06444 std::string path,file=MAPPERFILE; 06445 Cross::GetPlatformConfigDir(path); 06446 path += file; 06447 FILE* f = fopen(path.c_str(),"r"); 06448 if(!f) exit(0); 06449 fclose(f); 06450 unlink(path.c_str()); 06451 exit(0); 06452 } 06453 06454 void SetNumLock(void) { 06455 #ifdef WIN32 06456 if (control->opt_disable_numlock_check) 06457 return; 06458 06459 // Simulate a key press 06460 keybd_event(VK_NUMLOCK,0x45,KEYEVENTF_EXTENDEDKEY | 0,0); 06461 06462 // Simulate a key release 06463 keybd_event(VK_NUMLOCK,0x45,KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,0); 06464 #endif 06465 } 06466 06467 void CheckNumLockState(void) { 06468 #ifdef WIN32 06469 BYTE keyState[256]; 06470 06471 GetKeyboardState((LPBYTE)(&keyState)); 06472 if (keyState[VK_NUMLOCK] & 1) { 06473 startup_state_numlock = true; 06474 } 06475 #endif 06476 } 06477 06478 void CheckCapsLockState(void) { 06479 #ifdef WIN32 06480 BYTE keyState[256]; 06481 06482 GetKeyboardState((LPBYTE)(&keyState)); 06483 if (keyState[VK_CAPITAL] & 1) { 06484 startup_state_capslock = true; 06485 } 06486 #endif 06487 } 06488 06489 void CheckScrollLockState(void) { 06490 #ifdef WIN32 06491 BYTE keyState[256]; 06492 06493 GetKeyboardState((LPBYTE)(&keyState)); 06494 if (keyState[VK_SCROLL] & 1) { 06495 startup_state_scrlock = true; 06496 } 06497 #endif 06498 } 06499 06500 extern bool log_keyboard_scan_codes; 06501 06502 bool showconsole_init = false; 06503 06504 #if C_DEBUG 06505 bool DEBUG_IsDebuggerConsoleVisible(void); 06506 #endif 06507 06508 void DOSBox_ShowConsole() { 06509 #if defined(WIN32) && !defined(HX_DOS) 06510 CONSOLE_SCREEN_BUFFER_INFO csbi; 06511 COORD crd; 06512 HWND hwnd; 06513 06514 #if C_DEBUG 06515 /* if the debugger has already taken the console, do nothing */ 06516 if (DEBUG_IsDebuggerConsoleVisible()) 06517 return; 06518 #endif 06519 06520 /* if WE have already opened the console, do nothing */ 06521 if (showconsole_init) 06522 return; 06523 06524 /* Microsoft Windows: Allocate a console and begin spewing to it. 06525 DOSBox-X is compiled on Windows platforms as a Win32 application, and therefore, no console. */ 06526 /* FIXME: What about "file handles" 0/1/2 emulated by C library, for use with _open/_close/_lseek/etc? */ 06527 AllocConsole(); 06528 06529 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 06530 crd = csbi.dwSize; 06531 crd.X = 130; 06532 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), crd); 06533 06534 hwnd = GetConsoleWindow(); 06535 ShowWindow(hwnd, SW_MAXIMIZE); 06536 06537 freopen("CONIN$", "r", stdin); 06538 freopen("CONOUT$", "w", stdout); 06539 freopen("CONOUT$", "w", stderr); 06540 06541 showconsole_init = true; 06542 #endif 06543 } 06544 06545 void DOSBox_ConsolePauseWait() { 06546 char c; 06547 06548 printf("Press ENTER key to continue\n"); 06549 do { 06550 if (fread(&c, 1, 1, stdin) != 1) break; 06551 } while (!(c == 13 || c == 10)); /* wait for Enter key */ 06552 } 06553 06554 bool DOSBOX_parse_argv() { 06555 std::string optname,tmp; 06556 06557 assert(control != NULL); 06558 assert(control->cmdline != NULL); 06559 06560 control->cmdline->ChangeOptStyle(CommandLine::either_except); 06561 control->cmdline->BeginOpt(true/*eat argv*/); 06562 while (control->cmdline->GetOpt(optname)) { 06563 std::transform(optname.begin(), optname.end(), optname.begin(), ::tolower); 06564 06565 if (optname == "version") { 06566 DOSBox_ShowConsole(); 06567 06568 fprintf(stderr,"\nDOSBox-X version %s %s, copyright 2011-2020 joncampbell123.\n",VERSION,SDL_STRING); 06569 fprintf(stderr,"Based on DOSBox by the DOSBox Team (See AUTHORS file)\n\n"); 06570 fprintf(stderr,"DOSBox-X comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); 06571 fprintf(stderr,"and you are welcome to redistribute it under certain conditions;\n"); 06572 fprintf(stderr,"please read the COPYING file thoroughly before doing so.\n\n"); 06573 06574 #if defined(WIN32) 06575 DOSBox_ConsolePauseWait(); 06576 #endif 06577 06578 return 0; 06579 } 06580 else if (optname == "?" || optname == "h" || optname == "help") { 06581 DOSBox_ShowConsole(); 06582 06583 fprintf(stderr,"\ndosbox-x [options]\n"); 06584 fprintf(stderr,"\nDOSBox-X version %s %s, copyright 2011-2020 joncampbell123.\n",VERSION,SDL_STRING); 06585 fprintf(stderr,"Based on DOSBox by the DOSBox Team (See AUTHORS file)\n\n"); 06586 fprintf(stderr,"Options can be started with either \"-\" or \"/\" (e.g. \"-help\" or \"/help\"):\n\n"); 06587 fprintf(stderr," -?, -h, -help Show this help\n"); 06588 fprintf(stderr," -editconf Launch editor\n"); 06589 fprintf(stderr," -opencaptures <param> Launch captures\n"); 06590 fprintf(stderr," -opensaves <param> Launch saves\n"); 06591 fprintf(stderr," -eraseconf Erase config file\n"); 06592 fprintf(stderr," -resetconf Erase config file\n"); 06593 fprintf(stderr," -printconf Print config file location\n"); 06594 fprintf(stderr," -erasemapper Erase mapper file\n"); 06595 fprintf(stderr," -resetmapper Erase mapper file\n"); 06596 fprintf(stderr," -nogui Don't show GUI (Windows version only)\n"); 06597 fprintf(stderr," -nomenu Don't show menu (Windows version only)\n"); 06598 fprintf(stderr," -userconf Create user level config file\n"); 06599 fprintf(stderr," -conf <param> Use config file <param>\n"); 06600 fprintf(stderr," -startui -startgui Start DOSBox-X with UI\n"); 06601 fprintf(stderr," -startmapper Start DOSBox-X with mapper\n"); 06602 fprintf(stderr," -showcycles Show cycles count\n"); 06603 fprintf(stderr," -showrt Show emulation speed relative to realtime\n"); 06604 fprintf(stderr," -fullscreen Start in fullscreen\n"); 06605 fprintf(stderr," -savedir <path> Set save path\n"); 06606 fprintf(stderr," -disable-numlock-check Disable NumLock check (Windows version only)\n"); 06607 fprintf(stderr," -date-host-forced Force synchronization of date with host\n"); 06608 fprintf(stderr," -lang <message file> Use specific message file instead of language= setting\n"); 06609 fprintf(stderr," -nodpiaware Ignore (don't signal) Windows DPI awareness\n"); 06610 fprintf(stderr," -securemode Enable secure mode\n"); 06611 fprintf(stderr," -noconfig Don't execute CONFIG.SYS config section\n"); 06612 fprintf(stderr," -noautoexec Don't execute AUTOEXEC.BAT config section\n"); 06613 fprintf(stderr," -exit Exit after executing AUTOEXEC.BAT\n"); 06614 fprintf(stderr," -c <command string> Execute this command in addition to AUTOEXEC.BAT.\n"); 06615 fprintf(stderr," Make sure to surround the command in quotes to cover spaces.\n"); 06616 fprintf(stderr," -set <section property=value> Set the config option (overriding the config file).\n"); 06617 fprintf(stderr," Make sure to surround the string in quotes to cover spaces.\n"); 06618 fprintf(stderr," -time-limit <n> Kill the emulator after 'n' seconds\n"); 06619 fprintf(stderr," -fastbioslogo Fast BIOS logo (skip 1-second pause)\n"); 06620 fprintf(stderr," -helpdebug Show debug-related options\n\n"); 06621 06622 #if defined(WIN32) 06623 DOSBox_ConsolePauseWait(); 06624 #endif 06625 06626 return 0; 06627 } else if (optname == "helpdebug") { 06628 DOSBox_ShowConsole(); 06629 06630 fprintf(stderr,"\ndosbox-x [options]\n"); 06631 fprintf(stderr,"\nDOSBox-X version %s %s, copyright 2011-2020 joncampbell123.\n",VERSION,SDL_STRING); 06632 fprintf(stderr,"Based on DOSBox by the DOSBox Team (See AUTHORS file)\n\n"); 06633 fprintf(stderr,"Debugging options:\n\n"); 06634 fprintf(stderr," -debug Set all logging levels to debug\n"); 06635 fprintf(stderr," -early-debug Log early initialization messages in DOSBox-X (implies -console)\n"); 06636 fprintf(stderr," -keydbg Log all SDL key events\n"); 06637 fprintf(stderr," -break-start Break into debugger at startup\n"); 06638 fprintf(stderr," -console Show console (Windows builds only)\n"); 06639 fprintf(stderr," -noconsole Don't show console (Windows debug builds only)\n"); 06640 fprintf(stderr," -log-con Log CON output to a log file\n"); 06641 fprintf(stderr," -log-int21 Log calls to INT 21h (debug level)\n"); 06642 fprintf(stderr," -log-fileio Log file I/O through INT 21h (debug level)\n\n"); 06643 06644 #if defined(WIN32) 06645 DOSBox_ConsolePauseWait(); 06646 #endif 06647 06648 return 0; 06649 } 06650 else if (optname == "c") { 06651 if (!control->cmdline->NextOptArgv(tmp)) return false; 06652 control->opt_c.push_back(tmp); 06653 } 06654 else if (optname == "set") { 06655 if (!control->cmdline->NextOptArgv(tmp)) return false; 06656 control->opt_set.push_back(tmp); 06657 } 06658 else if (optname == "alt-vga") { 06659 control->opt_alt_vga_render = true; 06660 } 06661 else if (optname == "log-con") { 06662 control->opt_log_con = true; 06663 } 06664 else if (optname == "time-limit") { 06665 if (!control->cmdline->NextOptArgv(tmp)) return false; 06666 control->opt_time_limit = atof(tmp.c_str()); 06667 } 06668 else if (optname == "break-start") { 06669 control->opt_break_start = true; 06670 } 06671 else if (optname == "exit") { 06672 control->opt_exit = true; 06673 } 06674 else if (optname == "noconfig") { 06675 control->opt_noconfig = true; 06676 } 06677 else if (optname == "noautoexec") { 06678 control->opt_noautoexec = true; 06679 } 06680 else if (optname == "securemode") { 06681 control->opt_securemode = true; 06682 } 06683 else if (optname == "nodpiaware") { 06684 control->opt_disable_dpi_awareness = true; 06685 } 06686 else if (optname == "keydbg") { 06687 log_keyboard_scan_codes = true; 06688 } 06689 else if (optname == "date-host-forced" || optname == "date_host_forced") { 06690 control->opt_date_host_forced = true; 06691 } 06692 else if (optname == "showrt") { 06693 control->opt_showrt = true; 06694 } 06695 else if (optname == "showcycles") { 06696 control->opt_showcycles = true; 06697 } 06698 else if (optname == "startmapper") { 06699 control->opt_startmapper = true; 06700 } 06701 else if (optname == "fullscreen") { 06702 control->opt_fullscreen = true; 06703 } 06704 else if (optname == "startui" || optname == "startgui") { 06705 control->opt_startui = true; 06706 } 06707 else if (optname == "disable-numlock-check" || optname == "disable_numlock_check") { 06708 /* mainline DOSBox expects -disable_numlock_check so we support that here too */ 06709 control->opt_disable_numlock_check = true; 06710 } 06711 else if (optname == "savedir") { 06712 if (!control->cmdline->NextOptArgv(custom_savedir)) return false; 06713 } 06714 else if (optname == "userconf") { 06715 control->opt_userconf = true; 06716 } 06717 else if (optname == "lang") { 06718 if (!control->cmdline->NextOptArgv(control->opt_lang)) return false; 06719 } 06720 else if (optname == "fastbioslogo") { 06721 control->opt_fastbioslogo = true; 06722 } 06723 else if (optname == "conf") { 06724 if (!control->cmdline->NextOptArgv(tmp)) return false; 06725 control->config_file_list.push_back(tmp); 06726 } 06727 else if (optname == "editconf") { 06728 if (!control->cmdline->NextOptArgv(control->opt_editconf)) return false; 06729 } 06730 else if (optname == "opencaptures") { 06731 if (!control->cmdline->NextOptArgv(control->opt_opencaptures)) return false; 06732 } 06733 else if (optname == "opensaves") { 06734 if (!control->cmdline->NextOptArgv(control->opt_opensaves)) return false; 06735 } 06736 else if (optname == "eraseconf") { 06737 control->opt_eraseconf = true; 06738 } 06739 else if (optname == "resetconf") { 06740 control->opt_resetconf = true; 06741 } 06742 else if (optname == "printconf") { 06743 control->opt_printconf = true; 06744 } 06745 else if (optname == "erasemapper") { 06746 control->opt_erasemapper = true; 06747 } 06748 else if (optname == "resetmapper") { 06749 control->opt_resetmapper = true; 06750 } 06751 else if (optname == "log-int21") { 06752 control->opt_logint21 = true; 06753 } 06754 else if (optname == "log-fileio") { 06755 control->opt_logfileio = true; 06756 } 06757 else if (optname == "noconsole") { 06758 control->opt_noconsole = true; 06759 control->opt_console = false; 06760 } 06761 else if (optname == "console") { 06762 control->opt_noconsole = false; 06763 control->opt_console = true; 06764 } 06765 else if (optname == "nomenu") { 06766 control->opt_nomenu = true; 06767 } 06768 else if (optname == "nogui") { 06769 control->opt_nogui = true; 06770 } 06771 else if (optname == "debug") { 06772 control->opt_debug = true; 06773 } 06774 else if (optname == "early-debug") { 06775 control->opt_earlydebug = true; 06776 control->opt_console = true; 06777 } 06778 else { 06779 printf("WARNING: Unknown option %s (first parsing stage)\n",optname.c_str()); 06780 } 06781 } 06782 06783 /* now that the above loop has eaten all the options from the command 06784 * line, scan the command line for batch files to run. 06785 * https://github.com/joncampbell123/dosbox-x/issues/369 */ 06786 control->cmdline->BeginOpt(/*don't eat*/false); 06787 while (!control->cmdline->CurrentArgvEnd()) { 06788 control->cmdline->GetCurrentArgv(tmp); 06789 06790 { 06791 struct stat st; 06792 const char *ext = strrchr(tmp.c_str(),'.'); 06793 if (ext != NULL) { /* if it looks like a file... with an extension */ 06794 if (stat(tmp.c_str(), &st) == 0 && S_ISREG(st.st_mode)) { 06795 if (!strcasecmp(ext,".bat") || !strcasecmp(ext,".exe") || !strcasecmp(ext,".com")) { /* .BAT files given on the command line trigger automounting C: to run it */ 06796 control->auto_bat_additional.push_back(tmp); 06797 control->cmdline->EatCurrentArgv(); 06798 continue; 06799 } 06800 } 06801 } 06802 } 06803 06804 control->cmdline->NextArgv(); 06805 } 06806 06807 return true; 06808 } 06809 06810 void MSG_Init(); 06811 void DOSBOX_RealInit(); 06812 void DOSBOX_InitTickLoop(); 06813 void TIMER_ShutdownTickHandlers(); 06814 void DOSBOX_SetupConfigSections(void); 06815 void PAGING_Init(); 06816 void IO_Init(); 06817 void Init_VGABIOS(); 06818 void Init_AddressLimitAndGateMask(); 06819 void Init_RAM(); 06820 void Init_MemHandles(); 06821 void Init_MemoryAccessArray(); 06822 void Init_PCJR_CartridgeROM(); 06823 void Init_PS2_Port_92h(); 06824 void Init_A20_Gate(); 06825 void HARDWARE_Init(); 06826 void CAPTURE_Init(); 06827 void ROMBIOS_Init(); 06828 void CALLBACK_Init(); 06829 void Init_DMA(); 06830 void Init_PIC(); 06831 void PCIBUS_Init(); 06832 void PROGRAMS_Init(); 06833 void RENDER_Init(); 06834 void TIMER_Init(); 06835 void CMOS_Init(); 06836 void VGA_Init(); 06837 void CPU_Init(); 06838 void ISAPNP_Cfg_Init(); 06839 #if C_FPU 06840 void FPU_Init(); 06841 #endif 06842 void KEYBOARD_Init(); 06843 void VOODOO_Init(); 06844 void MIXER_Init(); 06845 void MIDI_Init(); 06846 06847 /* Init all the sections */ 06848 void MPU401_Init(); 06849 #if C_DEBUG 06850 void DEBUG_Init(); 06851 #endif 06852 void SBLASTER_Init(); 06853 void GUS_Init(); 06854 void INNOVA_Init(); 06855 void PCSPEAKER_Init(); 06856 void TANDYSOUND_Init(); 06857 void DISNEY_Init(); 06858 void PS1SOUND_Init(); 06859 void BIOS_Init(); 06860 void INT10_Init(); 06861 void JOYSTICK_Init(); 06862 void SERIAL_Init(); 06863 #if C_PRINTER 06864 void PRINTER_Init(); 06865 #endif 06866 void PARALLEL_Init(); 06867 void DONGLE_Init(); 06868 void DOS_Init(); 06869 void XMS_Init(); 06870 void EMS_Init(); 06871 void MOUSE_Init(); 06872 void DOS_KeyboardLayout_Init(); 06873 void CDROM_Image_Init(); 06874 void MSCDEX_Init(); 06875 void DRIVES_Init(); 06876 void IPX_Init(); 06877 void IDE_Init(); 06878 void NE2K_Init(); 06879 void FDC_Primary_Init(); 06880 void AUTOEXEC_Init(); 06881 06882 #if defined(WIN32) 06883 // NTS: I intend to add code that not only indicates High DPI awareness but also queries the monitor DPI 06884 // and then factor the DPI into DOSBox's scaler and UI decisions. 06885 void Windows_DPI_Awareness_Init() { 06886 // if the user says not to from the command line, or disables it from dosbox-x.conf, then don't enable DPI awareness. 06887 if (!dpi_aware_enable || control->opt_disable_dpi_awareness) 06888 return; 06889 06890 /* log it */ 06891 LOG(LOG_MISC,LOG_DEBUG)("Win32: I will announce High DPI awareness to Windows to eliminate upscaling"); 06892 06893 // turn off DPI scaling so DOSBox-X doesn't look so blurry on Windows 8 & Windows 10. 06894 // use GetProcAddress and LoadLibrary so that these functions are not hard dependencies that prevent us from 06895 // running under Windows 7 or XP. 06896 HRESULT (WINAPI *__SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS) = NULL; // windows 8.1 06897 BOOL (WINAPI *__SetProcessDPIAware)(void) = NULL; // vista/7/8/10 06898 HMODULE __user32; 06899 HMODULE __shcore; 06900 06901 __user32 = GetModuleHandle("USER32.DLL"); 06902 __shcore = GetModuleHandle("SHCORE.DLL"); 06903 06904 if (__user32) 06905 __SetProcessDPIAware = (BOOL(WINAPI *)(void))GetProcAddress(__user32, "SetProcessDPIAware"); 06906 if (__shcore) 06907 __SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS))GetProcAddress(__shcore, "SetProcessDpiAwareness"); 06908 06909 if (__SetProcessDpiAwareness) { 06910 LOG(LOG_MISC,LOG_DEBUG)("SHCORE.DLL exports SetProcessDpiAwareness function, calling it to signal we are DPI aware."); 06911 if (__SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) != S_OK) 06912 LOG(LOG_MISC,LOG_DEBUG)("SetProcessDpiAwareness failed"); 06913 } 06914 if (__SetProcessDPIAware) { 06915 LOG(LOG_MISC,LOG_DEBUG)("USER32.DLL exports SetProcessDPIAware function, calling it to signal we are DPI aware."); 06916 __SetProcessDPIAware(); 06917 } 06918 } 06919 #endif 06920 06921 bool VM_Boot_DOSBox_Kernel() { 06922 if (!dos_kernel_disabled) { 06923 RemoveEMSPageFrame(); 06924 RemoveUMBBlock(); 06925 DisableINT33(); 06926 DOS_GetMemory_unmap(); 06927 VFILE_Shutdown(); 06928 PROGRAMS_Shutdown(); 06929 DOS_UninstallMisc(); 06930 SBLASTER_DOS_Shutdown(); 06931 GUS_DOS_Shutdown(); 06932 EMS_DoShutDown(); 06933 XMS_DoShutDown(); 06934 DOS_DoShutDown(); 06935 06936 DispatchVMEvent(VM_EVENT_DOS_SURPRISE_REBOOT); // <- apparently we rebooted without any notification (such as jmp'ing to FFFF:0000) 06937 06938 dos_kernel_disabled = true; 06939 06940 #if defined(WIN32) && !defined(C_SDL2) 06941 int Reflect_Menu(void); 06942 Reflect_Menu(); 06943 #endif 06944 } 06945 06946 if (dos_kernel_disabled) { 06947 /* in case of reboot */ 06948 Init_MemHandles(); 06949 06950 DispatchVMEvent(VM_EVENT_DOS_BOOT); // <- just starting the DOS kernel now 06951 06952 /* DOS kernel init */ 06953 dos_kernel_disabled = false; // FIXME: DOS_Init should install VM callback handler to set this 06954 void DOS_Startup(Section* sec); 06955 DOS_Startup(NULL); 06956 06957 #if defined(WIN32) && !defined(C_SDL2) 06958 int Reflect_Menu(void); 06959 Reflect_Menu(); 06960 #endif 06961 06962 void update_pc98_function_row(unsigned char setting,bool force_redraw=false); 06963 06964 void DRIVES_Startup(Section *s); 06965 DRIVES_Startup(NULL); 06966 06967 /* NEC's function key row seems to be deeply embedded in the CON driver. Am I wrong? */ 06968 if (IS_PC98_ARCH) update_pc98_function_row(1); 06969 06970 DispatchVMEvent(VM_EVENT_DOS_INIT_KERNEL_READY); // <- kernel is ready 06971 06972 /* keyboard mapping, at this point in CONFIG.SYS parsing, right? */ 06973 void DOS_KeyboardLayout_Startup(Section* sec); 06974 DOS_KeyboardLayout_Startup(NULL); 06975 06976 /* Most MS-DOS installations have a DEVICE=C:\HIMEM.SYS somewhere near the top of their CONFIG.SYS */ 06977 void XMS_Startup(Section *sec); 06978 XMS_Startup(NULL); 06979 06980 /* And then after that, usually a DEVICE=C:\EMM386.EXE just after HIMEM.SYS */ 06981 void EMS_Startup(Section* sec); 06982 EMS_Startup(NULL); 06983 06984 DispatchVMEvent(VM_EVENT_DOS_INIT_CONFIG_SYS_DONE); // <- we just finished executing CONFIG.SYS 06985 SHELL_Init(); // <- NTS: this will change CPU instruction pointer! 06986 DispatchVMEvent(VM_EVENT_DOS_INIT_SHELL_READY); // <- we just finished loading the shell (COMMAND.COM) 06987 06988 /* it's time to init parsing AUTOEXEC.BAT */ 06989 void AUTOEXEC_Startup(Section *sec); 06990 AUTOEXEC_Startup(NULL); 06991 06992 /* Most MS-DOS installations run MSCDEX.EXE from somewhere in AUTOEXEC.BAT. We do the same here, in a fashion. */ 06993 /* TODO: Can we make this an OPTION if the user doesn't want to make MSCDEX.EXE resident? */ 06994 /* TODO: When we emulate executing AUTOEXEC.BAT between INIT_SHELL_READY and AUTOEXEC_BAT_DONE, can we make a fake MSCDEX.EXE within drive Z:\ 06995 * and auto-add a Z:\MSCDEX.EXE to the top of AUTOEXEC.BAT, command line switches and all. if the user has not already added it? */ 06996 void MSCDEX_Startup(Section* sec); 06997 MSCDEX_Startup(NULL); 06998 06999 /* Some installations load the MOUSE.COM driver from AUTOEXEC.BAT as well */ 07000 /* TODO: Can we make this an option? Can we add a fake MOUSE.COM to the Z:\ drive as well? */ 07001 void MOUSE_Startup(Section *sec); 07002 MOUSE_Startup(NULL); 07003 07004 DispatchVMEvent(VM_EVENT_DOS_INIT_AUTOEXEC_BAT_DONE); // <- we just finished executing AUTOEXEC.BAT 07005 DispatchVMEvent(VM_EVENT_DOS_INIT_AT_PROMPT); // <- now, we're at the DOS prompt 07006 SHELL_Run(); 07007 } 07008 07009 return true; 07010 } 07011 07012 bool VM_PowerOn() { 07013 if (!guest_machine_power_on) { 07014 // powering on means power on event, followed by reset assert, then reset deassert 07015 guest_machine_power_on = true; 07016 DispatchVMEvent(VM_EVENT_POWERON); 07017 DispatchVMEvent(VM_EVENT_RESET); 07018 DispatchVMEvent(VM_EVENT_RESET_END); 07019 } 07020 07021 return true; 07022 } 07023 07024 #if !defined(C_EMSCRIPTEN) 07025 void update_capture_fmt_menu(void); 07026 #endif 07027 07028 bool capture_fmt_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem); 07029 07030 void update_pc98_clock_pit_menu(void) { 07031 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07032 07033 int pc98rate = pc98_section->Get_int("pc-98 timer master frequency"); 07034 if (pc98rate > 6) pc98rate /= 2; 07035 if (pc98rate == 0) pc98rate = 5; /* Pick the most likely to work with DOS games (FIXME: This is a GUESS!! Is this correct?) */ 07036 else if (pc98rate < 5) pc98rate = 4; 07037 else pc98rate = 5; 07038 07039 mainMenu.get_item("dos_pc98_pit_4mhz").check(pc98rate == 4).refresh_item(mainMenu); 07040 mainMenu.get_item("dos_pc98_pit_5mhz").check(pc98rate == 5).refresh_item(mainMenu); 07041 } 07042 07043 bool dos_pc98_clock_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07044 (void)menu;//UNUSED 07045 (void)menuitem;//UNUSED 07046 void TIMER_OnPowerOn(Section*); 07047 void TIMER_OnEnterPC98_Phase2_UpdateBDA(void); 07048 07049 const char *ts = menuitem->get_name().c_str(); 07050 if (!strncmp(ts,"dos_pc98_pit_",13)) 07051 ts += 13; 07052 else 07053 return true; 07054 07055 std::string tmp = "pc-98 timer master frequency="; 07056 07057 { 07058 char tmp1[64]; 07059 sprintf(tmp1,"%d",atoi(ts)); 07060 tmp += tmp1; 07061 } 07062 07063 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07064 pc98_section->HandleInputline(tmp.c_str()); 07065 07066 TIMER_OnPowerOn(NULL); 07067 TIMER_OnEnterPC98_Phase2_UpdateBDA(); 07068 07069 update_pc98_clock_pit_menu(); 07070 return true; 07071 } 07072 07073 bool dos_debug_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07074 (void)menu;//UNUSED 07075 (void)menuitem;//UNUSED 07076 07077 const auto &ts = menuitem->get_name(); 07078 07079 if (ts == "debug_logint21") { 07080 log_int21 = !log_int21; 07081 mainMenu.get_item("debug_logint21").check(log_int21).refresh_item(mainMenu); 07082 } 07083 else if (ts == "debug_logfileio") { 07084 log_fileio = !log_fileio; 07085 mainMenu.get_item("debug_logfileio").check(log_fileio).refresh_item(mainMenu); 07086 } 07087 07088 return true; 07089 } 07090 07091 void SetScaleForced(bool forced); 07092 void OutputSettingMenuUpdate(void); 07093 07094 bool scaler_forced_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07095 (void)menu;//UNUSED 07096 (void)menuitem;//UNUSED 07097 SetScaleForced(!render.scale.forced); 07098 return true; 07099 } 07100 07101 void MENU_swapstereo(bool enabled); 07102 bool MENU_get_swapstereo(void); 07103 07104 bool mixer_swapstereo_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07105 (void)menu;//UNUSED 07106 (void)menuitem;//UNUSED 07107 MENU_swapstereo(!MENU_get_swapstereo()); 07108 return true; 07109 } 07110 07111 void MENU_mute(bool enabled); 07112 bool MENU_get_mute(void); 07113 07114 bool mixer_mute_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07115 (void)menu;//UNUSED 07116 (void)menuitem;//UNUSED 07117 MENU_mute(!MENU_get_mute()); 07118 return true; 07119 } 07120 07121 bool dos_mouse_enable_int33_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07122 (void)menu;//UNUSED 07123 (void)menuitem;//UNUSED 07124 extern bool Mouse_Drv; 07125 Mouse_Drv = !Mouse_Drv; 07126 mainMenu.get_item("dos_mouse_enable_int33").check(Mouse_Drv).refresh_item(mainMenu); 07127 return true; 07128 } 07129 07130 bool dos_mouse_y_axis_reverse_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07131 (void)menu;//UNUSED 07132 (void)menuitem;//UNUSED 07133 extern bool Mouse_Vertical; 07134 Mouse_Vertical = !Mouse_Vertical; 07135 mainMenu.get_item("dos_mouse_y_axis_reverse").check(Mouse_Vertical).refresh_item(mainMenu); 07136 return true; 07137 } 07138 07139 bool dos_mouse_sensitivity_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07140 (void)menu;//UNUSED 07141 (void)menuitem;//UNUSED 07142 GUI_Shortcut(2); 07143 return true; 07144 } 07145 07146 extern int enablelfn; 07147 bool dos_lfn_auto_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07148 (void)menu;//UNUSED 07149 (void)menuitem;//UNUSED 07150 enablelfn = -1; 07151 uselfn = dos.version.major>6; 07152 mainMenu.get_item("dos_lfn_auto").check(true).refresh_item(mainMenu); 07153 mainMenu.get_item("dos_lfn_enable").check(false).refresh_item(mainMenu); 07154 mainMenu.get_item("dos_lfn_disable").check(false).refresh_item(mainMenu); 07155 return true; 07156 } 07157 07158 bool dos_lfn_enable_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07159 (void)menu;//UNUSED 07160 (void)menuitem;//UNUSED 07161 enablelfn = 1; 07162 uselfn = true; 07163 mainMenu.get_item("dos_lfn_auto").check(false).refresh_item(mainMenu); 07164 mainMenu.get_item("dos_lfn_enable").check(true).refresh_item(mainMenu); 07165 mainMenu.get_item("dos_lfn_disable").check(false).refresh_item(mainMenu); 07166 return true; 07167 } 07168 07169 bool dos_lfn_disable_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07170 (void)menu;//UNUSED 07171 (void)menuitem;//UNUSED 07172 enablelfn = 0; 07173 uselfn = false; 07174 mainMenu.get_item("dos_lfn_auto").check(false).refresh_item(mainMenu); 07175 mainMenu.get_item("dos_lfn_enable").check(false).refresh_item(mainMenu); 07176 mainMenu.get_item("dos_lfn_disable").check(true).refresh_item(mainMenu); 07177 return true; 07178 } 07179 07180 extern bool gdc_5mhz_mode_initial; 07181 07182 bool vid_pc98_5mhz_gdc_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07183 (void)menu;//UNUSED 07184 (void)menuitem;//UNUSED 07185 if (IS_PC98_ARCH) { 07186 void gdc_5mhz_mode_update_vars(void); 07187 extern bool gdc_5mhz_mode; 07188 extern bool gdc_clock_1; 07189 extern bool gdc_clock_2; 07190 07191 gdc_5mhz_mode = !gdc_5mhz_mode; 07192 gdc_5mhz_mode_update_vars(); 07193 07194 // this is the user's command to change GDC setting, so it should appear 07195 // as if the initial setting in the dip switches 07196 gdc_5mhz_mode_initial = gdc_5mhz_mode; 07197 07198 gdc_clock_1 = gdc_5mhz_mode; 07199 gdc_clock_2 = gdc_5mhz_mode; 07200 07201 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07202 if (gdc_5mhz_mode) 07203 pc98_section->HandleInputline("pc-98 start gdc at 5mhz=1"); 07204 else 07205 pc98_section->HandleInputline("pc-98 start gdc at 5mhz=0"); 07206 07207 mainMenu.get_item("pc98_5mhz_gdc").check(gdc_5mhz_mode).refresh_item(mainMenu); 07208 } 07209 07210 return true; 07211 } 07212 07213 bool vid_pc98_200scanline_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07214 (void)menu;//UNUSED 07215 (void)menuitem;//UNUSED 07216 if (IS_PC98_ARCH) { 07217 extern bool pc98_allow_scanline_effect; 07218 07219 pc98_allow_scanline_effect = !pc98_allow_scanline_effect; 07220 07221 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07222 if (pc98_allow_scanline_effect) 07223 pc98_section->HandleInputline("pc-98 allow scanline effect=1"); 07224 else 07225 pc98_section->HandleInputline("pc-98 allow scanline effect=0"); 07226 07227 mainMenu.get_item("pc98_allow_200scanline").check(pc98_allow_scanline_effect).refresh_item(mainMenu); 07228 } 07229 07230 return true; 07231 } 07232 07233 bool vid_pc98_4parts_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07234 (void)menu;//UNUSED 07235 (void)menuitem;//UNUSED 07236 if (IS_PC98_ARCH) { 07237 extern bool pc98_allow_4_display_partitions; 07238 void updateGDCpartitions4(bool enable); 07239 07240 updateGDCpartitions4(!pc98_allow_4_display_partitions); 07241 07242 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07243 if (pc98_allow_4_display_partitions) 07244 pc98_section->HandleInputline("pc-98 allow 4 display partition graphics=1"); 07245 else 07246 pc98_section->HandleInputline("pc-98 allow 4 display partition graphics=0"); 07247 07248 mainMenu.get_item("pc98_allow_4partitions").check(pc98_allow_4_display_partitions).refresh_item(mainMenu); 07249 } 07250 07251 return true; 07252 } 07253 07254 bool vid_pc98_enable_188user_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07255 (void)menu;//UNUSED 07256 (void)menuitem;//UNUSED 07257 void gdc_egc_enable_update_vars(void); 07258 // extern bool enable_pc98_egc; 07259 // extern bool enable_pc98_grcg; 07260 // extern bool enable_pc98_16color; 07261 extern bool enable_pc98_188usermod; 07262 07263 if(IS_PC98_ARCH) { 07264 enable_pc98_188usermod = !enable_pc98_188usermod; 07265 gdc_egc_enable_update_vars(); 07266 07267 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07268 if (enable_pc98_188usermod) 07269 pc98_section->HandleInputline("pc-98 enable 188 user cg=1"); 07270 else 07271 pc98_section->HandleInputline("pc-98 enable 188 user cg=0"); 07272 07273 mainMenu.get_item("pc98_enable_188user").check(enable_pc98_188usermod).refresh_item(mainMenu); 07274 } 07275 07276 return true; 07277 } 07278 07279 bool vid_pc98_enable_egc_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07280 (void)menu;//UNUSED 07281 (void)menuitem;//UNUSED 07282 void gdc_egc_enable_update_vars(void); 07283 extern bool enable_pc98_egc; 07284 extern bool enable_pc98_grcg; 07285 extern bool enable_pc98_16color; 07286 // extern bool enable_pc98_188usermod; 07287 07288 if(IS_PC98_ARCH) { 07289 enable_pc98_egc = !enable_pc98_egc; 07290 gdc_egc_enable_update_vars(); 07291 07292 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07293 if (enable_pc98_egc) { 07294 pc98_section->HandleInputline("pc-98 enable egc=1"); 07295 07296 if(!enable_pc98_grcg) { //Also enable GRCG if GRCG is disabled when enabling EGC 07297 enable_pc98_grcg = !enable_pc98_grcg; 07298 mem_writeb(0x54C,(enable_pc98_grcg ? 0x02 : 0x00) | (enable_pc98_16color ? 0x04 : 0x00)); 07299 pc98_section->HandleInputline("pc-98 enable grcg=1"); 07300 } 07301 } 07302 else 07303 pc98_section->HandleInputline("pc-98 enable egc=0"); 07304 07305 mainMenu.get_item("pc98_enable_egc").check(enable_pc98_egc).refresh_item(mainMenu); 07306 mainMenu.get_item("pc98_enable_grcg").check(enable_pc98_grcg).refresh_item(mainMenu); 07307 } 07308 07309 return true; 07310 } 07311 07312 bool vid_pc98_enable_grcg_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07313 (void)menu;//UNUSED 07314 (void)menuitem;//UNUSED 07315 extern bool enable_pc98_grcg; 07316 extern bool enable_pc98_egc; 07317 void gdc_grcg_enable_update_vars(void); 07318 07319 if(IS_PC98_ARCH) { 07320 enable_pc98_grcg = !enable_pc98_grcg; 07321 gdc_grcg_enable_update_vars(); 07322 07323 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07324 if (enable_pc98_grcg) 07325 pc98_section->HandleInputline("pc-98 enable grcg=1"); 07326 else 07327 pc98_section->HandleInputline("pc-98 enable grcg=0"); 07328 07329 if ((!enable_pc98_grcg) && enable_pc98_egc) { // Also disable EGC if switching off GRCG 07330 void gdc_egc_enable_update_vars(void); 07331 enable_pc98_egc = !enable_pc98_egc; 07332 gdc_egc_enable_update_vars(); 07333 pc98_section->HandleInputline("pc-98 enable egc=0"); 07334 } 07335 07336 mainMenu.get_item("pc98_enable_egc").check(enable_pc98_egc).refresh_item(mainMenu); 07337 mainMenu.get_item("pc98_enable_grcg").check(enable_pc98_grcg).refresh_item(mainMenu); 07338 } 07339 07340 return true; 07341 } 07342 07343 bool vid_pc98_enable_analog_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07344 (void)menu;//UNUSED 07345 (void)menuitem;//UNUSED 07346 //NOTE: I thought that even later PC-9801s and some PC-9821s could use EGC features in digital 8-colors mode? 07347 extern bool enable_pc98_16color; 07348 void gdc_16color_enable_update_vars(void); 07349 07350 if(IS_PC98_ARCH) { 07351 enable_pc98_16color = !enable_pc98_16color; 07352 gdc_16color_enable_update_vars(); 07353 07354 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07355 if (enable_pc98_16color) 07356 pc98_section->HandleInputline("pc-98 enable 16-color=1"); 07357 else 07358 pc98_section->HandleInputline("pc-98 enable 16-color=0"); 07359 07360 mainMenu.get_item("pc98_enable_analog").check(enable_pc98_16color).refresh_item(mainMenu); 07361 } 07362 07363 return true; 07364 } 07365 07366 bool vid_pc98_enable_analog256_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07367 (void)menu;//UNUSED 07368 (void)menuitem;//UNUSED 07369 //NOTE: I thought that even later PC-9801s and some PC-9821s could use EGC features in digital 8-colors mode? 07370 extern bool enable_pc98_256color; 07371 void gdc_16color_enable_update_vars(void); 07372 07373 if(IS_PC98_ARCH) { 07374 enable_pc98_256color = !enable_pc98_256color; 07375 gdc_16color_enable_update_vars(); 07376 07377 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 07378 if (enable_pc98_256color) 07379 pc98_section->HandleInputline("pc-98 enable 256-color=1"); 07380 else 07381 pc98_section->HandleInputline("pc-98 enable 256-color=0"); 07382 07383 mainMenu.get_item("pc98_enable_analog256").check(enable_pc98_256color).refresh_item(mainMenu); 07384 } 07385 07386 return true; 07387 } 07388 07389 bool vid_pc98_cleartext_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07390 (void)menu;//UNUSED 07391 (void)menuitem;//UNUSED 07392 void pc98_clear_text(void); 07393 if (IS_PC98_ARCH) pc98_clear_text(); 07394 return true; 07395 } 07396 07397 #ifdef C_D3DSHADERS 07398 bool vid_select_pixel_shader_menu_callback(DOSBoxMenu* const menu, DOSBoxMenu::item* const menuitem) { 07399 (void)menu;//UNUSED 07400 (void)menuitem;//UNUSED 07401 07402 OPENFILENAME ofn; 07403 char filenamebuf[300] = { 0 }; 07404 char cwd[1024]; /* to prevent the dialog box from browsing relative to the Documents folder */ 07405 07406 GetCurrentDirectory(sizeof(cwd) - 16,cwd); 07407 07408 std::string forced_setting; 07409 std::string o_cwd = cwd; /* GetOpenFileName() will change the current working directory! */ 07410 07411 strcat(cwd, "\\shaders"); /* DOSBox "D3D patch" compat: File names are assumed to exist relative to <cwd>\shaders */ 07412 07413 Section_prop* section = static_cast<Section_prop*>(control->GetSection("sdl")); 07414 assert(section != NULL); 07415 { 07416 Section_prop* section = static_cast<Section_prop*>(control->GetSection("sdl")); 07417 Prop_multival* prop = section->Get_multival("pixelshader"); 07418 const char *path = prop->GetSection()->Get_string("type"); 07419 forced_setting = prop->GetSection()->Get_string("force"); 07420 07421 if (path != NULL && strcmp(path, "none") != 0) { 07422 filenamebuf[sizeof(filenamebuf) - 1] = 0; 07423 strncpy(filenamebuf, path, sizeof(filenamebuf) - 1); 07424 } 07425 } 07426 07427 memset(&ofn, 0, sizeof(ofn)); 07428 ofn.lStructSize = sizeof(ofn); 07429 ofn.hwndOwner = GetHWND(); 07430 ofn.lpstrFilter = 07431 "D3D shaders\0" "*.fx\0" 07432 "\0" "\0"; 07433 ofn.nFilterIndex = 1; 07434 ofn.lpstrFile = filenamebuf; 07435 ofn.nMaxFile = sizeof(filenamebuf); 07436 ofn.lpstrTitle = "Select D3D shader"; 07437 ofn.lpstrInitialDir = cwd; 07438 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_LONGNAMES; 07439 07440 if (GetOpenFileName(&ofn)) { 07441 /* Windows will fill lpstrFile with the FULL PATH. 07442 The full path should be given to the pixelshader setting unless it's just 07443 the same base path it was given: <cwd>\shaders in which case just cut it 07444 down to the filename. */ 07445 const char* name = ofn.lpstrFile; 07446 07447 /* filenames in Windows are case insensitive so do the comparison the same */ 07448 if (!strnicmp(name, cwd, strlen(cwd))) { 07449 name += strlen(cwd); 07450 while (*name == '\\') name++; 07451 } 07452 07453 /* the shader set included with the source code includes none.fx which is empty. 07454 if that was chosen then just change it to "none" so the D3D shader code does 07455 not waste it's time. */ 07456 { 07457 const char* n = strrchr(name, '\\'); 07458 if (n == NULL) n = name; 07459 07460 if (!strcasecmp(n, "none.fx")) 07461 name = "none"; 07462 } 07463 07464 /* SetVal just forces the interpreter to parse name=value and pixelshader is a multivalue. */ 07465 std::string tmp = name; 07466 tmp += " "; 07467 tmp += forced_setting; 07468 SetVal("sdl", "pixelshader", tmp); 07469 07470 /* GetOpenFileName() probably changed the current directory. 07471 This must be done before reinit of GFX because pixelshader might be relative path. */ 07472 SetCurrentDirectory(o_cwd.c_str()); 07473 07474 /* force reinit */ 07475 GFX_ForceRedrawScreen(); 07476 } 07477 else { 07478 /* GetOpenFileName() probably changed the current directory */ 07479 SetCurrentDirectory(o_cwd.c_str()); 07480 } 07481 07482 return true; 07483 } 07484 #endif 07485 07486 bool vid_pc98_graphics_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07487 (void)menu;//UNUSED 07488 (void)menuitem;//UNUSED 07489 void pc98_clear_graphics(void); 07490 if (IS_PC98_ARCH) pc98_clear_graphics(); 07491 return true; 07492 } 07493 07494 bool overscan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07495 (void)menu;//UNUSED 07496 int f = atoi(menuitem->get_text().c_str()); /* Off becomes 0 */ 07497 char tmp[64]; 07498 07499 sprintf(tmp,"%d",f); 07500 SetVal("sdl", "overscan", tmp); 07501 change_output(7); 07502 return true; 07503 } 07504 07505 void UpdateOverscanMenu(void) { 07506 for (size_t i=0;i <= 10;i++) { 07507 char tmp[64]; 07508 sprintf(tmp,"overscan_%zu",i); 07509 mainMenu.get_item(tmp).check(sdl.overscan_width == i).refresh_item(mainMenu); 07510 } 07511 } 07512 07513 bool vsync_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07514 (void)menu;//UNUSED 07515 (void)menuitem;//UNUSED 07516 #if !defined(C_SDL2) 07517 const char *val = menuitem->get_name().c_str(); 07518 if (!strncmp(val,"vsync_",6)) 07519 val += 6; 07520 else 07521 return true; 07522 07523 SetVal("vsync", "vsyncmode", val); 07524 07525 void change_output(int output); 07526 change_output(8); 07527 07528 VGA_Vsync VGA_Vsync_Decode(const char *vsyncmodestr); 07529 void VGA_VsyncUpdateMode(VGA_Vsync vsyncmode); 07530 VGA_VsyncUpdateMode(VGA_Vsync_Decode(val)); 07531 #endif 07532 return true; 07533 } 07534 07535 bool vsync_set_syncrate_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07536 (void)menu;//UNUSED 07537 (void)menuitem;//UNUSED 07538 #if !defined(C_SDL2) 07539 GUI_Shortcut(17); 07540 #endif 07541 return true; 07542 } 07543 07544 bool output_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07545 (void)menu;//UNUSED 07546 07547 const char *what = menuitem->get_name().c_str(); 07548 07549 if (!strncmp(what,"output_",7)) 07550 what += 7; 07551 else 07552 return true; 07553 07554 if (!strcmp(what,"surface")) { 07555 if (sdl.desktop.want_type == SCREEN_SURFACE) return true; 07556 change_output(0); 07557 } 07558 else if (!strcmp(what,"opengl")) { 07559 #if C_OPENGL 07560 if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear) return true; 07561 change_output(3); 07562 #endif 07563 } 07564 else if (!strcmp(what,"openglnb")) { 07565 #if C_OPENGL 07566 if (sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear) return true; 07567 change_output(4); 07568 #endif 07569 } 07570 else if (!strcmp(what,"direct3d")) { 07571 #if C_DIRECT3D 07572 if (sdl.desktop.want_type == SCREEN_DIRECT3D) return true; 07573 change_output(5); 07574 #endif 07575 } 07576 07577 SetVal("sdl", "output", what); 07578 OutputSettingMenuUpdate(); 07579 return true; 07580 } 07581 07582 bool MENU_SetBool(std::string secname, std::string value); 07583 07584 bool vga_9widetext_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07585 (void)menu;//UNUSED 07586 (void)menuitem;//UNUSED 07587 MENU_SetBool("render", "char9"); 07588 return true; 07589 } 07590 07591 bool doublescan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07592 (void)menu;//UNUSED 07593 (void)menuitem;//UNUSED 07594 MENU_SetBool("render", "doublescan"); 07595 return true; 07596 } 07597 07598 bool scaler_set_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07599 (void)menu;//UNUSED 07600 07601 const char *scaler = menuitem->get_name().c_str(); 07602 if (!strncmp(scaler,"scaler_set_",11)) 07603 scaler += 11; 07604 else 07605 abort(); 07606 07607 auto value = std::string(scaler) + (render.scale.forced ? " forced" : ""); 07608 SetVal("render", "scaler", value); 07609 07610 void RENDER_UpdateFromScalerSetting(void); 07611 RENDER_UpdateFromScalerSetting(); 07612 07613 void RENDER_UpdateScalerMenu(void); 07614 RENDER_UpdateScalerMenu(); 07615 07616 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 07617 RENDER_CallBack(GFX_CallBackReset); 07618 07619 return true; 07620 } 07621 07622 void CALLBACK_Idle(void); 07623 07624 void PauseWithInterruptsEnabled(Bitu /*val*/) { 07625 /* we can ONLY do this when the CPU is either in real mode or v86 mode. 07626 * doing this from protected mode will only crash the game. 07627 * also require that interrupts are enabled before pausing. */ 07628 if (cpu.pmode) { 07629 if (!(reg_flags & FLAG_VM)) { 07630 PIC_AddEvent(PauseWithInterruptsEnabled,0.001); 07631 return; 07632 } 07633 } 07634 07635 if (!(reg_flags & FLAG_IF)) { 07636 PIC_AddEvent(PauseWithInterruptsEnabled,0.001); 07637 return; 07638 } 07639 07640 while (pausewithinterrupts_enable) CALLBACK_Idle(); 07641 } 07642 07643 void PauseWithInterrupts_mapper_shortcut(bool pressed) { 07644 if (!pressed) return; 07645 07646 if (!pausewithinterrupts_enable) { 07647 pausewithinterrupts_enable = true; 07648 PIC_AddEvent(PauseWithInterruptsEnabled,0.001); 07649 } 07650 else { 07651 pausewithinterrupts_enable = false; 07652 } 07653 07654 mainMenu.get_item("mapper_pauseints").check(pausewithinterrupts_enable).refresh_item(mainMenu); 07655 } 07656 07657 bool video_frameskip_common_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07658 (void)menu;//UNUSED 07659 07660 int f = atoi(menuitem->get_text().c_str()); /* Off becomes 0 */ 07661 char tmp[64]; 07662 07663 sprintf(tmp,"%d",f); 07664 SetVal("render", "frameskip", tmp); 07665 return true; 07666 } 07667 07668 bool show_console_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuitem) { 07669 #if !defined(C_EMSCRIPTEN) 07670 (void)menu;//UNUSED 07671 (void)menuitem;//UNUSED 07672 DOSBox_ShowConsole(); 07673 mainMenu.get_item("show_console").check(true).refresh_item(mainMenu); 07674 #endif 07675 return true; 07676 } 07677 07678 bool wait_on_error_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07679 #if !defined(C_EMSCRIPTEN) 07680 (void)menu;//UNUSED 07681 (void)menuitem;//UNUSED 07682 sdl.wait_on_error = !sdl.wait_on_error; 07683 mainMenu.get_item("wait_on_error").check(sdl.wait_on_error).refresh_item(mainMenu); 07684 #endif 07685 return true; 07686 } 07687 07688 bool autolock_mouse_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07689 (void)menu;//UNUSED 07690 (void)menuitem;//UNUSED 07691 sdl.mouse.autoenable = !sdl.mouse.autoenable; 07692 mainMenu.get_item("auto_lock_mouse").check(sdl.mouse.autoenable).refresh_item(mainMenu); 07693 return true; 07694 } 07695 07696 bool doublebuf_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07697 (void)menu;//UNUSED 07698 (void)menuitem;//UNUSED 07699 std::string doubleBufString = std::string("desktop.doublebuf"); 07700 SetVal("sdl", "fulldouble", (GetSetSDLValue(1, doubleBufString, 0)) ? "false" : "true"); res_init(); 07701 mainMenu.get_item("doublebuf").check(!!GetSetSDLValue(1, doubleBufString, 0)).refresh_item(mainMenu); 07702 return true; 07703 } 07704 07705 bool force_loadstate_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07706 (void)menu;//UNUSED 07707 (void)menuitem;//UNUSED 07708 force_load_state = !force_load_state; 07709 mainMenu.get_item("force_loadstate").check(force_load_state).refresh_item(mainMenu); 07710 return true; 07711 } 07712 07713 bool refresh_slots_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07714 (void)menu;//UNUSED 07715 (void)menuitem;//UNUSED 07716 for (unsigned int i=0; i<SaveState::SLOT_COUNT; i++) { 07717 char name[6]="slot0"; 07718 name[4]='0'+i; 07719 std::string command=SaveState::instance().getName(i); 07720 std::string str="Slot "+(i>=9?"10":std::string(1, '1'+i))+(command=="[Empty]"?" [Empty slot]":(command==""?"":" (Program: "+command+")")); 07721 mainMenu.get_item(name).set_text(str.c_str()).refresh_item(mainMenu); 07722 } 07723 return true; 07724 } 07725 07726 #if defined(LINUX) 07727 bool x11_on_top = false; 07728 #endif 07729 07730 #if defined(MACOSX) && !defined(C_SDL2) 07731 bool macosx_on_top = false; 07732 #endif 07733 07734 bool is_always_on_top(void) { 07735 #if defined(_WIN32) && !defined(C_SDL2) 07736 DWORD dwExStyle = ::GetWindowLong(GetHWND(), GWL_EXSTYLE); 07737 return !!(dwExStyle & WS_EX_TOPMOST); 07738 #elif defined(MACOSX) && !defined(C_SDL2) 07739 return macosx_on_top; 07740 #elif defined(LINUX) 07741 return x11_on_top; 07742 #else 07743 return false; 07744 #endif 07745 } 07746 07747 #if defined(_WIN32) && !defined(C_SDL2) 07748 extern "C" void sdl1_hax_set_topmost(unsigned char topmost); 07749 #endif 07750 #if defined(MACOSX) && !defined(C_SDL2) 07751 extern "C" void sdl1_hax_set_topmost(unsigned char topmost); 07752 #endif 07753 #if defined(MACOSX) && !defined(C_SDL2) 07754 extern "C" void sdl1_hax_macosx_highdpi_set_enable(const bool enable); 07755 #endif 07756 07757 void toggle_always_on_top(void) { 07758 bool cur = is_always_on_top(); 07759 #if defined(_WIN32) && !defined(C_SDL2) 07760 sdl1_hax_set_topmost(!cur); 07761 #elif defined(MACOSX) && !defined(C_SDL2) 07762 sdl1_hax_set_topmost(macosx_on_top = (!cur)); 07763 #elif defined(LINUX) 07764 void LinuxX11_OnTop(bool f); 07765 LinuxX11_OnTop(x11_on_top = (!cur)); 07766 #else 07767 (void)cur; 07768 #endif 07769 } 07770 07771 void BlankDisplay(void); 07772 07773 bool refreshtest_menu_callback(DOSBoxMenu * const xmenu, DOSBoxMenu::item * const menuitem) { 07774 (void)menuitem; 07775 (void)xmenu; 07776 07777 BlankDisplay(); 07778 07779 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 07780 mainMenu.setRedraw(); 07781 GFX_DrawSDLMenu(mainMenu,mainMenu.display_list); 07782 #endif 07783 07784 return true; 07785 } 07786 07787 bool showdetails_menu_callback(DOSBoxMenu * const xmenu, DOSBoxMenu::item * const menuitem) { 07788 (void)xmenu;//UNUSED 07789 (void)menuitem;//UNUSED 07790 menu.showrt = !(menu.hidecycles = !menu.hidecycles); 07791 GFX_SetTitle((Bit32s)CPU_CycleMax, -1, -1, false); 07792 mainMenu.get_item("showdetails").check(!menu.hidecycles).refresh_item(mainMenu); 07793 return true; 07794 } 07795 07796 bool alwaysontop_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07797 (void)menu;//UNUSED 07798 (void)menuitem;//UNUSED 07799 toggle_always_on_top(); 07800 mainMenu.get_item("alwaysontop").check(is_always_on_top()).refresh_item(mainMenu); 07801 return true; 07802 } 07803 07804 bool highdpienable_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07805 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 07806 07807 (void)menu;//UNUSED 07808 (void)menuitem;//UNUSED 07809 07810 #if defined(MACOSX) && !defined(C_SDL2) 07811 dpi_aware_enable = !dpi_aware_enable; 07812 if (!control->opt_disable_dpi_awareness) { 07813 sdl1_hax_macosx_highdpi_set_enable(dpi_aware_enable); 07814 RENDER_CallBack(GFX_CallBackReset); 07815 } 07816 #endif 07817 07818 mainMenu.get_item("highdpienable").check(dpi_aware_enable).refresh_item(mainMenu); 07819 return true; 07820 } 07821 07822 bool sendkey_preset_menu_callback(DOSBoxMenu * const menu, DOSBoxMenu::item * const menuitem) { 07823 (void)menu;//UNUSED 07824 if (menuitem->get_name() == "sendkey_ctrlesc") { 07825 KEYBOARD_AddKey(KBD_leftctrl, true); 07826 KEYBOARD_AddKey(KBD_esc, true); 07827 KEYBOARD_AddKey(KBD_leftctrl, false); 07828 KEYBOARD_AddKey(KBD_esc, false); 07829 } 07830 else if (menuitem->get_name() == "sendkey_alttab") { 07831 KEYBOARD_AddKey(KBD_leftalt, true); 07832 KEYBOARD_AddKey(KBD_tab, true); 07833 KEYBOARD_AddKey(KBD_leftalt, false); 07834 KEYBOARD_AddKey(KBD_tab, false); 07835 } 07836 else if (menuitem->get_name() == "sendkey_winlogo") { 07837 KEYBOARD_AddKey(KBD_lwindows, true); 07838 KEYBOARD_AddKey(KBD_lwindows, false); 07839 } 07840 else if (menuitem->get_name() == "sendkey_winmenu") { 07841 KEYBOARD_AddKey(KBD_rwinmenu, true); 07842 KEYBOARD_AddKey(KBD_rwinmenu, false); 07843 } 07844 else if (menuitem->get_name() == "sendkey_cad") { 07845 KEYBOARD_AddKey(KBD_leftctrl, true); 07846 KEYBOARD_AddKey(KBD_leftalt, true); 07847 KEYBOARD_AddKey(KBD_delete, true); 07848 KEYBOARD_AddKey(KBD_leftctrl, false); 07849 KEYBOARD_AddKey(KBD_leftalt, false); 07850 KEYBOARD_AddKey(KBD_delete, false); 07851 } 07852 07853 return true; 07854 } 07855 07856 void SetCyclesCount_mapper_shortcut_RunInternal(void) { 07857 void MAPPER_ReleaseAllKeys(void); 07858 MAPPER_ReleaseAllKeys(); 07859 07860 GFX_LosingFocus(); 07861 07862 GUI_Shortcut(16); 07863 07864 void MAPPER_ReleaseAllKeys(void); 07865 MAPPER_ReleaseAllKeys(); 07866 07867 GFX_LosingFocus(); 07868 } 07869 07870 void SetCyclesCount_mapper_shortcut_RunEvent(Bitu /*val*/) { 07871 KEYBOARD_ClrBuffer(); //Clear buffer 07872 GFX_LosingFocus(); //Release any keys pressed (buffer gets filled again). 07873 SetCyclesCount_mapper_shortcut_RunInternal(); 07874 } 07875 07876 void SetCyclesCount_mapper_shortcut(bool pressed) { 07877 if (!pressed) return; 07878 PIC_AddEvent(SetCyclesCount_mapper_shortcut_RunEvent, 0.0001f); //In case mapper deletes the key object that ran it 07879 } 07880 07881 void AspectRatio_mapper_shortcut(bool pressed) { 07882 if (!pressed) return; 07883 07884 if (!GFX_GetPreventFullscreen()) { 07885 SetVal("render", "aspect", render.aspect ? "false" : "true"); 07886 } 07887 } 07888 07889 void HideMenu_mapper_shortcut(bool pressed) { 07890 if (!pressed) return; 07891 07892 void ToggleMenu(bool pressed); 07893 ToggleMenu(true); 07894 07895 mainMenu.get_item("mapper_togmenu").check(!menu.toggle).refresh_item(mainMenu); 07896 } 07897 07898 void OutputSettingMenuUpdate(void) { 07899 mainMenu.get_item("output_surface").check(sdl.desktop.want_type == SCREEN_SURFACE).refresh_item(mainMenu); 07900 #if C_DIRECT3D 07901 mainMenu.get_item("output_direct3d").check(sdl.desktop.want_type == SCREEN_DIRECT3D).refresh_item(mainMenu); 07902 #endif 07903 #if C_OPENGL 07904 mainMenu.get_item("output_opengl").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear).refresh_item(mainMenu); 07905 mainMenu.get_item("output_openglnb").check(sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear).refresh_item(mainMenu); 07906 #endif 07907 } 07908 07909 bool custom_bios = false; 07910 07911 // OK why isn't this being set for Linux?? 07912 #ifndef SDL_MAIN_NOEXCEPT 07913 #define SDL_MAIN_NOEXCEPT 07914 #endif 07915 07916 //extern void UI_Init(void); 07917 int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT { 07918 CommandLine com_line(argc,argv); 07919 Config myconf(&com_line); 07920 07921 #if defined(WIN32) && !defined(HX_DOS) 07922 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); 07923 #endif 07924 07925 #if 0 /* VGA_Draw_2 self test: dot clock */ 07926 { 07927 const double start_time = 0; 07928 signed long long count = 0; 07929 VGA_Draw_2 t; 07930 07931 fprintf(stderr,"VGA_Draw_2: 1000Hz\n"); 07932 07933 t.dotclock.set_rate(1000,start_time);/*hz*/ 07934 for (int i=0;i < 10000;i++) { 07935 t.dotclock.update(start_time + i); 07936 07937 if (labs(t.dotclock.ticks - (signed long long)i) > 1ll) { /* NTS: Expect possible +/- 1 error due to floating point */ 07938 fprintf(stderr,"* TEST FAILURE:\n"); 07939 fprintf(stderr," ticks=%lld ticks_prev=%lld\n",(signed long long)i,(signed long long)t.dotclock.ticks); 07940 return 1; 07941 } 07942 } 07943 07944 t.dotclock.reset(start_time); 07945 assert(t.dotclock.base == start_time); 07946 assert(t.dotclock.ticks_prev == 0); 07947 assert(t.dotclock.ticks == 0); 07948 07949 fprintf(stderr,"VGA_Draw_2: 1000Hz incremental\n"); 07950 07951 count = 0; 07952 t.dotclock.set_rate(1000,start_time);/*hz*/ 07953 for (int i=0;i < 10000;i++) { 07954 t.dotclock.update(start_time + i); 07955 count += t.dotclock.delta_get(); 07956 assert(t.dotclock.ticks == t.dotclock.ticks_prev); 07957 07958 if (labs(count - (signed long long)i) > 1ll) { /* NTS: Expect possible +/- 1 error due to floating point */ 07959 fprintf(stderr,"* TEST FAILURE:\n"); 07960 fprintf(stderr," count=%lld ticks=%lld ticks_prev=%lld\n",count,(signed long long)i,(signed long long)t.dotclock.ticks); 07961 return 1; 07962 } 07963 07964 signed long long rc = t.dotclock.ticks2pic(count); 07965 if (labs(rc - (signed long long)i) > 1ll) { /* NTS: Expect possible +/- 1 error due to floating point */ 07966 fprintf(stderr,"* TEST FAILURE:\n"); 07967 fprintf(stderr," count=%lld ticks=%lld ticks_prev=%lld rc=%lld\n",count,(signed long long)i,(signed long long)t.dotclock.ticks,rc); 07968 return 1; 07969 } 07970 } 07971 07972 fprintf(stderr,"VGA_Draw_2: 1000Hz inc then 100Hz inc\n"); 07973 07974 count = 0; 07975 t.dotclock.set_rate(100,start_time + 1000);/*hz, rate change*/ 07976 for (int i=0;i < 10000;i++) { 07977 t.dotclock.update(start_time + 1000 + (i * 10));/*1ms * 10 = 10ms = 100Hz */ 07978 count += t.dotclock.delta_get(); 07979 assert(t.dotclock.ticks == t.dotclock.ticks_prev); 07980 07981 if (labs(count - (signed long long)i) > 1ll) { /* NTS: Expect possible +/- 1 error due to floating point */ 07982 fprintf(stderr,"* TEST FAILURE:\n"); 07983 fprintf(stderr," count=%lld ticks=%lld ticks_prev=%lld\n",count,(signed long long)i,(signed long long)t.dotclock.ticks); 07984 return 1; 07985 } 07986 07987 signed long long rc = t.dotclock.ticks2pic(count); 07988 if (labs(rc - ((signed long long)(i * 10) + 1000 + start_time)) > 1ll) { /* NTS: Expect possible +/- 1 error due to floating point */ 07989 fprintf(stderr,"* TEST FAILURE:\n"); 07990 fprintf(stderr," count=%lld ticks=%lld ticks_prev=%lld rc=%lld\n",count,(signed long long)i,(signed long long)t.dotclock.ticks,rc); 07991 return 1; 07992 } 07993 } 07994 07995 return 0; 07996 } 07997 #endif 07998 07999 #if C_EMSCRIPTEN 08000 control->opt_debug = true; 08001 control->opt_earlydebug = true; 08002 #endif 08003 08004 bitop::self_test(); 08005 ptrop::self_test(); 08006 08007 // initialize output libraries 08008 OUTPUT_SURFACE_Initialize(); 08009 #if C_OPENGL 08010 OUTPUT_OPENGL_Initialize(); 08011 #endif 08012 #if C_DIRECT3D 08013 OUTPUT_DIRECT3D_Initialize(); 08014 #endif 08015 08016 // initialize some defaults in SDL structure here 08017 sdl.srcAspect.x = 4; sdl.srcAspect.y = 3; 08018 sdl.srcAspect.xToY = (double)sdl.srcAspect.x / sdl.srcAspect.y; 08019 sdl.srcAspect.yToX = (double)sdl.srcAspect.y / sdl.srcAspect.x; 08020 08021 control=&myconf; 08022 #if defined(WIN32) && !defined(HX_DOS) 08023 /* Microsoft's IME does not play nice with DOSBox */ 08024 ImmDisableIME((DWORD)(-1)); 08025 #endif 08026 08027 #if defined(MACOSX) 08028 /* The resource system of DOSBox-X relies on being able to locate the Resources subdirectory 08029 within the DOSBox-X .app bundle. To do this, we have to first know where our own executable 08030 is, which Mac OS X helpfully puts int argv[0] for us */ 08031 /* NTS: Experimental testing shows that when we are run from the desktop (double-clicking on 08032 the .app bundle from the Finder) the current working directory is / (fs root). */ 08033 extern std::string MacOSXEXEPath; 08034 extern std::string MacOSXResPath; 08035 MacOSXEXEPath = argv[0]; 08036 08037 /* The path should be something like /blah/blah/dosbox-x.app/Contents/MacOS/DosBox */ 08038 /* If that's true, then we can move one level up the tree and look for */ 08039 /* /blah/blah/dosbox-x.app/Contents/Resources */ 08040 { 08041 const char *ref = argv[0]; 08042 const char *s = strrchr(ref,'/'); 08043 if (s != NULL) { 08044 if (s > ref) s--; 08045 while (s > ref && *s != '/') s--; 08046 if (!strncasecmp(s,"/MacOS/",7)) { 08047 MacOSXResPath = std::string(ref,(size_t)(s-ref)) + "/Resources"; 08048 } 08049 } 08050 } 08051 08052 /* If we were launched by the Finder, the current working directory will usually be 08053 the root of the filesystem (/) which is useless. If we see that, change instead 08054 to the user's home directory */ 08055 { 08056 char *home = getenv("HOME"); 08057 char cwd[512]; 08058 08059 cwd[0]=0; 08060 getcwd(cwd,sizeof(cwd)-1); 08061 08062 if (!strcmp(cwd,"/")) { 08063 /* Only the Finder would do that. 08064 Even if the user somehow did this from the Terminal app, it's still 08065 worth changing to the home directory because certain directories 08066 including / are locked readonly even for sudo in Mac OS X */ 08067 /* NTS: HOME is usually an absolute path */ 08068 if (home != NULL) chdir(home); 08069 } 08070 } 08071 #endif 08072 08073 { 08074 std::string tmp,config_path,config_combined; 08075 08076 /* -- parse command line arguments */ 08077 if (!DOSBOX_parse_argv()) return 1; 08078 08079 if (control->opt_time_limit > 0) 08080 time_limit_ms = (Bitu)(control->opt_time_limit * 1000); 08081 08082 if (control->opt_console) 08083 DOSBox_ShowConsole(); 08084 08085 /* -- Handle some command line options */ 08086 if (control->opt_eraseconf || control->opt_resetconf) 08087 eraseconfigfile(); 08088 if (control->opt_printconf) 08089 printconfiglocation(); 08090 if (control->opt_erasemapper || control->opt_resetmapper) 08091 erasemapperfile(); 08092 08093 /* -- Early logging init, in case these details are needed to debug problems at this level */ 08094 /* If --early-debug was given this opens up logging to STDERR until Log::Init() */ 08095 LOG::EarlyInit(); 08096 08097 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 08098 { 08099 DISPLAY_DEVICE dd; 08100 unsigned int i = 0; 08101 08102 do { 08103 memset(&dd, 0, sizeof(dd)); 08104 dd.cb = sizeof(dd); 08105 if (!EnumDisplayDevices(NULL, i, &dd, 0)) break; 08106 LOG_MSG("Win32 EnumDisplayDevices #%d: name=%s string=%s", i, dd.DeviceName, dd.DeviceString); 08107 i++; 08108 08109 if (strstr(dd.DeviceString, "VirtualBox") != NULL) 08110 isVirtualBox = true; 08111 } while (1); 08112 } 08113 #endif 08114 08115 /* -- Init the configuration system and add default values */ 08116 CheckNumLockState(); 08117 CheckCapsLockState(); 08118 CheckScrollLockState(); 08119 08120 /* -- setup the config sections for config parsing */ 08121 SDL_SetupConfigSection(); 08122 LOG::SetupConfigSection(); 08123 DOSBOX_SetupConfigSections(); 08124 08125 /* -- Parse configuration files */ 08126 Cross::GetPlatformConfigDir(config_path); 08127 08128 /* -- -- first the user config file */ 08129 if (control->opt_userconf) { 08130 tmp.clear(); 08131 Cross::GetPlatformConfigDir(config_path); 08132 Cross::GetPlatformConfigName(tmp); 08133 config_combined = config_path + tmp; 08134 08135 LOG(LOG_MISC,LOG_DEBUG)("Loading config file according to -userconf from %s",config_combined.c_str()); 08136 control->ParseConfigFile(config_combined.c_str()); 08137 if (!control->configfiles.size()) { 08138 //Try to create the userlevel configfile. 08139 tmp.clear(); 08140 Cross::CreatePlatformConfigDir(config_path); 08141 Cross::GetPlatformConfigName(tmp); 08142 config_combined = config_path + tmp; 08143 08144 LOG(LOG_MISC,LOG_DEBUG)("Attempting to write config file according to -userconf, to %s",config_combined.c_str()); 08145 if (control->PrintConfig(config_combined.c_str())) { 08146 LOG(LOG_MISC,LOG_NORMAL)("Generating default configuration. Writing it to %s",config_combined.c_str()); 08147 //Load them as well. Makes relative paths much easier 08148 control->ParseConfigFile(config_combined.c_str()); 08149 } 08150 } 08151 } 08152 08153 /* -- -- second the -conf switches from the command line */ 08154 for (size_t si=0;si < control->config_file_list.size();si++) { 08155 std::string &cfg = control->config_file_list[si]; 08156 if (!control->ParseConfigFile(cfg.c_str())) { 08157 // try to load it from the user directory 08158 control->ParseConfigFile((config_path + cfg).c_str()); 08159 if (!control->ParseConfigFile((config_path + cfg).c_str())) { 08160 LOG_MSG("CONFIG: Can't open specified config file: %s",cfg.c_str()); 08161 } 08162 } 08163 } 08164 08165 /* -- -- if none found, use dosbox-x.conf or dosbox.conf */ 08166 if (!control->configfiles.size()) control->ParseConfigFile("dosbox-x.conf"); 08167 if (!control->configfiles.size()) control->ParseConfigFile("dosbox.conf"); 08168 08169 /* -- -- if none found, use userlevel conf */ 08170 if (!control->configfiles.size()) { 08171 tmp.clear(); 08172 Cross::GetPlatformConfigName(tmp); 08173 control->ParseConfigFile((config_path + tmp).c_str()); 08174 } 08175 08176 MSG_Add("PROGRAM_CONFIG_PROPERTY_ERROR","No such section or property.\n"); 08177 MSG_Add("PROGRAM_CONFIG_NO_PROPERTY","There is no property %s in section %s.\n"); 08178 MSG_Add("PROGRAM_CONFIG_SET_SYNTAX","The syntax for -set option is incorrect.\n"); 08179 for (auto it=control->opt_set.begin(); it!=control->opt_set.end();it++) { /* -set switches */ 08180 // add rest of command 08181 std::string rest; 08182 std::vector<std::string> pvars; 08183 pvars.clear(); 08184 pvars.push_back(trim((char *)(*it).c_str())); 08185 if (!strlen(pvars[0].c_str())) continue; 08186 if (pvars[0][0]=='%'||pvars[0][0]=='\0'||pvars[0][0]=='#'||pvars[0][0]=='\n') continue; 08187 08188 08189 // attempt to split off the first word 08190 std::string::size_type spcpos = pvars[0].find_first_of(' '); 08191 if (spcpos>1&&pvars[0].c_str()[spcpos-1]==',') 08192 spcpos=pvars[0].find_first_of(' ', spcpos+1); 08193 08194 std::string::size_type equpos = pvars[0].find_first_of('='); 08195 08196 if ((equpos != std::string::npos) && 08197 ((spcpos == std::string::npos) || (equpos < spcpos))) { 08198 // If we have a '=' possibly before a ' ' split on the = 08199 pvars.insert(pvars.begin()+1,pvars[0].substr(equpos+1)); 08200 pvars[0].erase(equpos); 08201 // As we had a = the first thing must be a property now 08202 Section* sec=control->GetSectionFromProperty(pvars[0].c_str()); 08203 if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); 08204 else { 08205 LOG_MSG("%s", MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); 08206 continue; 08207 } 08208 // order in the vector should be ok now 08209 } else { 08210 if (equpos != std::string::npos && spcpos < equpos) { 08211 // ' ' before a possible '=', split on the ' ' 08212 pvars.insert(pvars.begin()+1,pvars[0].substr(spcpos+1)); 08213 pvars[0].erase(spcpos); 08214 } 08215 // check if the first parameter is a section or property 08216 Section* sec = control->GetSection(pvars[0].c_str()); 08217 if (!sec) { 08218 // not a section: little duplicate from above 08219 sec=control->GetSectionFromProperty(pvars[0].c_str()); 08220 if (sec) pvars.insert(pvars.begin(),std::string(sec->GetName())); 08221 else { 08222 LOG_MSG("%s", MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR")); 08223 continue; 08224 } 08225 } else { 08226 // first of pvars is most likely a section, but could still be gus 08227 // have a look at the second parameter 08228 if (pvars.size() < 2) { 08229 LOG_MSG("%s", MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); 08230 continue; 08231 } 08232 std::string::size_type equpos2 = pvars[1].find_first_of('='); 08233 if (equpos2 != std::string::npos) { 08234 // split on the = 08235 pvars.insert(pvars.begin()+2,pvars[1].substr(equpos2+1)); 08236 pvars[1].erase(equpos2); 08237 } 08238 // is this a property? 08239 Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); 08240 if (!sec2) { 08241 // not a property, 08242 Section* sec3 = control->GetSectionFromProperty(pvars[0].c_str()); 08243 if (sec3) { 08244 // section and property name are identical 08245 pvars.insert(pvars.begin(),pvars[0]); 08246 } // else has been checked above already 08247 } 08248 } 08249 } 08250 if(pvars.size() < 3) { 08251 LOG_MSG("%s", MSG_Get("PROGRAM_CONFIG_SET_SYNTAX")); 08252 continue; 08253 } 08254 // check if the property actually exists in the section 08255 Section* sec2 = control->GetSectionFromProperty(pvars[1].c_str()); 08256 if (!sec2) { 08257 LOG_MSG(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"), 08258 pvars[1].c_str(),pvars[0].c_str()); 08259 continue; 08260 } 08261 // Input has been parsed (pvar[0]=section, [1]=property, [2]=value) 08262 // now execute 08263 Section* tsec = control->GetSection(pvars[0]); 08264 std::string value(pvars[2]); 08265 //Due to parsing there can be a = at the start of value. 08266 while (value.size() && (value.at(0) ==' ' ||value.at(0) =='=') ) value.erase(0,1); 08267 for(Bitu i = 3; i < pvars.size(); i++) value += (std::string(" ") + pvars[i]); 08268 std::string inputline = pvars[1] + "=" + value; 08269 08270 bool change_success = tsec->HandleInputline(inputline.c_str()); 08271 if (!change_success&&!value.empty()) LOG_MSG("Cannot set \"%s\"\n", inputline.c_str()); 08272 } 08273 08274 // Redirect existing PC-98 related settings from other sections to the [pc98] section if the latter is empty 08275 Section_prop * pc98_section = static_cast<Section_prop *>(control->GetSection("pc98")); 08276 assert(pc98_section != NULL); 08277 const char * extra = const_cast<char*>(pc98_section->data.c_str()); 08278 if (!extra||!strlen(extra)) { 08279 char linestr[CROSS_LEN+1], *p; 08280 Section_prop * section = static_cast<Section_prop *>(control->GetSection("dosbox")); 08281 extra = const_cast<char*>(section->data.c_str()); 08282 if (extra&&strlen(extra)) { 08283 std::istringstream in(extra); 08284 if (in) for (std::string line; std::getline(in, line); ) { 08285 if (strncasecmp(line.c_str(), "pc-98 ", 6)) continue; 08286 if (line.length()>CROSS_LEN) { 08287 strncpy(linestr, line.c_str(), CROSS_LEN); 08288 linestr[CROSS_LEN]=0; 08289 } else 08290 strcpy(linestr, line.c_str()); 08291 p=strchr(linestr, '='); 08292 if (p!=NULL&&pc98_section->HandleInputline(line)) { 08293 *p=0; 08294 LOG_MSG("Redirected \"%s\" from [dosbox] to [pc98] section\n", trim(linestr)); 08295 } 08296 } 08297 } 08298 section = static_cast<Section_prop *>(control->GetSection("dos")); 08299 extra = const_cast<char*>(section->data.c_str()); 08300 if (extra&&strlen(extra)) { 08301 std::istringstream in(extra); 08302 if (in) for (std::string line; std::getline(in, line); ) { 08303 if (strncasecmp(line.c_str(), "pc-98 ", 6)) continue; 08304 if (line.length()>CROSS_LEN) { 08305 strncpy(linestr, line.c_str(), CROSS_LEN); 08306 linestr[CROSS_LEN]=0; 08307 } else 08308 strcpy(linestr, line.c_str()); 08309 p=strchr(linestr, '='); 08310 if (p!=NULL&&pc98_section->HandleInputline(line)) { 08311 *p=0; 08312 LOG_MSG("Redirected \"%s\" from [dos] to [pc98] section\n", trim(linestr)); 08313 } 08314 } 08315 } 08316 } 08317 08318 // Redirect existing files= setting from [dos] section to the [config] section if the latter is empty 08319 Section_prop * config_section = static_cast<Section_prop *>(control->GetSection("config")); 08320 assert(config_section != NULL); 08321 extra = const_cast<char*>(config_section->data.c_str()); 08322 if (!extra||!strlen(extra)) { 08323 char linestr[CROSS_LEN+1], *p; 08324 Section_prop * section = static_cast<Section_prop *>(control->GetSection("dos")); 08325 extra = const_cast<char*>(section->data.c_str()); 08326 if (extra&&strlen(extra)) { 08327 std::istringstream in(extra); 08328 if (in) for (std::string line; std::getline(in, line); ) { 08329 if (strncasecmp(line.c_str(), "files", 5)&&strncasecmp(line.c_str(), "dos in hma", 10)) continue; 08330 if (line.length()>CROSS_LEN) { 08331 strncpy(linestr, line.c_str(), CROSS_LEN); 08332 linestr[CROSS_LEN]=0; 08333 } else 08334 strcpy(linestr, line.c_str()); 08335 p=strchr(linestr, '='); 08336 if (p!=NULL) { 08337 if (!strncasecmp(line.c_str(), "dos in hma", 10)) { 08338 if (!strcasecmp(trim(p+1), "true")) line="dos=high"; 08339 else if (!strcasecmp(trim(p+1), "false")) line="dos=low"; 08340 } 08341 if (config_section->HandleInputline(line)) { 08342 *p=0; 08343 LOG_MSG("Redirected \"%s\" from [dos] to [config] section\n", trim(linestr)); 08344 } 08345 } 08346 } 08347 } 08348 } 08349 08350 #if (ENVIRON_LINKED) 08351 /* -- parse environment block (why?) */ 08352 control->ParseEnv(environ); 08353 #endif 08354 08355 /* -- initialize logging first, so that higher level inits can report problems to the log file */ 08356 LOG::Init(); 08357 08358 #if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS) 08359 { 08360 DISPLAY_DEVICE dd; 08361 unsigned int i = 0; 08362 08363 do { 08364 memset(&dd, 0, sizeof(dd)); 08365 dd.cb = sizeof(dd); 08366 if (!EnumDisplayDevices(NULL, i, &dd, 0)) break; 08367 LOG_MSG("Win32 EnumDisplayDevices #%d: name=%s string=%s", i, dd.DeviceName, dd.DeviceString); 08368 i++; 08369 } while (1); 08370 } 08371 08372 if (isVirtualBox) LOG_MSG("Win32 VirtualBox graphics adapter detected"); 08373 #endif 08374 08375 /* -- Welcome to DOSBox-X! */ 08376 LOG_MSG("DOSBox-X version %s",VERSION); 08377 LOG(LOG_MISC,LOG_NORMAL)("Copyright 2002-2019 enhanced branch by The Great Codeholio, forked from the main project by the DOSBox Team, published under GNU GPL."); 08378 08379 #if defined(MACOSX) 08380 LOG_MSG("Mac OS X EXE path: %s",MacOSXEXEPath.c_str()); 08381 LOG_MSG("Mac OS X Resource path: %s",MacOSXResPath.c_str()); 08382 #endif 08383 08384 /* -- [debug] setup console */ 08385 #if C_DEBUG 08386 # if defined(WIN32) && !defined(HX_DOS) 08387 /* Can't disable the console with debugger enabled */ 08388 if (control->opt_noconsole) { 08389 LOG(LOG_MISC,LOG_DEBUG)("-noconsole: hiding Win32 console window"); 08390 ShowWindow(GetConsoleWindow(), SW_HIDE); 08391 DestroyWindow(GetConsoleWindow()); 08392 } 08393 # endif 08394 #endif 08395 08396 #if defined(WIN32) 08397 /* -- Windows: set console control handler */ 08398 SetConsoleCtrlHandler((PHANDLER_ROUTINE) ConsoleEventHandler,TRUE); 08399 #endif 08400 08401 #if !defined(C_SDL2) 08402 { 08403 int id, major, minor; 08404 08405 DOSBox_CheckOS(id, major, minor); 08406 if (id == 1) menu.compatible=true; 08407 08408 /* use all variables to shut up the compiler about unused vars */ 08409 LOG(LOG_MISC,LOG_DEBUG)("DOSBox_CheckOS results: id=%u major=%u minor=%u",id,major,minor); 08410 } 08411 #endif 08412 08413 /* -- SDL init hackery */ 08414 #if SDL_VERSION_ATLEAST(1, 2, 14) 08415 /* hack: On debian/ubuntu with older libsdl version as they have done this themselves, but then differently. 08416 * with this variable they will work correctly. I've only tested the 1.2.14 behaviour against the windows version of libsdl */ 08417 putenv(const_cast<char*>("SDL_DISABLE_LOCK_KEYS=1")); 08418 LOG(LOG_GUI,LOG_DEBUG)("SDL 1.2.14 hack: SDL_DISABLE_LOCK_KEYS=1"); 08419 #endif 08420 08421 #ifdef WIN32 08422 /* hack: Encourage SDL to use windib if not otherwise specified */ 08423 if (getenv("SDL_VIDEODRIVER") == NULL) { 08424 #if defined(C_SDL2) 08425 LOG(LOG_GUI, LOG_DEBUG)("Win32 hack: setting SDL_VIDEODRIVER=windows because environ variable is not set"); 08426 putenv("SDL_VIDEODRIVER=windows"); 08427 #else 08428 LOG(LOG_GUI,LOG_DEBUG)("Win32 hack: setting SDL_VIDEODRIVER=windib because environ variable is not set"); 08429 putenv("SDL_VIDEODRIVER=windib"); 08430 #endif 08431 sdl.using_windib=true; 08432 } 08433 #endif 08434 08435 #if defined(WIN32) && defined(C_SDL2) 08436 /* HACK: WASAPI output on Windows 10 isn't working... */ 08437 if (getenv("SDL_AUDIODRIVER") == NULL) { 08438 LOG(LOG_GUI, LOG_DEBUG)("Win32: using directsound audio driver"); 08439 putenv("SDL_AUDIODRIVER=directsound"); 08440 } 08441 #endif 08442 08443 sdl.init_ignore = true; 08444 08445 { 08446 Section_prop *section = static_cast<Section_prop *>(control->GetSection("dosbox")); 08447 assert(section != NULL); 08448 08449 // boot-time option whether or not to report ourself as "DPI aware" to Windows so the 08450 // DWM doesn't upscale our window for backwards compat. 08451 { 08452 std::string dpiw = section->Get_string("dpi aware"); 08453 08454 if (dpiw == "1" || dpiw == "true") { 08455 dpi_aware_enable = true; 08456 } 08457 else if (dpiw == "0" || dpiw == "false") { 08458 dpi_aware_enable = false; 08459 } 08460 else { /* auto */ 08461 #if defined(MACOSX) 08462 /* Try not to look extra tiny on Retina displays */ 08463 dpi_aware_enable = false; 08464 #elif defined(WIN32) && !defined(HX_DOS) 08465 dpi_aware_enable = true; 08466 UINT dpi=0; 08467 HMODULE __user32 = GetModuleHandle("USER32.DLL"); 08468 if (__user32) { 08469 DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); 08470 #ifndef DPI_AWARENESS_CONTEXT_SYSTEM_AWARE 08471 #define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2) 08472 #endif 08473 DPI_AWARENESS_CONTEXT (WINAPI *__SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT) = NULL; 08474 UINT (WINAPI *__GetDpiForSystem)() = NULL; 08475 __SetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(DPI_AWARENESS_CONTEXT))GetProcAddress(__user32,"SetThreadDpiAwarenessContext"); 08476 __GetDpiForSystem = (UINT (WINAPI *)())GetProcAddress(__user32,"GetDpiForSystem"); 08477 if (__SetThreadDpiAwarenessContext && __GetDpiForSystem) { 08478 DPI_AWARENESS_CONTEXT previousDpiContext = __SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); 08479 dpi=__GetDpiForSystem(); 08480 if (previousDpiContext!=NULL) __SetThreadDpiAwarenessContext(previousDpiContext); 08481 } 08482 } 08483 if (dpi&&dpi/96>1) dpi_aware_enable = false; 08484 #else 08485 dpi_aware_enable = true; 08486 #endif 08487 } 08488 } 08489 } 08490 08491 #ifdef WIN32 08492 /* Windows Vista/7/8/10 DPI awareness. If we don't tell Windows we're high DPI aware, the DWM will 08493 * upscale our window to emulate a 96 DPI display which on high res screen will make our UI look blurry. 08494 * But we obey the user if they don't want us to do that. */ 08495 Windows_DPI_Awareness_Init(); 08496 #endif 08497 #if defined(MACOSX) && !defined(C_SDL2) 08498 /* Our SDL1 in-tree library has a High DPI awareness function for Mac OS X now */ 08499 if (!control->opt_disable_dpi_awareness) 08500 sdl1_hax_macosx_highdpi_set_enable(dpi_aware_enable); 08501 #endif 08502 08503 #ifdef MACOSX 08504 osx_detect_nstouchbar();/*assigns to has_touch_bar_support*/ 08505 if (has_touch_bar_support) { 08506 LOG_MSG("Mac OS X: NSTouchBar support detected in system"); 08507 osx_init_touchbar(); 08508 } 08509 08510 extern void osx_init_dock_menu(void); 08511 osx_init_dock_menu(); 08512 08513 void qz_set_match_monitor_cb(void); 08514 qz_set_match_monitor_cb(); 08515 #endif 08516 08517 /* -- SDL init */ 08518 if (SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE) >= 0) 08519 sdl.inited = true; 08520 else 08521 E_Exit("Can't init SDL %s",SDL_GetError()); 08522 08523 /* -- -- decide whether to show menu in GUI */ 08524 if (control->opt_nogui || menu.compatible) 08525 menu.gui=false; 08526 08527 /* -- -- helpful advice */ 08528 LOG(LOG_GUI,LOG_NORMAL)("Press Ctrl-F10 to capture/release mouse, Alt-F10 for configuration."); 08529 08530 /* -- -- other steps to prepare SDL window/output */ 08531 SDL_Prepare(); 08532 08533 /* -- NOW it is safe to send change events to SDL */ 08534 { 08535 Section_prop *sdl_sec = static_cast<Section_prop*>(control->GetSection("sdl")); 08536 sdl_sec->onpropchange.push_back(&SDL_OnSectionPropChange); 08537 } 08538 08539 /* -- -- Keyboard layout detection and setup */ 08540 KeyboardLayoutDetect(); 08541 SetMapperKeyboardLayout(host_keyboard_layout); 08542 08543 /* -- -- Initialise Joystick and CD-ROM seperately. This way we can warn when it fails instead of exiting the application */ 08544 LOG(LOG_MISC,LOG_DEBUG)("Initializing SDL joystick subsystem..."); 08545 if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0) { 08546 sdl.num_joysticks = (Bitu)SDL_NumJoysticks(); 08547 LOG(LOG_MISC,LOG_DEBUG)("SDL reports %u joysticks",(unsigned int)sdl.num_joysticks); 08548 } 08549 else { 08550 LOG(LOG_GUI,LOG_WARN)("Failed to init joystick support"); 08551 sdl.num_joysticks = 0; 08552 } 08553 08554 #if !defined(C_SDL2) 08555 if (SDL_InitSubSystem(SDL_INIT_CDROM) < 0) { 08556 LOG(LOG_GUI,LOG_WARN)("Failed to init CD-ROM support"); 08557 } 08558 #endif 08559 08560 /* must redraw after modeset */ 08561 sdl.must_redraw_all = true; 08562 sdl.deferred_resize = false; 08563 08564 /* assume L+R ALT keys are up */ 08565 sdl.laltstate = SDL_KEYUP; 08566 sdl.raltstate = SDL_KEYUP; 08567 sdl.lctrlstate = SDL_KEYUP; 08568 sdl.rctrlstate = SDL_KEYUP; 08569 sdl.lshiftstate = SDL_KEYUP; 08570 sdl.rshiftstate = SDL_KEYUP; 08571 08572 #if defined(WIN32) && !defined(C_SDL2) 08573 # if SDL_VERSION_ATLEAST(1, 2, 10) 08574 sdl.using_windib=true; 08575 # else 08576 sdl.using_windib=false; 08577 # endif 08578 08579 if (getenv("SDL_VIDEODRIVER")==NULL) { 08580 putenv("SDL_VIDEODRIVER=windib"); 08581 if (SDL_InitSubSystem(SDL_INIT_VIDEO)<0) E_Exit("Can't init SDL Video %s",SDL_GetError()); 08582 sdl.using_windib=true; 08583 } else { 08584 char* sdl_videodrv = getenv("SDL_VIDEODRIVER"); 08585 08586 LOG(LOG_MISC,LOG_DEBUG)("Win32: SDL_VIDEODRIVER is '%s', so I will obey it",sdl_videodrv); 08587 if (strcmp(sdl_videodrv,"directx")==0) sdl.using_windib = false; 08588 else if (strcmp(sdl_videodrv,"windib")==0) sdl.using_windib = true; 08589 } 08590 #endif 08591 08592 /* GUI init */ 08593 GUI_StartUp(); 08594 08595 /* FIXME: We need a more general "init list", outside of the section-based design, 08596 * that we then execute serially here. */ 08597 /* TODO: Each section currently uses "AddDestroyFunction" per section. We need to 08598 * change over that code to a global destroy callback list instead. */ 08599 /* TODO: Get rid of "init" and "destroy" callback lists per section. */ 08600 /* TODO: Add a global (within the Config object) init and destroy callback list. 08601 * On each call, init functions are added to the end of the list, and 08602 * destroy functions added to the beginning of the list. That way, init 08603 * is lowest level to highest, destroy is highest level to lowest. */ 08604 /* TODO: Config object should also have a "reset" callback list. On system 08605 * reset each device would be notified so that it can emulate hardware 08606 * reset (the RESET line on ISA/PCI bus), lowest level to highest. */ 08607 /* TODO: Each "init" function should do the work of getting the section object, 08608 * whatever section it wants to read, instead of us doing the work. When 08609 * that's complete, the call to init should be without parameters (void). 08610 * The hope is that the init functions can read whatever sections it wants, 08611 * both newer DOSBox-X sections and existing DOSBox (mainline) compatible 08612 * sections. */ 08613 08614 /* The order is important here: 08615 * Init functions are called low-level first to high level last, 08616 * because some init functions rely on others. */ 08617 08618 #if !defined(C_SDL2) 08619 # if defined(WIN32) 08620 Reflect_Menu(); 08621 # endif 08622 #endif 08623 08624 /* stock top-level menu items */ 08625 { 08626 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"MainMenu"); 08627 item.set_text("Main"); 08628 { 08629 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"MainSendKey"); 08630 item.set_text("Send special key"); 08631 } 08632 } 08633 { 08634 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuMenu"); 08635 item.set_text("CPU"); 08636 { 08637 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuCoreMenu"); 08638 item.set_text("CPU core"); 08639 } 08640 { 08641 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CpuTypeMenu"); 08642 item.set_text("CPU type"); 08643 } 08644 } 08645 { 08646 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoMenu"); 08647 item.set_text("Video"); 08648 { 08649 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoFrameskipMenu"); 08650 item.set_text("Frameskip"); 08651 08652 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"frameskip_0").set_text("Off"). 08653 set_callback_function(video_frameskip_common_menu_callback); 08654 08655 for (unsigned int f=1;f <= 10;f++) { 08656 char tmp1[64],tmp2[64]; 08657 08658 sprintf(tmp1,"frameskip_%u",f); 08659 sprintf(tmp2,"%u frame",f); 08660 08661 mainMenu.alloc_item(DOSBoxMenu::item_type_id,tmp1).set_text(tmp2). 08662 set_callback_function(video_frameskip_common_menu_callback); 08663 } 08664 } 08665 { 08666 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoScalerMenu"); 08667 item.set_text("Scaler"); 08668 08669 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"scaler_forced").set_text("Force scaler"). 08670 set_callback_function(scaler_forced_menu_callback); 08671 08672 for (size_t i=0;scaler_menu_opts[i][0] != NULL;i++) { 08673 const std::string name = std::string("scaler_set_") + scaler_menu_opts[i][0]; 08674 08675 mainMenu.alloc_item(DOSBoxMenu::item_type_id,name).set_text(scaler_menu_opts[i][1]). 08676 set_callback_function(scaler_set_menu_callback); 08677 } 08678 } 08679 { 08680 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoCompatMenu"); 08681 item.set_text("Compatibility"); 08682 08683 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vga_9widetext").set_text("Allow 9-pixel wide text mode"). 08684 set_callback_function(vga_9widetext_menu_callback); 08685 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"doublescan").set_text("Doublescan"). 08686 set_callback_function(doublescan_menu_callback); 08687 } 08688 { 08689 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoOutputMenu"); 08690 item.set_text("Output"); 08691 08692 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_surface").set_text("Surface"). 08693 set_callback_function(output_menu_callback); 08694 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_direct3d").set_text("Direct3D"). 08695 set_callback_function(output_menu_callback); 08696 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_opengl").set_text("OpenGL"). 08697 set_callback_function(output_menu_callback); 08698 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_openglnb").set_text("OpenGL NB"). 08699 set_callback_function(output_menu_callback); 08700 } 08701 { 08702 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoVsyncMenu"); 08703 item.set_text("V-Sync"); 08704 08705 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_on").set_text("On"). 08706 set_callback_function(vsync_menu_callback); 08707 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_force").set_text("Force"). 08708 set_callback_function(vsync_menu_callback); 08709 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_host").set_text("Host"). 08710 set_callback_function(vsync_menu_callback); 08711 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_off").set_text("Off"). 08712 set_callback_function(vsync_menu_callback); 08713 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"vsync_set_syncrate").set_text("Set syncrate"). 08714 set_callback_function(vsync_set_syncrate_menu_callback); 08715 } 08716 { 08717 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoOverscanMenu"); 08718 item.set_text("Overscan"); 08719 08720 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"overscan_0").set_text("Off"). 08721 set_callback_function(overscan_menu_callback); 08722 08723 for (size_t i=1;i <= 10;i++) { 08724 char tmp1[64],tmp2[64]; 08725 08726 sprintf(tmp1,"overscan_%zu",i); 08727 sprintf(tmp2,"%zu",i); 08728 mainMenu.alloc_item(DOSBoxMenu::item_type_id,tmp1).set_text(tmp2). 08729 set_callback_function(overscan_menu_callback); 08730 } 08731 } 08732 { 08733 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoPC98Menu"); 08734 item.set_text("PC-98"); 08735 08736 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_5mhz_gdc").set_text("5MHz GDC clock"). 08737 set_callback_function(vid_pc98_5mhz_gdc_menu_callback); 08738 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_allow_200scanline").set_text("Allow 200-line scanline effect"). 08739 set_callback_function(vid_pc98_200scanline_menu_callback); 08740 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_allow_4partitions").set_text("Allow 4 display partitions in graphics layer"). 08741 set_callback_function(vid_pc98_4parts_menu_callback); 08742 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_egc").set_text("Enable EGC"). 08743 set_callback_function(vid_pc98_enable_egc_menu_callback); 08744 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_grcg").set_text("Enable GRCG"). 08745 set_callback_function(vid_pc98_enable_grcg_menu_callback); 08746 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_analog").set_text("Enable analog display"). 08747 set_callback_function(vid_pc98_enable_analog_menu_callback); 08748 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_analog256").set_text("Enable analog 256-color display"). 08749 set_callback_function(vid_pc98_enable_analog256_menu_callback); 08750 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_enable_188user").set_text("Enable 188+ user CG cells"). 08751 set_callback_function(vid_pc98_enable_188user_menu_callback); 08752 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_clear_text").set_text("Clear text layer"). 08753 set_callback_function(vid_pc98_cleartext_menu_callback); 08754 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"pc98_clear_graphics").set_text("Clear graphics layer"). 08755 set_callback_function(vid_pc98_graphics_menu_callback); 08756 } 08757 { 08758 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"VideoDebugMenu"); 08759 item.set_text("Debug"); 08760 } 08761 #ifdef C_D3DSHADERS 08762 { 08763 mainMenu.alloc_item(DOSBoxMenu::item_type_id, "load_d3d_shader").set_text("Select pixel shader..."). 08764 set_callback_function(vid_select_pixel_shader_menu_callback); 08765 } 08766 #endif 08767 } 08768 { 08769 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"SoundMenu"); 08770 item.set_text("Sound"); 08771 08772 { 08773 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"mixer_swapstereo").set_text("Swap stereo"). 08774 set_callback_function(mixer_swapstereo_menu_callback); 08775 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"mixer_mute").set_text("Mute"). 08776 set_callback_function(mixer_mute_menu_callback); 08777 } 08778 } 08779 { 08780 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSMenu"); 08781 item.set_text("DOS"); 08782 08783 { 08784 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSMouseMenu"); 08785 item.set_text("Mouse"); 08786 08787 { 08788 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_enable_int33").set_text("Internal Emulation"). 08789 set_callback_function(dos_mouse_enable_int33_menu_callback); 08790 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_y_axis_reverse").set_text("Y-axis Reverse"). 08791 set_callback_function(dos_mouse_y_axis_reverse_menu_callback); 08792 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_mouse_sensitivity").set_text("Sensitivity"). 08793 set_callback_function(dos_mouse_sensitivity_menu_callback); 08794 } 08795 } 08796 08797 { 08798 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSLFNMenu"); 08799 item.set_text("Long filename support"); 08800 08801 { 08802 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_lfn_auto").set_text("Auto"). 08803 set_callback_function(dos_lfn_auto_menu_callback); 08804 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_lfn_enable").set_text("Enable"). 08805 set_callback_function(dos_lfn_enable_menu_callback); 08806 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_lfn_disable").set_text("Disable"). 08807 set_callback_function(dos_lfn_disable_menu_callback); 08808 } 08809 } 08810 08811 { 08812 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSPC98Menu"); 08813 item.set_text("PC-98 PIT master clock"); 08814 08815 { 08816 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_pc98_pit_4mhz").set_text("4MHz/8MHz"). 08817 set_callback_function(dos_pc98_clock_menu_callback); 08818 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"dos_pc98_pit_5mhz").set_text("5MHz/10MHz"). 08819 set_callback_function(dos_pc98_clock_menu_callback); 08820 } 08821 } 08822 08823 { 08824 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DOSDebugMenu"); 08825 item.set_text("Debug"); 08826 08827 { 08828 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"debug_logint21").set_text("Log INT 21h calls"). 08829 set_callback_function(dos_debug_menu_callback); 08830 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"debug_logfileio").set_text("Log file I/O"). 08831 set_callback_function(dos_debug_menu_callback); 08832 } 08833 } 08834 } 08835 #if !defined(C_EMSCRIPTEN) 08836 { 08837 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CaptureMenu"); 08838 item.set_text("Capture"); 08839 } 08840 # if (C_SSHOT) 08841 { 08842 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"CaptureFormatMenu"); 08843 item.set_text("Capture format"); 08844 08845 { 08846 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"capture_fmt_avi_zmbv").set_text("AVI + ZMBV"). 08847 set_callback_function(capture_fmt_menu_callback); 08848 # if (C_AVCODEC) 08849 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"capture_fmt_mpegts_h264").set_text("MPEG-TS + H.264"). 08850 set_callback_function(capture_fmt_menu_callback); 08851 # endif 08852 } 08853 } 08854 # endif 08855 { 08856 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"saveslotmenu"); 08857 item.set_text("Select save slot"); 08858 08859 { 08860 DOSBoxMenu::callback_t callbacks[SaveState::SLOT_COUNT] = {save_slot_0_callback, save_slot_1_callback, save_slot_2_callback, save_slot_3_callback, save_slot_4_callback, save_slot_5_callback, save_slot_6_callback, save_slot_7_callback, save_slot_8_callback, save_slot_9_callback}; 08861 char name[6]="slot0"; 08862 for (unsigned int i=0; i<SaveState::SLOT_COUNT; i++) { 08863 name[4]='0'+i; 08864 std::string command=SaveState::instance().getName(i); 08865 std::string str="Slot "+(i>=9?"10":std::string(1, '1'+i))+(command=="[Empty]"?" [Empty slot]":(command==""?"":" (Program: "+command+")")); 08866 mainMenu.alloc_item(DOSBoxMenu::item_type_id,name).set_text(str.c_str()).set_callback_function(callbacks[i]); 08867 } 08868 } 08869 char name[6]="slot0"; 08870 name[4]='0'+GetGameState_Run(); 08871 mainMenu.get_item(name).check(true).refresh_item(mainMenu); 08872 } 08873 #endif 08874 { 08875 DOSBoxMenu::item &item = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,"DriveMenu"); 08876 item.set_text("Drive"); 08877 08878 for (char c='A';c <= 'Z';c++) { 08879 std::string dmenu = "Drive"; 08880 dmenu += c; 08881 08882 std::string dmenut; 08883 dmenut = c; 08884 08885 DOSBoxMenu::item &ditem = mainMenu.alloc_item(DOSBoxMenu::submenu_type_id,dmenu.c_str()); 08886 ditem.set_text(dmenut.c_str()); 08887 08888 for (size_t i=0;drive_opts[i][0] != NULL;i++) { 08889 if ((!strcmp(drive_opts[i][0], "boot")||!strcmp(drive_opts[i][0], "bootimg"))&&(c!='A'&&c!='C'&&c!='D')) continue; 08890 const std::string name = std::string("drive_") + c + "_" + drive_opts[i][0]; 08891 08892 mainMenu.alloc_item(DOSBoxMenu::item_type_id,name).set_text(drive_opts[i][1]). 08893 set_callback_function(drive_callbacks[i]); 08894 } 08895 } 08896 } 08897 08898 if (control->opt_startui) 08899 GUI_Run(false); 08900 if (control->opt_editconf.length() != 0) 08901 launcheditor(control->opt_editconf); 08902 if (control->opt_opencaptures.length() != 0) 08903 launchcaptures(control->opt_opencaptures); 08904 if (control->opt_opensaves.length() != 0) 08905 launchsaves(control->opt_opensaves); 08906 08907 { 08908 /* Some extra SDL Functions */ 08909 Section_prop* sdl_sec = static_cast<Section_prop*>(control->GetSection("sdl")); 08910 08911 if (control->opt_fullscreen || sdl_sec->Get_bool("fullscreen")) { 08912 LOG(LOG_MISC, LOG_DEBUG)("Going fullscreen immediately, during startup"); 08913 08914 #if !defined(C_SDL2) 08915 void DOSBox_SetSysMenu(void); 08916 DOSBox_SetSysMenu(); 08917 #endif 08918 //only switch if not already in fullscreen 08919 if (!sdl.desktop.fullscreen) GFX_SwitchFullScreen(); 08920 } 08921 } 08922 08923 /* Start up main machine */ 08924 08925 // Shows menu bar (window) 08926 menu.startup = true; 08927 menu.showrt = control->opt_showrt; 08928 menu.hidecycles = (control->opt_showcycles ? false : true); 08929 08930 #if defined(WIN32) && !defined(C_SDL2) 08931 { 08932 Section_prop *sec = static_cast<Section_prop *>(control->GetSection("dosbox")); 08933 enable_hook_special_keys = sec->Get_bool("keyboard hook"); 08934 } 08935 #endif 08936 08937 MSG_Init(); 08938 MAPPER_StartUp(); 08939 DOSBOX_InitTickLoop(); 08940 DOSBOX_RealInit(); 08941 08942 /* at this point: If the machine type is PC-98, and the mapper keyboard layout was "Japanese", 08943 * then change the mapper layout to "Japanese PC-98" */ 08944 if (host_keyboard_layout == DKM_JPN && IS_PC98_ARCH) 08945 SetMapperKeyboardLayout(DKM_JPN_PC98); 08946 08947 /* more */ 08948 { 08949 DOSBoxMenu::item *item; 08950 08951 MAPPER_AddHandler(&HideMenu_mapper_shortcut, MK_escape, MMODHOST, "togmenu", "ToggleMenu", &item); 08952 item->set_text("Hide/show menu bar"); 08953 08954 MAPPER_AddHandler(&PauseWithInterrupts_mapper_shortcut, MK_nothing, 0, "pauseints", "PauseInts", &item); 08955 item->set_text("Pause with interrupts enabled"); 08956 } 08957 08958 RENDER_Init(); 08959 CAPTURE_Init(); 08960 IO_Init(); 08961 HARDWARE_Init(); 08962 Init_AddressLimitAndGateMask(); /* <- need to init address mask so Init_RAM knows the maximum amount of RAM possible */ 08963 Init_MemoryAccessArray(); /* <- NTS: In DOSBox-X this is the "cache" of devices that responded to memory access */ 08964 Init_A20_Gate(); // FIXME: Should be handled by motherboard! 08965 Init_PS2_Port_92h(); // FIXME: Should be handled by motherboard! 08966 Init_RAM(); 08967 Init_DMA(); 08968 Init_PIC(); 08969 TIMER_Init(); 08970 PCIBUS_Init(); 08971 PAGING_Init(); /* <- NTS: At this time, must come before memory init because paging is so well integrated into emulation code */ 08972 CMOS_Init(); 08973 ROMBIOS_Init(); 08974 CALLBACK_Init(); /* <- NTS: This relies on ROM BIOS allocation and it must happen AFTER ROMBIOS init */ 08975 #if C_DEBUG 08976 DEBUG_Init(); /* <- NTS: Relies on callback system */ 08977 #endif 08978 Init_VGABIOS(); 08979 VOODOO_Init(); 08980 PROGRAMS_Init(); /* <- NTS: Does not init programs, it inits the callback used later when creating the .COM programs on drive Z: */ 08981 PCSPEAKER_Init(); 08982 TANDYSOUND_Init(); 08983 MPU401_Init(); 08984 MIXER_Init(); 08985 MIDI_Init(); 08986 CPU_Init(); 08987 #if C_FPU 08988 FPU_Init(); 08989 #endif 08990 VGA_Init(); 08991 ISAPNP_Cfg_Init(); 08992 FDC_Primary_Init(); 08993 KEYBOARD_Init(); 08994 SBLASTER_Init(); 08995 JOYSTICK_Init(); 08996 PS1SOUND_Init(); 08997 DISNEY_Init(); 08998 GUS_Init(); 08999 IDE_Init(); 09000 INNOVA_Init(); 09001 BIOS_Init(); 09002 INT10_Init(); 09003 SERIAL_Init(); 09004 DONGLE_Init(); 09005 #if C_PRINTER 09006 PRINTER_Init(); 09007 #endif 09008 PARALLEL_Init(); 09009 #if C_NE2000 09010 NE2K_Init(); 09011 #endif 09012 09013 #if defined(WIN32) && !defined(C_SDL2) 09014 Reflect_Menu(); 09015 #endif 09016 09017 /* If PCjr emulation, map cartridge ROM */ 09018 if (machine == MCH_PCJR) 09019 Init_PCJR_CartridgeROM(); 09020 09021 /* let's assume motherboards are sane on boot because A20 gate is ENABLED on first boot */ 09022 MEM_A20_Enable(true); 09023 09024 /* OS init now */ 09025 DOS_Init(); 09026 DRIVES_Init(); 09027 DOS_KeyboardLayout_Init(); 09028 MOUSE_Init(); // FIXME: inits INT 15h and INT 33h at the same time. Also uses DOS_GetMemory() which is why DOS_Init must come first 09029 XMS_Init(); 09030 EMS_Init(); 09031 AUTOEXEC_Init(); 09032 #if C_IPX 09033 IPX_Init(); 09034 #endif 09035 MSCDEX_Init(); 09036 CDROM_Image_Init(); 09037 09038 /* Init memhandle system. This part is used by DOSBox's XMS/EMS emulation to associate handles 09039 * per page. FIXME: I would like to push this down to the point that it's never called until 09040 * XMS/EMS emulation needs it. I would also like the code to free the mhandle array immediately 09041 * upon booting into a guest OS, since memory handles no longer have meaning in the guest OS 09042 * memory layout. */ 09043 Init_MemHandles(); 09044 09045 /* finally, the mapper */ 09046 MAPPER_Init(); 09047 09048 /* stop at this point, and show the mapper, if instructed */ 09049 if (control->opt_startmapper) { 09050 LOG(LOG_MISC,LOG_DEBUG)("Running mapper interface, during startup, as instructed"); 09051 MAPPER_RunInternal(); 09052 } 09053 09054 /* more */ 09055 std::string doubleBufString = std::string("desktop.doublebuf"); 09056 #if !defined(C_EMSCRIPTEN) 09057 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"show_console").set_text("Show console").set_callback_function(show_console_menu_callback); 09058 #endif 09059 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"wait_on_error").set_text("Wait on error").set_callback_function(wait_on_error_menu_callback).check(sdl.wait_on_error); 09060 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"auto_lock_mouse").set_text("Autolock mouse").set_callback_function(autolock_mouse_menu_callback).check(sdl.mouse.autoenable); 09061 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_ctrlesc").set_text("Ctrl+Esc").set_callback_function(sendkey_preset_menu_callback); 09062 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_alttab").set_text("Alt+Tab").set_callback_function(sendkey_preset_menu_callback); 09063 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_winlogo").set_text("Logo key").set_callback_function(sendkey_preset_menu_callback); 09064 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_winmenu").set_text("Menu key").set_callback_function(sendkey_preset_menu_callback); 09065 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"sendkey_cad").set_text("Ctrl+Alt+Del").set_callback_function(sendkey_preset_menu_callback); 09066 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"doublebuf").set_text("Double Buffering (Fullscreen)").set_callback_function(doublebuf_menu_callback).check(!!GetSetSDLValue(1, doubleBufString, 0)); 09067 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"alwaysontop").set_text("Always on top").set_callback_function(alwaysontop_menu_callback).check(is_always_on_top()); 09068 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"showdetails").set_text("Show details").set_callback_function(showdetails_menu_callback).check(!menu.hidecycles && !menu.showrt); 09069 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"highdpienable").set_text("High DPI enable").set_callback_function(highdpienable_menu_callback).check(dpi_aware_enable); 09070 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"force_loadstate").set_text("Force load state").set_callback_function(force_loadstate_menu_callback).check(force_load_state); 09071 mainMenu.alloc_item(DOSBoxMenu::item_type_id,"refreshslot").set_text("Refresh status").set_callback_function(refresh_slots_menu_callback); 09072 09073 mainMenu.get_item("mapper_blankrefreshtest").set_text("Refresh test (blank display)").set_callback_function(refreshtest_menu_callback).refresh_item(mainMenu); 09074 09075 bool MENU_get_swapstereo(void); 09076 mainMenu.get_item("mixer_swapstereo").check(MENU_get_swapstereo()).refresh_item(mainMenu); 09077 09078 bool MENU_get_mute(void); 09079 mainMenu.get_item("mixer_mute").check(MENU_get_mute()).refresh_item(mainMenu); 09080 09081 mainMenu.get_item("scaler_forced").check(render.scale.forced); 09082 09083 mainMenu.get_item("debug_logint21").check(log_int21); 09084 mainMenu.get_item("debug_logfileio").check(log_fileio); 09085 09086 mainMenu.get_item("vga_9widetext").enable(!IS_PC98_ARCH); 09087 mainMenu.get_item("doublescan").enable(!IS_PC98_ARCH); 09088 09089 mainMenu.get_item("pc98_5mhz_gdc").enable(IS_PC98_ARCH); 09090 mainMenu.get_item("pc98_allow_200scanline").enable(IS_PC98_ARCH); 09091 mainMenu.get_item("pc98_allow_4partitions").enable(IS_PC98_ARCH); 09092 mainMenu.get_item("pc98_enable_egc").enable(IS_PC98_ARCH); 09093 mainMenu.get_item("pc98_enable_grcg").enable(IS_PC98_ARCH); 09094 mainMenu.get_item("pc98_enable_analog").enable(IS_PC98_ARCH); 09095 mainMenu.get_item("pc98_enable_analog256").enable(IS_PC98_ARCH); 09096 mainMenu.get_item("pc98_enable_188user").enable(IS_PC98_ARCH); 09097 mainMenu.get_item("pc98_clear_text").enable(IS_PC98_ARCH); 09098 mainMenu.get_item("pc98_clear_graphics").enable(IS_PC98_ARCH); 09099 mainMenu.get_item("dos_pc98_pit_4mhz").enable(IS_PC98_ARCH); 09100 mainMenu.get_item("dos_pc98_pit_5mhz").enable(IS_PC98_ARCH); 09101 09102 extern bool Mouse_Vertical; 09103 extern bool Mouse_Drv; 09104 09105 mainMenu.get_item("dos_mouse_enable_int33").check(Mouse_Drv).refresh_item(mainMenu); 09106 mainMenu.get_item("dos_mouse_y_axis_reverse").check(Mouse_Vertical).refresh_item(mainMenu); 09107 09108 #if !defined(C_EMSCRIPTEN) 09109 mainMenu.get_item("show_console").check(showconsole_init).refresh_item(mainMenu); 09110 #endif 09111 09112 OutputSettingMenuUpdate(); 09113 update_pc98_clock_pit_menu(); 09114 #if !defined(C_EMSCRIPTEN) 09115 update_capture_fmt_menu(); 09116 #endif 09117 09118 /* The machine just "powered on", and then reset finished */ 09119 if (!VM_PowerOn()) E_Exit("VM failed to power on"); 09120 09121 /* go! */ 09122 sdl.init_ignore = false; 09123 UpdateWindowDimensions(); 09124 userResizeWindowWidth = 0; 09125 userResizeWindowHeight = 0; 09126 09127 UpdateOverscanMenu(); 09128 09129 void GUI_ResetResize(bool pressed); 09130 GUI_ResetResize(true); 09131 09132 void ConstructMenu(void); 09133 ConstructMenu(); 09134 09135 #if 0 09136 mainMenu.dump_log_debug(); /*DEBUG*/ 09137 #endif 09138 mainMenu.rebuild(); 09139 09140 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW 09141 mainMenu.screenWidth = (unsigned int)sdl.surface->w; 09142 mainMenu.screenHeight = (unsigned int)sdl.surface->h; 09143 mainMenu.updateRect(); 09144 #endif 09145 #if defined(WIN32) && !defined(HX_DOS) 09146 /* Windows 7 taskbar extension support */ 09147 { 09148 HRESULT hr; 09149 09150 hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_SERVER, IID_ITaskbarList3, (LPVOID*)(&winTaskbarList)); 09151 if (hr == S_OK) { 09152 LOG_MSG("Windows: IID_ITaskbarList3 is available"); 09153 09154 #if !defined(C_SDL2) 09155 THUMBBUTTON buttons[8]; 09156 int buttoni = 0; 09157 09158 { 09159 THUMBBUTTON &b = buttons[buttoni++]; 09160 memset(&b, 0, sizeof(b)); 09161 b.iId = ID_WIN_SYSMENU_MAPPER; 09162 b.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_MAPPER)); 09163 b.dwMask = THB_TOOLTIP | THB_FLAGS | THB_ICON; 09164 b.dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK; 09165 wcscpy(b.szTip, L"Mapper"); 09166 } 09167 09168 { 09169 THUMBBUTTON &b = buttons[buttoni++]; 09170 memset(&b, 0, sizeof(b)); 09171 b.iId = ID_WIN_SYSMENU_CFG_GUI; 09172 b.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_CFG_GUI)); 09173 b.dwMask = THB_TOOLTIP | THB_FLAGS | THB_ICON; 09174 b.dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK; 09175 wcscpy(b.szTip, L"Configuration GUI"); 09176 } 09177 09178 { 09179 THUMBBUTTON &b = buttons[buttoni++]; 09180 memset(&b, 0, sizeof(b)); 09181 b.iId = 1; 09182 b.dwMask = THB_FLAGS; 09183 b.dwFlags = THBF_DISABLED | THBF_NONINTERACTIVE | THBF_NOBACKGROUND; 09184 } 09185 09186 { 09187 THUMBBUTTON &b = buttons[buttoni++]; 09188 memset(&b, 0, sizeof(b)); 09189 b.iId = ID_WIN_SYSMENU_PAUSE; 09190 b.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_PAUSE)); 09191 b.dwMask = THB_TOOLTIP | THB_FLAGS | THB_ICON; 09192 b.dwFlags = THBF_ENABLED; 09193 wcscpy(b.szTip, L"Pause"); 09194 } 09195 09196 winTaskbarList->ThumbBarAddButtons(GetHWND(), buttoni, buttons); 09197 #endif 09198 } 09199 } 09200 #endif 09201 { 09202 Section_prop *section = static_cast<Section_prop *>(control->GetSection("SDL")); 09203 assert(section != NULL); 09204 09205 bool cfg_want_menu = section->Get_bool("showmenu"); 09206 09207 /* -- -- decide whether to set menu */ 09208 if (menu_gui && !control->opt_nomenu && cfg_want_menu) 09209 DOSBox_SetMenu(); 09210 else 09211 DOSBox_NoMenu(); 09212 } 09213 09214 #if DOSBOXMENU_TYPE == DOSBOXMENU_HMENU 09215 int Reflect_Menu(void); 09216 Reflect_Menu(); 09217 #endif 09218 09219 bool reboot_dos; 09220 bool run_machine; 09221 bool wait_debugger; 09222 bool reboot_machine; 09223 bool dos_kernel_shutdown; 09224 09225 fresh_boot: 09226 reboot_dos = false; 09227 run_machine = false; 09228 wait_debugger = false; 09229 reboot_machine = false; 09230 dos_kernel_shutdown = false; 09231 guest_msdos_mcb_chain = (Bit16u)(~0u); 09232 09233 /* NTS: CPU reset handler, and BIOS init, has the instruction pointer poised to run through BIOS initialization, 09234 * which will then "boot" into the DOSBox-X kernel, and then the shell, by calling VM_Boot_DOSBox_Kernel() */ 09235 /* FIXME: throwing int() is a stupid and nondescriptive way to signal shutdown/reset. */ 09236 try { 09237 #if C_DEBUG 09238 if (control->opt_break_start) DEBUG_EnableDebugger(); 09239 #endif 09240 DOSBOX_RunMachine(); 09241 } catch (int x) { 09242 if (x == 2) { /* booting a guest OS. "boot" has already done the work to load the image and setup CPU registers */ 09243 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to boot guest OS"); 09244 09245 run_machine = true; /* make note. don't run the whole shebang from an exception handler! */ 09246 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */ 09247 } 09248 else if (x == 3) { /* reboot the system */ 09249 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot the system"); 09250 09251 reboot_machine = true; 09252 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */ 09253 } 09254 else if (x == 5) { /* go to PC-98 mode */ 09255 E_Exit("Obsolete int signal"); 09256 } 09257 else if (x == 6) { /* reboot DOS kernel */ 09258 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot DOS kernel"); 09259 09260 reboot_dos = true; 09261 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */ 09262 } 09263 else if (x == 7) { /* DOS kernel corruption error (need to restart the DOS kernel) */ 09264 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to reboot DOS kernel"); 09265 09266 reboot_dos = true; 09267 wait_debugger = true; 09268 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */ 09269 } 09270 else if (x == 8) { /* Booting to a BIOS, shutting down DOSBox-X BIOS */ 09271 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw a signal to boot into BIOS image"); 09272 09273 reboot_machine = true; 09274 dos_kernel_shutdown = !dos_kernel_disabled; /* only if DOS kernel enabled */ 09275 } 09276 else { 09277 LOG(LOG_MISC,LOG_DEBUG)("Emulation threw DOSBox-X kill switch signal"); 09278 09279 // kill switch (see instances of throw(0) and throw(1) elsewhere in DOSBox) 09280 run_machine = false; 09281 dos_kernel_shutdown = false; 09282 } 09283 } 09284 catch (...) { 09285 throw; 09286 } 09287 09288 #if defined(WIN32) && !defined(C_SDL2) 09289 int Reflect_Menu(void); 09290 Reflect_Menu(); 09291 #endif 09292 09293 if (dos_kernel_shutdown) { 09294 /* NTS: we take different paths depending on whether we're just shutting down DOS 09295 * or doing a hard reboot. */ 09296 09297 if (wait_debugger) { 09298 #if C_DEBUG 09299 Bitu DEBUG_EnableDebugger(void); 09300 void DEBUG_WaitNoExecute(void); 09301 09302 LOG_MSG("Starting debugger."); 09303 DEBUG_EnableDebugger(); 09304 DEBUG_WaitNoExecute(); 09305 #endif 09306 } 09307 09308 /* new code: fire event */ 09309 if (reboot_machine) 09310 DispatchVMEvent(VM_EVENT_DOS_EXIT_REBOOT_BEGIN); 09311 else 09312 DispatchVMEvent(VM_EVENT_DOS_EXIT_BEGIN); 09313 09314 /* older shutdown code */ 09315 RemoveEMSPageFrame(); 09316 09317 /* remove UMB block */ 09318 if (!keep_umb_on_boot) RemoveUMBBlock(); 09319 09320 /* disable INT 33h mouse services. it can interfere with guest OS paging and control of the mouse */ 09321 DisableINT33(); 09322 09323 /* unmap the DOSBox-X kernel private segment. if the user told us not to, 09324 * but the segment exists below 640KB, then we must, because the guest OS 09325 * will trample it and assume control of that region of RAM. */ 09326 if (!keep_private_area_on_boot || reboot_machine) 09327 DOS_GetMemory_unmap(); 09328 else if (DOS_PRIVATE_SEGMENT < 0xA000) 09329 DOS_GetMemory_unmap(); 09330 09331 /* revector some dos-allocated interrupts */ 09332 if (!reboot_machine) { 09333 real_writed(0,0x01*4,(Bit32u)BIOS_DEFAULT_HANDLER_LOCATION); 09334 real_writed(0,0x03*4,(Bit32u)BIOS_DEFAULT_HANDLER_LOCATION); 09335 } 09336 09337 /* shutdown DOSBox-X's virtual drive Z */ 09338 VFILE_Shutdown(); 09339 09340 /* shutdown the programs */ 09341 PROGRAMS_Shutdown(); /* FIXME: Is this safe? Or will this cause use-after-free bug? */ 09342 09343 /* remove environment variables for some components */ 09344 DOS_UninstallMisc(); 09345 SBLASTER_DOS_Shutdown(); 09346 GUS_DOS_Shutdown(); 09347 /* disable Expanded Memory. EMM is a DOS API, not a BIOS API */ 09348 EMS_DoShutDown(); 09349 /* and XMS, also a DOS API */ 09350 XMS_DoShutDown(); 09351 /* and the DOS API in general */ 09352 DOS_DoShutDown(); 09353 09354 /* mem handles too */ 09355 ShutDownMemHandles(NULL); 09356 09357 /* set the "disable DOS kernel" flag so other parts of this program 09358 * do not attempt to manipulate now-defunct parts of the kernel 09359 * such as the environment block */ 09360 dos_kernel_disabled = true; 09361 09362 /* new code: fire event */ 09363 if (reboot_machine) 09364 DispatchVMEvent(VM_EVENT_DOS_EXIT_REBOOT_KERNEL); 09365 else 09366 DispatchVMEvent(VM_EVENT_DOS_EXIT_KERNEL); 09367 09368 #if defined(WIN32) && !defined(C_SDL2) 09369 int Reflect_Menu(void); 09370 Reflect_Menu(); 09371 #endif 09372 } 09373 09374 #if defined(WIN32) && !defined(C_SDL2) 09375 int Reflect_Menu(void); 09376 Reflect_Menu(); 09377 #endif 09378 09379 if (run_machine) { 09380 bool disable_a20 = static_cast<Section_prop *>(control->GetSection("dosbox"))->Get_bool("turn off a20 gate on boot"); 09381 09382 /* if instructed, turn off A20 at boot */ 09383 if (disable_a20) MEM_A20_Enable(false); 09384 09385 /* PC-98: hide the cursor */ 09386 if (IS_PC98_ARCH) { 09387 void PC98_show_cursor(bool show); 09388 PC98_show_cursor(false); 09389 } 09390 09391 /* new code: fire event */ 09392 DispatchVMEvent(VM_EVENT_GUEST_OS_BOOT); 09393 09394 LOG_MSG("Alright: DOS kernel shutdown, booting a guest OS\n"); 09395 LOG_MSG(" CS:IP=%04x:%04x SS:SP=%04x:%04x AX=%04x BX=%04x CX=%04x DX=%04x\n", 09396 SegValue(cs),reg_ip, 09397 SegValue(ss),reg_sp, 09398 reg_ax,reg_bx,reg_cx,reg_dx); 09399 09400 #if C_DEBUG 09401 if (boot_debug_break) { 09402 boot_debug_break = false; 09403 09404 Bitu DEBUG_EnableDebugger(void); 09405 DEBUG_EnableDebugger(); 09406 } 09407 #endif 09408 09409 /* run again */ 09410 goto fresh_boot; 09411 } 09412 09413 #if defined(WIN32) && !defined(C_SDL2) 09414 int Reflect_Menu(void); 09415 Reflect_Menu(); 09416 #endif 09417 09418 if (reboot_machine) { 09419 LOG_MSG("Rebooting the system\n"); 09420 09421 boothax = BOOTHAX_NONE; 09422 guest_msdos_LoL = 0; 09423 guest_msdos_mcb_chain = 0; 09424 09425 void CPU_Snap_Back_Forget(); 09426 /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */ 09427 CPU_Snap_Back_To_Real_Mode(); 09428 CPU_Snap_Back_Forget(); 09429 09430 /* new code: fire event */ 09431 DispatchVMEvent(VM_EVENT_RESET); 09432 09433 /* force the mapper to let go of all keys so that the host key is not stuck (Issue #1320) */ 09434 void MAPPER_ReleaseAllKeys(void); 09435 MAPPER_ReleaseAllKeys(); 09436 void MAPPER_LosingFocus(void); 09437 MAPPER_LosingFocus(); 09438 09439 if (custom_bios) { 09440 /* need to relocate BIOS allocations */ 09441 void ROMBIOS_InitForCustomBIOS(void); 09442 ROMBIOS_InitForCustomBIOS(); 09443 09444 void CALLBACK_Init(); 09445 CALLBACK_Init(); 09446 09447 #if C_DEBUG 09448 void DEBUG_ReinitCallback(void); 09449 DEBUG_ReinitCallback(); 09450 #endif 09451 } 09452 09453 DispatchVMEvent(VM_EVENT_RESET_END); 09454 09455 /* HACK: EGA/VGA modes will need VGA BIOS mapped in, ready to go */ 09456 if (IS_EGAVGA_ARCH) { 09457 void INT10_Startup(Section *sec); 09458 INT10_Startup(NULL); 09459 } 09460 09461 #if C_DEBUG 09462 if (boot_debug_break) { 09463 boot_debug_break = false; 09464 09465 Bitu DEBUG_EnableDebugger(void); 09466 DEBUG_EnableDebugger(); 09467 } 09468 #endif 09469 09470 /* run again */ 09471 goto fresh_boot; 09472 } 09473 else if (reboot_dos) { /* typically (at this time) to enter/exit PC-98 mode */ 09474 LOG_MSG("Rebooting DOS\n"); 09475 09476 void CPU_Snap_Back_Forget(); 09477 /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */ 09478 CPU_Snap_Back_To_Real_Mode(); 09479 CPU_Snap_Back_Forget(); 09480 09481 /* all hardware devices need to know to reregister themselves PC-98 style */ 09482 09483 /* begin booting DOS again. */ 09484 void BIOS_Enter_Boot_Phase(void); 09485 BIOS_Enter_Boot_Phase(); 09486 09487 /* run again */ 09488 goto fresh_boot; 09489 } 09490 09491 #if defined(WIN32) && !defined(C_SDL2) 09492 int Reflect_Menu(void); 09493 Reflect_Menu(); 09494 #endif 09495 09496 /* and then shutdown */ 09497 GFX_ShutDown(); 09498 09499 void CPU_Snap_Back_Forget(); 09500 /* Shutdown everything. For shutdown to work properly we must force CPU to real mode */ 09501 CPU_Snap_Back_To_Real_Mode(); 09502 CPU_Snap_Back_Forget(); 09503 09504 /* NTS: The "control" object destructor is called here because the "myconf" object leaves scope. 09505 * The destructor calls all section destroy functions here. After this point, all sections have 09506 * freed resources. */ 09507 } 09508 09509 void CALLBACK_Dump(void); 09510 CALLBACK_Dump(); 09511 09512 /* GUI font registry shutdown */ 09513 #if !defined(C_SDL2) 09514 GUI::Font::registry_freeall(); 09515 #endif 09516 DOS_ShutdownDrives(); 09517 DOS_ShutdownFiles(); 09518 DOS_ShutdownDevices(); 09519 CALLBACK_Shutdown(); 09520 #if C_DYNAMIC_X86 09521 CPU_Core_Dyn_X86_Shutdown(); 09522 #endif 09523 FreeBIOSDiskList(); 09524 MAPPER_Shutdown(); 09525 VFILE_Shutdown(); 09526 PROGRAMS_Shutdown(); 09527 TIMER_ShutdownTickHandlers(); 09528 #if C_DEBUG 09529 DEBUG_ShutDown(NULL); 09530 #endif 09531 09532 sticky_keys(true); //Might not be needed if the shutdown function switches to windowed mode, but it doesn't hurt 09533 09534 //Force visible mouse to end user. Somehow this sometimes doesn't happen 09535 #if defined(C_SDL2) 09536 SDL_SetRelativeMouseMode(SDL_FALSE); 09537 #else 09538 SDL_WM_GrabInput(SDL_GRAB_OFF); 09539 #endif 09540 SDL_ShowCursor(SDL_ENABLE); 09541 09542 /* Exit functions */ 09543 while (!exitfunctions.empty()) { 09544 Function_wrapper &ent = exitfunctions.front(); 09545 09546 LOG(LOG_MISC,LOG_DEBUG)("Calling exit function (%p) '%s'",(void*)((uintptr_t)ent.function),ent.name.c_str()); 09547 ent.function(NULL); 09548 exitfunctions.pop_front(); 09549 } 09550 09551 LOG::Exit(); 09552 09553 #if defined(WIN32) && !defined(C_SDL2) 09554 # if !defined(HX_DOS) 09555 ShowWindow(GetHWND(), SW_HIDE); 09556 SDL1_hax_SetMenu(NULL);/* detach menu from window, or else Windows will destroy the menu out from under the C++ class */ 09557 # endif 09558 #endif 09559 #if DOSBOXMENU_TYPE == DOSBOXMENU_NSMENU 09560 void sdl_hax_macosx_setmenu(void *nsMenu); 09561 sdl_hax_macosx_setmenu(NULL); 09562 #endif 09563 09564 SDL_Quit();//Let's hope sdl will quit as well when it catches an exception 09565 09566 #if defined(WIN32) && !defined(HX_DOS) 09567 if (winTaskbarList != NULL) { 09568 winTaskbarList->Release(); 09569 winTaskbarList = NULL; 09570 } 09571 #endif 09572 09573 mainMenu.unbuild(); 09574 mainMenu.clear_all_menu_items(); 09575 09576 #if defined(LINUX) && defined(HAVE_ALSA) 09577 // force ALSA to release global cache, so that it's one less leak reported by Valgrind 09578 snd_config_update_free_global(); 09579 #endif 09580 09581 return 0; 09582 } 09583 09584 void GFX_GetSizeAndPos(int &x,int &y,int &width, int &height, bool &fullscreen) { 09585 x = sdl.clip.x; 09586 y = sdl.clip.y; 09587 width = sdl.clip.w; // draw.width 09588 height = sdl.clip.h; // draw.height 09589 fullscreen = sdl.desktop.fullscreen; 09590 } 09591 09592 void GFX_GetSize(int &width, int &height, bool &fullscreen) { 09593 width = sdl.clip.w; // draw.width 09594 height = sdl.clip.h; // draw.height 09595 fullscreen = sdl.desktop.fullscreen; 09596 } 09597 09598 void GFX_ShutDown(void) { 09599 LOG(LOG_MISC,LOG_DEBUG)("Shutting down GFX renderer"); 09600 GFX_Stop(); 09601 if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop ); 09602 if (sdl.mouse.locked) GFX_CaptureMouse(); 09603 if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); 09604 } 09605 09606 bool OpenGL_using(void) { 09607 #if C_OPENGL 09608 return (sdl.desktop.want_type==SCREEN_OPENGL?true:false); 09609 #else 09610 return false; 09611 #endif 09612 } 09613 09614 bool Get_Custom_SaveDir(std::string& savedir) { 09615 (void)savedir;//UNUSED 09616 if (custom_savedir.length() != 0) 09617 return true; 09618 09619 return false; 09620 } 09621 09622 void GUI_ResetResize(bool pressed) { 09623 void RENDER_CallBack( GFX_CallBackFunctions_t function ); 09624 09625 if (!pressed) return; 09626 userResizeWindowWidth = 0; 09627 userResizeWindowHeight = 0; 09628 09629 if (GFX_GetPreventFullscreen()) 09630 return; 09631 09632 if (sdl.updating && !GFX_MustActOnResize()) { 09633 /* act on resize when updating is complete */ 09634 sdl.deferred_resize = true; 09635 } 09636 else { 09637 sdl.deferred_resize = false; 09638 RENDER_CallBack(GFX_CallBackReset); 09639 } 09640 } 09641 09642 bool MOUSE_IsLocked() 09643 { 09644 return sdl.mouse.locked; 09645 } 09646 09647 #if defined(C_SDL2) && defined(C_OPENGL)/*HACK*/ 09648 void SDL_GL_SwapBuffers(void) { 09649 SDL_GL_SwapWindow(sdl.window); 09650 } 09651 #endif 09652 09653 // save state support 09654 void POD_Save_Sdlmain( std::ostream& stream ) 09655 { 09656 // - pure data 09657 WRITE_POD( &sdl.mouse.autolock, sdl.mouse.autolock ); 09658 WRITE_POD( &sdl.mouse.requestlock, sdl.mouse.requestlock ); 09659 } 09660 09661 void POD_Load_Sdlmain( std::istream& stream ) 09662 { 09663 // - pure data 09664 READ_POD( &sdl.mouse.autolock, sdl.mouse.autolock ); 09665 READ_POD( &sdl.mouse.requestlock, sdl.mouse.requestlock ); 09666 }