/* Copyright holders: Sarah Walker, Tenshi see COPYING for more details */ #define UNICODE #define _WIN32_WINNT 0x0501 #define BITMAP WINDOWS_BITMAP #include #include #undef BITMAP #include #include #include #include #include #include #include #include #include "../86box.h" #include "../device.h" #include "../disc.h" #include "../fdd.h" #include "../hdd.h" #include "../ibm.h" #include "../cpu/cpu.h" #include "../mem.h" #include "../rom.h" #include "../nvr.h" #include "../thread.h" #include "../config.h" #include "../model.h" #include "../ide.h" #include "../cdrom.h" #include "../cdrom_null.h" #include "../cdrom_ioctl.h" #include "../cdrom_image.h" #include "../video/video.h" #include "../video/vid_ega.h" #include "../mouse.h" #include "../sound/sound.h" #include "../sound/snd_dbopl.h" #include "plat_keyboard.h" #include "plat_mouse.h" #include "plat_midi.h" #include "win.h" #include "win_ddraw.h" #include "win_ddraw-fs.h" #include "win_d3d.h" #include "win_d3d-fs.h" #include "win_language.h" #include "resource.h" #ifndef MAPVK_VK_TO_VSC #define MAPVK_VK_TO_VSC 0 #endif static int save_window_pos = 0; uint64_t timer_freq; int rawinputkey[272]; static RAWINPUTDEVICE device; static uint16_t scancode_map[65536]; static struct { int (*init)(HWND h); void (*close)(); void (*resize)(int x, int y); } vid_apis[2][2] = { { ddraw_init, ddraw_close, NULL, d3d_init, d3d_close, d3d_resize }, { ddraw_fs_init, ddraw_fs_close, NULL, d3d_fs_init, d3d_fs_close, NULL }, }; #define TIMER_1SEC 1 int winsizex=640,winsizey=480; int efwinsizey=480; int gfx_present[GFX_MAX]; HANDLE ghMutex; HANDLE mainthreadh; int infocus=1; int drawits=0; int romspresent[ROM_MAX]; int quited=0; RECT oldclip; int mousecapture=0; /* Declare Windows procedure */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LONG_PTR OriginalStatusBarProcedure; HWND ghwnd; HINSTANCE hinstance; HMENU menu; extern int updatestatus; int pause=0; static int win_doresize = 0; static int leave_fullscreen_flag = 0; static int unscaled_size_x = 0; static int unscaled_size_y = 0; int scale = 0; HWND hwndRender, hwndStatus; void updatewindowsize(int x, int y) { int owsx = winsizex; int owsy = winsizey; int temp_overscan_x = overscan_x; int temp_overscan_y = overscan_y; if (vid_resize) return; if (x < 160) x = 160; if (y < 100) y = 100; if (x > 2048) x = 2048; if (y > 2048) y = 2048; if (suppress_overscan) { temp_overscan_x = temp_overscan_y = 0; } unscaled_size_x=x; efwinsizey=y; if (force_43) { /* Account for possible overscan. */ if (temp_overscan_y == 16) { /* CGA */ unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; } else if (temp_overscan_y < 16) { /* MDA/Hercules */ unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); } else { if (enable_overscan) { /* EGA/(S)VGA with overscan */ unscaled_size_y = ((int) (((double) (x - temp_overscan_x) / 4.0) * 3.0)) + temp_overscan_y; } else { /* EGA/(S)VGA without overscan */ unscaled_size_y = ((int) (((double) (x) / 4.0) * 3.0)); } } } else { unscaled_size_y = efwinsizey; } switch(scale) { case 0: winsizex = unscaled_size_x >> 1; winsizey = unscaled_size_y >> 1; break; case 1: winsizex = unscaled_size_x; winsizey = unscaled_size_y; break; case 2: winsizex = (unscaled_size_x * 3) >> 1; winsizey = (unscaled_size_y * 3) >> 1; break; case 3: winsizex = unscaled_size_x << 1; winsizey = unscaled_size_y << 1; break; } if ((owsx != winsizex) || (owsy != winsizey)) { win_doresize = 1; } else { win_doresize = 0; } } void uws_natural() { updatewindowsize(unscaled_size_x, efwinsizey); } void releasemouse() { if (mousecapture) { ClipCursor(&oldclip); ShowCursor(TRUE); mousecapture = 0; } } void startblit() { WaitForSingleObject(ghMutex, INFINITE); } void endblit() { ReleaseMutex(ghMutex); } void leave_fullscreen() { leave_fullscreen_flag = 1; } uint64_t main_time; uint64_t start_time; uint64_t end_time; void mainthread(LPVOID param) { int frames = 0; DWORD old_time, new_time; RECT r; int sb_borders[3]; drawits=0; old_time = GetTickCount(); while (!quited) { if (updatestatus) { updatestatus = 0; if (status_is_open) SendMessage(status_hwnd, WM_USER, 0, 0); } new_time = GetTickCount(); drawits += new_time - old_time; old_time = new_time; if (drawits > 0 && !pause) { start_time = timer_read(); drawits-=10; if (drawits>50) drawits=0; runpc(); frames++; if (frames >= 200 && nvr_dosave) { frames = 0; nvr_dosave = 0; savenvr(); } end_time = timer_read(); main_time += end_time - start_time; } else Sleep(1); if (!video_fullscreen && win_doresize && (winsizex > 0) && (winsizey > 0)) { video_wait_for_blit(); SendMessage(hwndStatus, SB_GETBORDERS, 0, (LPARAM) sb_borders); GetWindowRect(ghwnd, &r); MoveWindow(hwndRender, 0, 0, winsizex, winsizey, TRUE); GetWindowRect(hwndRender, &r); MoveWindow(hwndStatus, 0, r.bottom + GetSystemMetrics(SM_CYEDGE), winsizex, 17, TRUE); GetWindowRect(ghwnd, &r); MoveWindow(ghwnd, r.left, r.top, winsizex + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), winsizey + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, TRUE); win_doresize = 0; } if (leave_fullscreen_flag) { leave_fullscreen_flag = 0; SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); } if (video_fullscreen && infocus) { SetCursorPos(9999, 9999); } } } void *thread_create(void (*thread_rout)(void *param), void *param) { return (void *)_beginthread(thread_rout, 0, param); } void thread_kill(void *handle) { TerminateThread(handle, 0); } void thread_sleep(int t) { Sleep(t); } typedef struct win_event_t { HANDLE handle; } win_event_t; event_t *thread_create_event() { win_event_t *event = malloc(sizeof(win_event_t)); event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); return (event_t *)event; } void thread_set_event(event_t *_event) { win_event_t *event = (win_event_t *)_event; SetEvent(event->handle); } void thread_reset_event(event_t *_event) { win_event_t *event = (win_event_t *)_event; ResetEvent(event->handle); } int thread_wait_event(event_t *_event, int timeout) { win_event_t *event = (win_event_t *)_event; if (timeout == -1) timeout = INFINITE; if (WaitForSingleObject(event->handle, timeout)) return 1; return 0; } void thread_destroy_event(event_t *_event) { win_event_t *event = (win_event_t *)_event; CloseHandle(event->handle); free(event); } HMENU smenu; static void initmenu(void) { int i, c; HMENU m; WCHAR s[64]; for (i = 0; i < CDROM_NUM; i++) { m=GetSubMenu(smenu, i + 4); /*CD-ROM*/ /* Loop through each Windows drive letter and test to see if it's a CDROM */ for (c='A';c<='Z';c++) { _swprintf(s,L"%c:\\",c); if (GetDriveType(s)==DRIVE_CDROM) { _swprintf(s, win_language_get_string_from_id(2076), c); AppendMenu(m,MF_STRING,IDM_CDROM_1_REAL+(c << 2)+i,s); } } } } void get_executable_name(WCHAR *s, int size) { GetModuleFileName(hinstance, s, size); } void set_window_title(WCHAR *s) { if (video_fullscreen) return; SetWindowText(ghwnd, s); } uint64_t timer_read() { LARGE_INTEGER qpc_time; QueryPerformanceCounter(&qpc_time); return qpc_time.QuadPart; } /* This is so we can disambiguate scan codes that would otherwise conflict and get passed on incorrectly. */ UINT16 convert_scan_code(UINT16 scan_code) { switch (scan_code) { case 0xE001: return 0xF001; case 0xE002: return 0xF002; case 0xE0AA: return 0xF003; case 0xE005: return 0xF005; case 0xE006: return 0xF006; case 0xE007: return 0xF007; case 0xE071: return 0xF008; case 0xE072: return 0xF009; case 0xE07F: return 0xF00A; case 0xE0E1: return 0xF00B; case 0xE0EE: return 0xF00C; case 0xE0F1: return 0xF00D; case 0xE0FE: return 0xF00E; case 0xE0EF: return 0xF00F; default: return scan_code; } } void get_registry_key_map() { WCHAR *keyName = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; WCHAR *valueName = L"Scancode Map"; unsigned char buf[32768]; DWORD bufSize; HKEY hKey; int j; /* First, prepare the default scan code map list which is 1:1. Remappings will be inserted directly into it. 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, since each array element is a scan code and provides for E0, etc. ones too. */ for (j = 0; j < 65536; j++) scancode_map[j] = convert_scan_code(j); bufSize = 32768; /* Get the scan code remappings from: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) { if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) { UINT32 *bufEx2 = (UINT32 *) buf; int scMapCount = bufEx2[2]; if ((bufSize != 0) && (scMapCount != 0)) { UINT16 *bufEx = (UINT16 *) (buf + 12); for (j = 0; j < scMapCount*2; j += 2) { /* Each scan code is 32-bit: 16 bits of remapped scan code, and 16 bits of original scan code. */ int scancode_unmapped = bufEx[j + 1]; int scancode_mapped = bufEx[j]; scancode_mapped = convert_scan_code(scancode_mapped); /* Fixes scan code map logging. */ scancode_map[scancode_unmapped] = scancode_mapped; } } } RegCloseKey(hKey); } } static wchar_t **argv; static int argc; static wchar_t *argbuf; static void process_command_line() { WCHAR *cmdline; int argc_max; int i, q; cmdline = GetCommandLine(); i = wcslen(cmdline) + 1; argbuf = malloc(i * 2); memcpy(argbuf, cmdline, i * 2); argc = 0; argc_max = 64; argv = malloc(sizeof(wchar_t *) * argc_max); if (!argv) { free(argbuf); return; } i = 0; /* parse commandline into argc/argv format */ while (argbuf[i]) { while (argbuf[i] == L' ') i++; if (argbuf[i]) { if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) { q = argbuf[i++]; if (!argbuf[i]) break; } else q = 0; argv[argc++] = &argbuf[i]; if (argc >= argc_max) { argc_max += 64; argv = realloc(argv, sizeof(wchar_t *) * argc_max); if (!argv) { free(argbuf); return; } } while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != L' '))) i++; if (argbuf[i]) { argbuf[i] = 0; i++; } } } argv[argc] = NULL; } int valid_models[2] = { 0, 1 }; int valid_bases[6] = { 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 }; int valid_irqs[6] = { 9, 10, 11, 12, 14, 15 }; int valid_dma_channels[3] = { 5, 6, 7 }; int valid_ide_channels[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; int valid_scsi_ids[15] = { 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15 }; int valid_scsi_luns[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; int find_in_array(int *array, int val, int len, int menu_base) { int i = 0; int temp = 0; for (i = 0; i < len; i++) { CheckMenuItem(menu, menu_base + array[i], MF_UNCHECKED); if (array[i] == val) { temp = 1; } } return temp; } HANDLE hinstAcc; HICON LoadIconEx(PCTSTR pszIconName) { return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 16, 16, LR_SHARED); } HICON LoadIconBig(PCTSTR pszIconName) { return (HICON) LoadImage(hinstance, pszIconName, IMAGE_ICON, 64, 64, 0); } int fdd_type_to_icon(int type) { switch(type) { default: case 0: return 512; case 1: return 128; case 2: return 130; case 3: return 132; case 4: case 5: case 6: return 134; case 7: return 144; case 8: return 146; case 9: case 10: case 11: case 12: return 150; case 13: return 152; } } int sb_parts = 10; int sb_part_meanings[12]; int sb_part_icons[12]; int sb_icon_width = 24; int count_hard_disks(int bus) { int i = 0; int c = 0; for (i = 0; i < HDC_NUM; i++) { if (hdc[i].bus == bus) { c++; } } return c; } HICON hIcon[512]; int iStatusWidths[] = { 18, 36, 54, 72, 90, 108, 126, 144, 168, 192, 210, -1 }; #define SBI_FLAG_ACTIVE 1 #define SBI_FLAG_EMPTY 256 int sb_icon_flags[512]; /* This is for the disk activity indicator. */ void update_status_bar_icon(int tag, int active) { int i = 0; int found = -1; int temp_flags = 0; if ((tag & 0xf0) >= 0x40) { return; } temp_flags |= active; for (i = 0; i < 12; i++) { if (sb_part_meanings[i] == tag) { found = i; break; } } if (found != -1) { if (temp_flags != (sb_icon_flags[found] & 1)) { sb_icon_flags[found] &= ~1; sb_icon_flags[found] |= active; sb_part_icons[found] &= ~257; sb_part_icons[found] |= sb_icon_flags[found]; SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); } } } /* This is for the drive state indicator. */ void update_status_bar_icon_state(int tag, int state) { int i = 0; int found = -1; if ((tag & 0xf0) >= 0x20) { return; } for (i = 0; i < 12; i++) { if (sb_part_meanings[i] == tag) { found = i; break; } } if (found != -1) { sb_icon_flags[found] &= ~256; sb_icon_flags[found] |= state ? 256 : 0; sb_part_icons[found] &= ~257; sb_part_icons[found] |= sb_icon_flags[found]; SendMessage(hwndStatus, SB_SETICON, found, (LPARAM) hIcon[sb_part_icons[found]]); } } WCHAR sbTips[24][512]; void create_floppy_tip(int part) { WCHAR *szText; WCHAR wtext[512]; int drive = sb_part_meanings[part] & 0xf; mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), strlen(fdd_getname(fdd_get_type(drive))) + 1); if (wcslen(discfns[drive]) == 0) { _swprintf(sbTips[part], win_language_get_string_from_id(2179), drive + 1, wtext, win_language_get_string_from_id(2185)); } else { _swprintf(sbTips[part], win_language_get_string_from_id(2179), drive + 1, wtext, discfns[drive]); } } void create_cdrom_tip(int part) { WCHAR *szText; char ansi_text[3][512]; WCHAR wtext[512]; int drive = sb_part_meanings[part] & 0xf; if (cdrom_drives[drive].host_drive == 200) { if (wcslen(cdrom_image[drive].image_path) == 0) { _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); } else { _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, cdrom_image[drive].image_path); } } else if (cdrom_drives[drive].host_drive < 0x41) { _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, win_language_get_string_from_id(2185)); } else { _swprintf(wtext, win_language_get_string_from_id(2186), cdrom_drives[drive].host_drive & ~0x20); _swprintf(sbTips[part], win_language_get_string_from_id(2180), drive + 1, wtext); } } void create_removable_hd_tip(int part) { WCHAR *szText; WCHAR wtext[512]; int drive = sb_part_meanings[part] & 0xf; if (wcslen(hdd_fn[drive]) == 0) { _swprintf(sbTips[part], win_language_get_string_from_id(2201), win_language_get_string_from_id(2185)); } else { _swprintf(sbTips[part], win_language_get_string_from_id(2179), hdd_fn[drive]); } } void create_hd_tip(int part) { WCHAR *szText; int bus = sb_part_meanings[part] & 0xf; szText = (WCHAR *) win_language_get_string_from_id(2181 + bus); memcpy(sbTips[part], szText, (wcslen(szText) << 1) + 2); } void update_tip(int meaning) { int i = 0; int part = -1; for (i = 0; i < sb_parts; i++) { if (sb_part_meanings[i] == meaning) { part = i; } } if (part != -1) { switch(meaning & 0xf0) { case 0x00: create_floppy_tip(part); break; case 0x10: create_cdrom_tip(part); break; case 0x20: create_removable_hd_tip(part); break; case 0x30: create_hd_tip(part); break; default: break; } SendMessage(hwndStatus, SB_SETTIPTEXT, part, (LPARAM) sbTips[part]); } } static int get_floppy_state(int id) { return (wcslen(discfns[id]) == 0) ? 1 : 0; } static int get_cd_state(int id) { if (cdrom_drives[id].host_drive < 0x41) { return 1; } else { if (cdrom_drives[id].host_drive == 0x200) { return (wcslen(cdrom_image[id].image_path) == 0) ? 1 : 0; } else { return 0; } } } void status_settextw(wchar_t *wstr) { int i = 0; int part = -1; for (i = 0; i < sb_parts; i++) { if (sb_part_meanings[i] == 0x40) { part = i; } } if (part != -1) { SendMessage(hwndStatus, SB_SETTEXT, part | SBT_NOBORDERS, (LPARAM) wstr); } } static wchar_t cwstr[512]; void status_settext(char *str) { memset(cwstr, 0, 1024); mbstowcs(cwstr, str, strlen(str) + 1); status_settextw(cwstr); } void update_status_bar_panes(HWND hwnds) { int i, j, id; int edge = 0; int c_rll = 0; int c_mfm = 0; int c_ide_pio = 0; int c_ide_dma = 0; int c_scsi = 0; c_mfm = count_hard_disks(1); c_ide_pio = count_hard_disks(2); c_ide_dma = count_hard_disks(3); c_scsi = count_hard_disks(4); for (i = 0; i < sb_parts; i++) { SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); } sb_parts = 0; memset(iStatusWidths, 0, 48); memset(sb_part_meanings, 0, 48); for (i = 0; i < 4; i++) { if (fdd_get_type(i) != 0) { /* pclog("update_status_bar_panes(): Found floppy drive %c:, type %i\n", 65 + i, fdd_get_type(i)); */ edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x00 | i; sb_parts++; } } for (i = 0; i < 4; i++) { if (cdrom_drives[i].bus_type != 0) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x10 | i; sb_parts++; } } for (i = 0; i < 16; i++) { if (hdc[i].bus == 5) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x20 | i; sb_parts++; } } if (c_mfm && !(models[model].flags & MODEL_HAS_IDE) && !!memcmp(hdd_controller_name, "none", 4) && !!memcmp(hdd_controller_name, "xtide", 5)) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x30; sb_parts++; } if (c_ide_pio && ((models[model].flags & MODEL_HAS_IDE) || !memcmp(hdd_controller_name, "xtide", 5))) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x31; sb_parts++; } if (c_ide_dma && ((models[model].flags & MODEL_HAS_IDE) || !memcmp(hdd_controller_name, "xtide", 5))) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x32; sb_parts++; } if (c_scsi) { edge += sb_icon_width; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = 0x33; sb_parts++; } if (sb_parts) { iStatusWidths[sb_parts - 1] += (24 - sb_icon_width); } iStatusWidths[sb_parts] = -1; sb_part_meanings[sb_parts] = 0x40; sb_parts++; SendMessage(hwnds, SB_SETPARTS, (WPARAM) sb_parts, (LPARAM) iStatusWidths); for (i = 0; i < sb_parts; i++) { switch (sb_part_meanings[i] & 0xf0) { case 0x00: /* Floppy */ sb_icon_flags[i] = (wcslen(discfns[sb_part_meanings[i] & 0xf]) == 0) ? 256 : 0; sb_part_icons[i] = fdd_type_to_icon(fdd_get_type(sb_part_meanings[i] & 0xf)) | sb_icon_flags[i]; create_floppy_tip(i); break; case 0x10: /* CD-ROM */ id = sb_part_meanings[i] & 0xf; if (cdrom_drives[id].host_drive < 0x41) { sb_icon_flags[i] = 256; } else { if (cdrom_drives[id].host_drive == 0x200) { sb_icon_flags[i] = (wcslen(cdrom_image[id].image_path) == 0) ? 256 : 0; } else { sb_icon_flags[i] = 0; } } if (cdrom_drives[id].bus_type == 4) { j = 164; } else if (cdrom_drives[id].bus_type == 3) { j = 162; } else { j = 160; } sb_part_icons[i] = j | sb_icon_flags[i]; create_cdrom_tip(i); break; case 0x20: /* Removable hard disk */ sb_icon_flags[i] = (wcslen(discfns[sb_part_meanings[i] & 0xf]) == 0) ? 256 : 0; sb_part_icons[i] = 176 + sb_icon_flags[i]; create_removable_hd_tip(i); break; case 0x30: /* Hard disk */ sb_part_icons[i] = 192 + ((sb_part_meanings[i] & 0xf) << 1); create_hd_tip(i); break; case 0x40: /* Status text */ SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) L"Welcome to Unicode 86Box! :p"); sb_part_icons[i] = -1; break; } if (sb_part_icons[i] != -1) { SendMessage(hwnds, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM) ""); SendMessage(hwnds, SB_SETICON, i, (LPARAM) hIcon[sb_part_icons[i]]); SendMessage(hwnds, SB_SETTIPTEXT, i, (LPARAM) sbTips[i]); /* pclog("Status bar part found: %02X (%i)\n", sb_part_meanings[i], sb_part_icons[i]); */ } else { SendMessage(hwnds, SB_SETICON, i, (LPARAM) NULL); } } } HWND EmulatorStatusBar(HWND hwndParent, int idStatus, HINSTANCE hinst) { HWND hwndStatus; int i; RECT rectDialog; int dw, dh; for (i = 128; i < 136; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 144; i < 148; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 150; i < 154; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 160; i < 166; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 176; i < 178; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 192; i < 200; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 384; i < 392; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 400; i < 404; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 406; i < 410; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 416; i < 422; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } for (i = 432; i < 434; i++) { hIcon[i] = LoadIconEx((PCTSTR) i); } GetWindowRect(hwndParent, &rectDialog); dw = rectDialog.right - rectDialog.left; dh = rectDialog.bottom - rectDialog.top; InitCommonControls(); hwndStatus = CreateWindowEx( 0, STATUSCLASSNAME, (PCTSTR) NULL, SBARS_SIZEGRIP | WS_CHILD | WS_VISIBLE | SBT_TOOLTIPS, 0, dh - 17, dw, 17, hwndParent, (HMENU) idStatus, hinst, NULL); GetWindowRect(hwndStatus, &rectDialog); SetWindowPos( hwndStatus, HWND_TOPMOST, rectDialog.left, rectDialog.top, rectDialog.right - rectDialog.left, rectDialog.bottom - rectDialog.top, SWP_SHOWWINDOW); SendMessage(hwndStatus, SB_SETMINHEIGHT, (WPARAM) 17, (LPARAM) 0); update_status_bar_panes(hwndStatus); return hwndStatus; } void win_menu_update() { #if 0 menu = LoadMenu(hThisInstance, TEXT("MainMenu")); smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); initmenu(); SetMenu(ghwnd, menu); win_title_update = 1; #endif } int recv_key[272]; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; /* This is the handle for our window */ MSG messages; /* Here messages to the application are saved */ WNDCLASSEX wincl; /* Data structure for the windowclass */ int c, d, e, bRet; WCHAR emulator_title[200]; LARGE_INTEGER qpc_freq; HACCEL haccel; /* Handle to accelerator table */ memset(recv_key, 0, sizeof(recv_key)); process_command_line(); win_language_load_common_strings(); hinstance=hThisInstance; /* The Window structure */ wincl.hInstance = hThisInstance; wincl.lpszClassName = szClassName; wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ wincl.style = CS_DBLCLKS; /* Catch double-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Use default icon and mouse-pointer */ wincl.hIcon = LoadIcon(hinstance, (LPCTSTR) 100); wincl.hIconSm = LoadIcon(hinstance, (LPCTSTR) 100); wincl.hCursor = NULL; wincl.lpszMenuName = NULL; /* No menu */ wincl.cbClsExtra = 0; /* No extra bytes after the window class */ wincl.cbWndExtra = 0; /* structure or the window instance */ /* Use Windows's default color as the background of the window */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Register the window class, and if it fails quit the program */ if (!RegisterClassEx(&wincl)) return 0; wincl.lpszClassName = szSubClassName; wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ if (!RegisterClassEx(&wincl)) return 0; menu = LoadMenu(hThisInstance, TEXT("MainMenu")); _swprintf(emulator_title, L"86Box v%s", emulator_version_w); /* The class is registered, let's create the program*/ hwnd = CreateWindowEx ( 0, /* Extended possibilites for variation */ szClassName, /* Classname */ emulator_title, /* Title Text */ (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX)/* | DS_3DLOOK*/, /* default window */ CW_USEDEFAULT, /* Windows decides the position */ CW_USEDEFAULT, /* where the window ends up on the screen */ 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ HWND_DESKTOP, /* The window is a child-window to desktop */ menu, /* Menu */ hThisInstance, /* Program Instance handler */ NULL /* No Window Creation data */ ); /* Make the window visible on the screen */ ShowWindow (hwnd, nFunsterStil); /* Load the accelerator table */ haccel = LoadAccelerators(hinstAcc, L"MainAccel"); if (haccel == NULL) fatal("haccel is null\n"); memset(rawinputkey, 0, sizeof(rawinputkey)); device.usUsagePage = 0x01; device.usUsage = 0x06; device.dwFlags = RIDEV_NOHOTKEYS; device.hwndTarget = hwnd; if (RegisterRawInputDevices(&device, 1, sizeof(device))) pclog("Raw input registered!\n"); else pclog("Raw input registration failed!\n"); get_registry_key_map(); ghwnd=hwnd; initpc(argc, argv); hwndRender = CreateWindow(L"STATIC", NULL, WS_VISIBLE | WS_CHILD | SS_BITMAP, 0, 0, 1, 1, ghwnd, NULL, hinstance, NULL); hwndStatus = EmulatorStatusBar(hwnd, IDC_STATUS, hThisInstance); OriginalStatusBarProcedure = GetWindowLongPtr(hwndStatus, GWLP_WNDPROC); SetWindowLongPtr(hwndStatus, GWL_WNDPROC, (LONG_PTR) &StatusBarProcedure); smenu = LoadMenu(hThisInstance, TEXT("StatusBarMenu")); initmenu(); if (vid_apis[0][vid_api].init(hwndRender) == 0) { if (vid_apis[0][vid_api ^ 1].init(hwndRender) == 0) { fatal("Both DirectDraw and Direct3D renderers failed to initialize\n"); } else { vid_api ^= 1; } } if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_MINIMIZEBOX)|WS_VISIBLE); else SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX)|WS_VISIBLE); /* Note by Kiririn: I've redone this since the CD-ROM can be disabled but still have something inside it. */ for (e = 0; e < CDROM_NUM; e++) { if (!cdrom_drives[e].sound_on) { CheckMenuItem(smenu, IDM_CDROM_1_MUTE + e, MF_CHECKED); } if (cdrom_drives[e].host_drive == 200) { CheckMenuItem(smenu, IDM_CDROM_1_IMAGE + e, MF_CHECKED); } else if (cdrom_drives[e].host_drive >= 65) { CheckMenuItem(smenu, IDM_CDROM_1_REAL + e + (cdrom_drives[e].host_drive << 2), MF_CHECKED); } else { CheckMenuItem(smenu, IDM_CDROM_1_EMPTY + e, MF_CHECKED); } } #ifdef ENABLE_LOG_TOGGLES #ifdef ENABLE_BUSLOGIC_LOG CheckMenuItem(menu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #ifdef ENABLE_CDROM_LOG CheckMenuItem(menu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #ifdef ENABLE_D86F_LOG CheckMenuItem(menu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #ifdef ENABLE_FDC_LOG CheckMenuItem(menu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #ifdef ENABLE_IDE_LOG CheckMenuItem(menu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #ifdef ENABLE_NE2000_LOG CheckMenuItem(menu, IDM_LOG_NE2000, ne2000_do_log ? MF_CHECKED : MF_UNCHECKED); #endif #endif CheckMenuItem(menu, IDM_VID_FORCE43, force_43 ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menu, IDM_VID_OVERSCAN, enable_overscan ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menu, IDM_VID_INVERT, invert_display ? MF_CHECKED : MF_UNCHECKED); if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menu, IDM_VID_SCALE_1X + scale, MF_CHECKED); d=romset; for (c=0;c= 0; c--) { if (gfx_present[c]) { gfxcard = c; saveconfig(); resetpchard(); break; } } } loadbios(); resetpchard(); timeBeginPeriod(1); atexit(releasemouse); ghMutex = CreateMutex(NULL, FALSE, NULL); mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); updatewindowsize(640, 480); QueryPerformanceFrequency(&qpc_freq); timer_freq = qpc_freq.QuadPart; if (start_in_fullscreen) { startblit(); mouse_close(); vid_apis[0][vid_api].close(); video_fullscreen = 1; vid_apis[1][vid_api].init(hwndRender); mouse_init(); leave_fullscreen_flag = 0; endblit(); device_force_redraw(); } if (window_remember) { MoveWindow(hwnd, window_x, window_y, window_w, window_h, TRUE); } else { MoveWindow(hwndRender, 0, 0, winsizex, winsizey, TRUE); MoveWindow(hwndStatus, 0, winsizey + 6, winsizex, 17, TRUE); } /* Run the message loop. It will run until GetMessage() returns 0 */ while (!quited) { while (((bRet = GetMessage(&messages,NULL,0,0)) != 0) && !quited) { if (bRet == -1) { fatal("bRet is -1\n"); } if (messages.message==WM_QUIT) quited=1; if (!TranslateAccelerator(hwnd, haccel, &messages)) { TranslateMessage(&messages); DispatchMessage(&messages); } if (recv_key[0x58] && recv_key[0x42] && mousecapture) { ClipCursor(&oldclip); ShowCursor(TRUE); mousecapture=0; } if ((recv_key[0x1D] || recv_key[0x9D]) && (recv_key[0x38] || recv_key[0xB8]) && (recv_key[0x51] || recv_key[0xD1]) && video_fullscreen) { leave_fullscreen(); } } quited=1; } startblit(); Sleep(200); TerminateThread(mainthreadh,0); savenvr(); saveconfig(); closepc(); vid_apis[video_fullscreen][vid_api].close(); timeEndPeriod(1); if (mousecapture) { ClipCursor(&oldclip); ShowCursor(TRUE); } UnregisterClass(szSubClassName, hinstance); UnregisterClass(szClassName, hinstance); return messages.wParam; } HHOOK hKeyboardHook; int hook_enabled = 0; LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) { BOOL bControlKeyDown; KBDLLHOOKSTRUCT* p; if (nCode < 0 || nCode != HC_ACTION) return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); p = (KBDLLHOOKSTRUCT*)lParam; if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-tab */ if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1; /* disable windows keys */ if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1; /* disable alt-escape */ bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1); /* checks ctrl key pressed */ if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; /* disable ctrl-escape */ return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); } void cdrom_close(uint8_t id) { switch (cdrom_drives[id].host_drive) { case 0: null_close(id); break; default: ioctl_close(id); break; case 200: image_close(id); break; } } int ide_ter_set_irq(HMENU hmenu, int irq, int id) { if (ide_irq[2] == irq) { return 0; } if (msgbox_reset_yn(ghwnd) != IDYES) { return 0; } pause = 1; Sleep(100); ide_irq[2] = irq; CheckMenuItem(hmenu, IDM_IDE_TER_IRQ9, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_TER_IRQ10, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_TER_IRQ11, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_TER_IRQ12, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_TER_IRQ14, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_TER_IRQ15, MF_UNCHECKED); CheckMenuItem(hmenu, id, MF_CHECKED); saveconfig(); resetpchard(); pause = 0; return 1; } int ide_qua_set_irq(HMENU hmenu, int irq, int id) { if (ide_irq[3] == irq) { return 0; } if (msgbox_reset_yn(ghwnd) != IDYES) { return 0; } pause = 1; Sleep(100); ide_irq[3] = irq; CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ9, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ10, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ11, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ12, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ14, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_IDE_QUA_IRQ15, MF_UNCHECKED); CheckMenuItem(hmenu, id, MF_CHECKED); saveconfig(); resetpchard(); pause = 0; return 1; } void video_toggle_option(HMENU hmenu, int *val, int id) { *val ^= 1; CheckMenuItem(hmenu, id, *val ? MF_CHECKED : MF_UNCHECKED); saveconfig(); } void win_cdrom_eject(uint8_t id) { HMENU hmenu; hmenu = GetSubMenu(smenu, id + 4); if (cdrom_drives[id].host_drive == 0) { /* Switch from empty to empty. Do nothing. */ return; } cdrom_drives[id].handler->exit(id); cdrom_close(id); cdrom_null_open(id, 0); if (cdrom_drives[id].bus_type) { /* Signal disc change to the emulated machine. */ cdrom_insert(id); } CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + id, MF_UNCHECKED); if ((cdrom_drives[id].host_drive >= 65) && (cdrom_drives[id].host_drive <= 90)) { CheckMenuItem(hmenu, IDM_CDROM_1_REAL + id + (cdrom_drive << 2), MF_UNCHECKED); } cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; cdrom_drives[id].host_drive=0; CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_CHECKED); update_status_bar_icon_state(0x10 | id, get_cd_state(id)); update_tip(0x10 | id); saveconfig(); } void win_cdrom_reload(uint8_t id) { HMENU hmenu; hmenu = GetSubMenu(smenu, id + 4); int new_cdrom_drive; if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { /* Switch from empty to empty. Do nothing. */ return; } cdrom_close(id); if (cdrom_drives[id].prev_host_drive == 200) { image_open(id, cdrom_image[id].image_path); if (cdrom_drives[id].bus_type) { /* Signal disc change to the emulated machine. */ cdrom_insert(id); } CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_UNCHECKED); cdrom_drives[id].host_drive = 200; CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + id, MF_CHECKED); } else { new_cdrom_drive = cdrom_drives[id].prev_host_drive; ioctl_open(id, new_cdrom_drive); if (cdrom_drives[id].bus_type) { /* Signal disc change to the emulated machine. */ cdrom_insert(id); } CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + id, MF_UNCHECKED); cdrom_drive = new_cdrom_drive; CheckMenuItem(hmenu, IDM_CDROM_1_REAL + id + (cdrom_drives[id].host_drive << 2), MF_CHECKED); } update_status_bar_icon_state(0x10 | id, get_cd_state(id)); update_tip(0x10 | id); saveconfig(); } static BOOL CALLBACK about_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; switch (message) { case WM_INITDIALOG: pause = 1; h = GetDlgItem(hdlg, IDC_ABOUT_ICON); SendMessage(h, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM) LoadIconBig((PCTSTR) 100)); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hdlg, 0); pause = 0; return TRUE; default: break; } break; } return FALSE; } void about_open(HWND hwnd) { DialogBox(hinstance, (LPCTSTR) ABOUTDLG, hwnd, about_dlgproc); } LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HMENU hmenu; RECT rect; uint32_t ri_size = 0; int edgex, edgey; int sb_borders[3]; switch (message) { case WM_CREATE: SetTimer(hwnd, TIMER_1SEC, 1000, NULL); hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); hook_enabled = 1; break; case WM_COMMAND: hmenu=GetMenu(hwnd); switch (LOWORD(wParam)) { case IDM_FILE_HRESET: pause=1; Sleep(100); savenvr(); saveconfig(); resetpchard(); pause=0; break; case IDM_FILE_RESET_CAD: pause=1; Sleep(100); savenvr(); saveconfig(); resetpc_cad(); pause=0; break; case IDM_FILE_EXIT: PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case IDM_CONFIG: win_settings_open(hwnd); break; case IDM_ABOUT: about_open(hwnd); break; case IDM_STATUS: status_open(hwnd); break; case IDM_VID_RESIZE: vid_resize=!vid_resize; CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); if (vid_resize) SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_MINIMIZEBOX)|WS_VISIBLE); else SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX&~WS_MINIMIZEBOX)|WS_VISIBLE); GetWindowRect(hwnd,&rect); SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); GetWindowRect(hwndStatus,&rect); SetWindowPos(hwndStatus, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); if (vid_resize) { CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); scale = 1; } EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); win_doresize = 1; saveconfig(); break; case IDM_VID_REMEMBER: window_remember = !window_remember; CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); GetWindowRect(hwnd, &rect); if (window_remember) { window_x = rect.left; window_y = rect.top; window_w = rect.right - rect.left; window_h = rect.bottom - rect.top; } saveconfig(); break; case IDM_VID_DDRAW: case IDM_VID_D3D: startblit(); video_wait_for_blit(); CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); vid_apis[0][vid_api].close(); vid_api = LOWORD(wParam) - IDM_VID_DDRAW; CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); vid_apis[0][vid_api].init(hwndRender); endblit(); saveconfig(); device_force_redraw(); break; case IDM_VID_FULLSCREEN: if(video_fullscreen!=1){ if (video_fullscreen_first) { video_fullscreen_first = 0; msgbox_info(ghwnd, 2193); } startblit(); video_wait_for_blit(); mouse_close(); vid_apis[0][vid_api].close(); video_fullscreen = 1; vid_apis[1][vid_api].init(ghwnd); mouse_init(); leave_fullscreen_flag = 0; endblit(); device_force_redraw(); } break; case IDM_VID_FS_FULL: case IDM_VID_FS_43: case IDM_VID_FS_SQ: case IDM_VID_FS_INT: CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); saveconfig(); break; case IDM_VID_SCALE_1X: case IDM_VID_SCALE_2X: case IDM_VID_SCALE_3X: case IDM_VID_SCALE_4X: CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); scale = LOWORD(wParam) - IDM_VID_SCALE_1X; CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_CHECKED); saveconfig(); break; case IDM_VID_FORCE43: video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); break; case IDM_VID_INVERT: video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); break; case IDM_VID_OVERSCAN: video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); update_overscan = 1; break; case IDM_VID_FLASH: video_toggle_option(hmenu, &enable_flash, IDM_VID_FLASH); break; case IDM_VID_SCREENSHOT: take_screenshot(); break; #ifdef ENABLE_LOG_TOGGLES #ifdef ENABLE_BUSLOGIC_LOG case IDM_LOG_BUSLOGIC: buslogic_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #ifdef ENABLE_CDROM_LOG case IDM_LOG_CDROM: cdrom_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #ifdef ENABLE_D86F_LOG case IDM_LOG_D86F: d86f_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #ifdef ENABLE_FDC_LOG case IDM_LOG_FDC: fdc_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #ifdef ENABLE_IDE_LOG case IDM_LOG_IDE: ide_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #ifdef ENABLE_NE2000_LOG case IDM_LOG_NE2000: ne2000_do_log ^= 1; CheckMenuItem(hmenu, IDM_LOG_NE2000, ne2000_do_log ? MF_CHECKED : MF_UNCHECKED); break; #endif #endif #ifdef ENABLE_LOG_BREAKPOINT case IDM_LOG_BREAKPOINT: pclog("---- LOG BREAKPOINT ----\n"); break; #endif #ifdef ENABLE_VRAM_DUMP case IDM_DUMP_VRAM: svga_dump_vram(); break; #endif case IDM_CONFIG_LOAD: pause = 1; if (!file_dlg_st(hwnd, 2174, "", 0)) { if (msgbox_reset_yn(ghwnd) == IDYES) { config_save(config_file_default); loadconfig(wopenfilestring); pclog_w(L"NVR path: %s\n", nvr_path); mem_resize(); loadbios(); resetpchard(); } } pause = 0; break; case IDM_CONFIG_SAVE: pause = 1; if (!file_dlg_st(hwnd, 2174, "", 1)) config_save(wopenfilestring); pause = 0; break; } return 0; case WM_INPUT: { UINT size; RAWINPUT *raw; if (!infocus) break; GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); raw = malloc(size); if (raw == NULL) { return 0; } /* Here we read the raw input data for the keyboard */ ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); if(ri_size != size) { return 0; } /* If the input is keyboard, we process it */ if (raw->header.dwType == RIM_TYPEKEYBOARD) { const RAWKEYBOARD rawKB = raw->data.keyboard; USHORT scancode = rawKB.MakeCode; /* If it's not a scan code that starts with 0xE1 */ if (!(rawKB.Flags & RI_KEY_E1)) { if (rawKB.Flags & RI_KEY_E0) scancode |= (0xE0 << 8); /* Remap it according to the list from the Registry */ scancode = scancode_map[scancode]; if ((scancode >> 8) == 0xF0) scancode |= 0x100; /* Extended key code in disambiguated format */ else if ((scancode >> 8) == 0xE0) scancode |= 0x80; /* Normal extended key code */ /* If it's not 0 (therefore not 0xE1, 0xE2, etc), then pass it on to the rawinputkey array */ if (!(scancode & 0xf00)) { rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; } } else { if (rawKB.MakeCode == 0x1D) scancode = 0xFF; if (!(scancode & 0xf00)) { rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); recv_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; } } } free(raw); } break; case WM_SETFOCUS: infocus=1; if (!hook_enabled) { hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); hook_enabled = 1; } break; case WM_KILLFOCUS: infocus=0; if (mousecapture) { ClipCursor(&oldclip); ShowCursor(TRUE); mousecapture=0; } memset(rawinputkey, 0, sizeof(rawinputkey)); if (video_fullscreen) leave_fullscreen_flag = 1; if (hook_enabled) { UnhookWindowsHookEx(hKeyboardHook); hook_enabled = 0; } break; case WM_LBUTTONUP: if (!mousecapture && !video_fullscreen) { RECT pcclip; GetClipCursor(&oldclip); GetWindowRect(hwnd, &pcclip); pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; ClipCursor(&pcclip); mousecapture = 1; while (1) { if (ShowCursor(FALSE) < 0) break; } } break; case WM_MBUTTONUP: if (!(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) releasemouse(); break; case WM_ENTERMENULOOP: break; case WM_SIZE: winsizex = (lParam & 0xFFFF); winsizey = (lParam >> 16) - (17 + 6); MoveWindow(hwndRender, 0, 0, winsizex, winsizey, TRUE); if (vid_apis[video_fullscreen][vid_api].resize) { startblit(); video_wait_for_blit(); vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); endblit(); } MoveWindow(hwndStatus, 0, winsizey + 6, winsizex, 17, TRUE); if (mousecapture) { RECT pcclip; GetWindowRect(hwnd, &pcclip); pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; ClipCursor(&pcclip); } if (window_remember) { GetWindowRect(hwnd, &rect); window_x = rect.left; window_y = rect.top; window_w = rect.right - rect.left; window_h = rect.bottom - rect.top; save_window_pos = 1; } break; case WM_MOVE: if (window_remember) { GetWindowRect(hwnd, &rect); window_x = rect.left; window_y = rect.top; window_w = rect.right - rect.left; window_h = rect.bottom - rect.top; save_window_pos = 1; } break; case WM_TIMER: if (wParam == TIMER_1SEC) onesec(); break; case WM_RESETD3D: startblit(); if (video_fullscreen) d3d_fs_reset(); else d3d_reset(); endblit(); break; case WM_LEAVEFULLSCREEN: startblit(); mouse_close(); vid_apis[1][vid_api].close(); video_fullscreen = 0; vid_apis[0][vid_api].init(ghwnd); mouse_init(); endblit(); device_force_redraw(); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: return 0; case WM_DESTROY: UnhookWindowsHookEx( hKeyboardHook ); KillTimer(hwnd, TIMER_1SEC); PostQuitMessage (0); /* send a WM_QUIT to the message queue */ break; case WM_SYSCOMMAND: /* Disable ALT key *ALWAYS*, I don't think there's any use for reaching the menu that way. */ if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) return 0; /*disable ALT key for menu*/ default: return DefWindowProc (hwnd, message, wParam, lParam); } return 0; } LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } VOID APIENTRY HandlePopupMenu(HWND hwnd, POINT pt, int id) { HMENU pmenu; int menu_id = -1; if (id >= (sb_parts - 1)) { return; } pt.x = id * sb_icon_width; /* Justify to the left. */ pt.y = 0; /* Justify to the top. */ ClientToScreen(hwnd, (LPPOINT) &pt); if ((sb_part_meanings[id] & 0xf0) == 0x00) { menu_id = sb_part_meanings[id] & 0xf; } else if ((sb_part_meanings[id] & 0xf0) == 0x10) { menu_id = (sb_part_meanings[id] & 0xf) + 4; } #if 0 else if ((sb_part_meanings[id] & 0xf0) == 0x20) { menu_id = (sb_part_meanings[id] & 0xf) + 8; } #endif if (menu_id != -1) { pmenu = GetSubMenu(smenu, menu_id); TrackPopupMenu(pmenu, TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, hwndStatus, NULL); } } LRESULT CALLBACK StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rc; POINT pt; WCHAR temp_image_path[1024]; int new_cdrom_drive; int cdrom_id = 0; int menu_sub_param = 0; int menu_super_param = 0; int ret = 0; HMENU hmenu; switch (message) { case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_DISC_1: case IDM_DISC_1_WP: ret = file_dlg_w_st(hwnd, 2173, discfns[0], 0); if (!ret) { disc_close(0); ui_writeprot[0] = (LOWORD(wParam) == IDM_DISC_1_WP) ? 1 : 0; disc_load(0, wopenfilestring); update_status_bar_icon_state(0x00, 0); update_tip(0x00); saveconfig(); } break; case IDM_DISC_2: case IDM_DISC_2_WP: ret = file_dlg_w_st(hwnd, 2173, discfns[1], 0); if (!ret) { disc_close(1); ui_writeprot[1] = (LOWORD(wParam) == IDM_DISC_2_WP) ? 1 : 0; disc_load(1, wopenfilestring); update_status_bar_icon_state(0x01, 0); update_tip(0x01); saveconfig(); } break; case IDM_DISC_3: case IDM_DISC_3_WP: ret = file_dlg_w_st(hwnd, 2173, discfns[2], 0); if (!ret) { disc_close(2); ui_writeprot[2] = (LOWORD(wParam) == IDM_DISC_3_WP) ? 1 : 0; disc_load(2, wopenfilestring); update_status_bar_icon_state(0x02, 0); update_tip(0x02); saveconfig(); } break; case IDM_DISC_4: case IDM_DISC_4_WP: ret = file_dlg_w_st(hwnd, 2173, discfns[3], 0); if (!ret) { disc_close(3); ui_writeprot[3] = (LOWORD(wParam) == IDM_DISC_4_WP) ? 1 : 0; disc_load(3, wopenfilestring); update_status_bar_icon_state(0x03, 0); update_tip(0x03); saveconfig(); } break; case IDM_EJECT_1: disc_close(0); update_status_bar_icon_state(0x00, 1); update_tip(0x00); saveconfig(); break; case IDM_EJECT_2: disc_close(1); update_status_bar_icon_state(0x01, 1); update_tip(0x01); saveconfig(); break; case IDM_EJECT_3: disc_close(2); update_status_bar_icon_state(0x02, 1); update_tip(0x02); saveconfig(); break; case IDM_EJECT_4: disc_close(3); update_status_bar_icon_state(0x03, 1); update_tip(0x03); saveconfig(); break; case IDM_CDROM_1_MUTE: case IDM_CDROM_2_MUTE: case IDM_CDROM_3_MUTE: case IDM_CDROM_4_MUTE: cdrom_id = LOWORD(wParam) & 3; hmenu = GetSubMenu(smenu, cdrom_id + 4); Sleep(100); cdrom_drives[cdrom_id].sound_on ^= 1; CheckMenuItem(hmenu, IDM_CDROM_1_MUTE + (cdrom_id * 1000), cdrom_drives[cdrom_id].sound_on ? MF_UNCHECKED : MF_CHECKED); saveconfig(); sound_cd_thread_reset(); break; case IDM_CDROM_1_EMPTY: case IDM_CDROM_2_EMPTY: case IDM_CDROM_3_EMPTY: case IDM_CDROM_4_EMPTY: cdrom_id = LOWORD(wParam) & 3; hmenu = GetSubMenu(smenu, cdrom_id + 4); win_cdrom_eject(cdrom_id); break; case IDM_CDROM_1_RELOAD: case IDM_CDROM_2_RELOAD: case IDM_CDROM_3_RELOAD: case IDM_CDROM_4_RELOAD: cdrom_id = LOWORD(wParam) & 3; hmenu = GetSubMenu(smenu, cdrom_id + 4); win_cdrom_reload(cdrom_id); break; case IDM_CDROM_1_IMAGE: case IDM_CDROM_2_IMAGE: case IDM_CDROM_3_IMAGE: case IDM_CDROM_4_IMAGE: cdrom_id = LOWORD(wParam) & 3; hmenu = GetSubMenu(smenu, cdrom_id + 4); if (!file_dlg_w_st(hwnd, 2175, cdrom_image[cdrom_id].image_path, 0)) { cdrom_drives[cdrom_id].prev_host_drive = cdrom_drives[cdrom_id].host_drive; wcscpy(temp_image_path, wopenfilestring); if ((wcscmp(cdrom_image[cdrom_id].image_path, temp_image_path) == 0) && (cdrom_drives[cdrom_id].host_drive == 200)) { /* Switching from image to the same image. Do nothing. */ break; } cdrom_drives[cdrom_id].handler->exit(cdrom_id); cdrom_close(cdrom_id); image_open(cdrom_id, temp_image_path); if (cdrom_drives[cdrom_id].bus_type) { /* Signal disc change to the emulated machine. */ cdrom_insert(cdrom_id); } CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + cdrom_id, MF_UNCHECKED); if ((cdrom_drives[cdrom_id].host_drive != 0) && (cdrom_drives[cdrom_id].host_drive != 200)) { CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_UNCHECKED); } cdrom_drives[cdrom_id].host_drive = 200; CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + cdrom_id, MF_CHECKED); update_tip(0x10 | cdrom_id); saveconfig(); } break; default: cdrom_id = LOWORD(wParam) & 3; hmenu = GetSubMenu(smenu, cdrom_id + 4); menu_sub_param = ((LOWORD(wParam) - IDM_CDROM_1_REAL) - cdrom_id) >> 2; /* pclog("[%04X] Guest drive %c [%i]: -> Host drive %c [%i]:\n", LOWORD(wParam), 0x4b + cdrom_id, cdrom_id, menu_sub_param, menu_sub_param); */ if (((LOWORD(wParam) & ~3) >= (IDM_CDROM_1_REAL + ('A' << 2))) && ((LOWORD(wParam) & ~3) <= (IDM_CDROM_1_REAL + ('Z' << 2)))) { new_cdrom_drive = menu_sub_param; if (cdrom_drives[cdrom_id].host_drive == new_cdrom_drive) { /* Switching to the same drive. Do nothing. */ break; } cdrom_drives[cdrom_id].prev_host_drive = cdrom_drives[cdrom_id].host_drive; cdrom_drives[cdrom_id].handler->exit(cdrom_id); cdrom_close(cdrom_id); ioctl_open(cdrom_id, new_cdrom_drive); if (cdrom_drives[cdrom_id].bus_type) { /* Signal disc change to the emulated machine. */ cdrom_insert(cdrom_id); } CheckMenuItem(hmenu, IDM_CDROM_1_EMPTY + cdrom_id, MF_UNCHECKED); if ((cdrom_drives[cdrom_id].host_drive != 0) && (cdrom_drives[cdrom_id].host_drive != 200)) { CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_UNCHECKED); } CheckMenuItem(hmenu, IDM_CDROM_1_IMAGE + cdrom_id, MF_UNCHECKED); cdrom_drives[cdrom_id].host_drive = new_cdrom_drive; CheckMenuItem(hmenu, IDM_CDROM_1_REAL + cdrom_id + (cdrom_drives[cdrom_id].host_drive << 2), MF_CHECKED); update_tip(0x10 | cdrom_id); saveconfig(); } break; } return 0; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: GetClientRect(hwnd, (LPRECT)& rc); pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); if (PtInRect((LPRECT) &rc, pt)) { HandlePopupMenu(hwnd, pt, (pt.x / sb_icon_width)); } break; default: return CallWindowProc((WNDPROC) OriginalStatusBarProcedure, hwnd, message, wParam, lParam); } return 0; }