PCem

view src/win.c @ 151:55564c65aa15

Added configuration load/save options.
author TomW
date Sat Aug 23 21:32:36 2014 +0100
parents 82d7f693029b
children d0d530adce12
line source
1 #define _WIN32_WINNT 0x0501
2 #define BITMAP WINDOWS_BITMAP
3 #include <windows.h>
4 #include <windowsx.h>
5 #undef BITMAP
7 #include <commctrl.h>
8 #include <commdlg.h>
10 #include <process.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdarg.h>
15 #include <stdlib.h>
16 #include "ibm.h"
17 #include "config.h"
18 #include "video.h"
19 #include "resources.h"
20 #include "cpu.h"
21 #include "ide.h"
22 #include "model.h"
23 #include "nvr.h"
24 #include "sound.h"
25 #include "thread.h"
27 #include "plat-midi.h"
28 #include "plat-keyboard.h"
30 #include "win.h"
31 #include "win-ddraw.h"
32 #include "win-ddraw-fs.h"
33 #include "win-d3d.h"
34 #include "win-d3d-fs.h"
35 //#include "win-opengl.h"
37 #ifndef MAPVK_VK_TO_VSC
38 #define MAPVK_VK_TO_VSC 0
39 #endif
41 uint64_t timer_freq;
43 static RAWINPUTDEVICE device;
44 static uint16_t scancode_map[65536];
46 static struct
47 {
48 void (*init)(HWND h);
49 void (*close)();
50 void (*resize)(int x, int y);
51 } vid_apis[2][2] =
52 {
53 {
54 ddraw_init, ddraw_close, NULL,
55 d3d_init, d3d_close, d3d_resize
56 },
57 {
58 ddraw_fs_init, ddraw_fs_close, NULL,
59 d3d_fs_init, d3d_fs_close, NULL
60 },
61 };
63 #define TIMER_1SEC 1
65 int winsizex=640,winsizey=480;
66 int gfx_present[GFX_MAX];
67 #undef cs
68 CRITICAL_SECTION cs;
70 HANDLE mainthreadh;
72 int infocus=1;
74 int drawits=0;
76 int romspresent[ROM_MAX];
77 int quited=0;
79 RECT oldclip;
80 int mousecapture=0;
82 /* Declare Windows procedure */
83 LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
84 LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
86 HWND ghwnd;
88 HINSTANCE hinstance;
90 HMENU menu;
92 extern int updatestatus;
94 int pause=0;
96 static int win_doresize = 0;
98 static int leave_fullscreen_flag = 0;
100 void updatewindowsize(int x, int y)
101 {
102 RECT r;
103 if (vid_resize) return;
105 winsizex=x; winsizey=y;
106 win_doresize = 1;
107 }
109 void releasemouse()
110 {
111 if (mousecapture)
112 {
113 ClipCursor(&oldclip);
114 ShowCursor(TRUE);
115 mousecapture = 0;
116 }
117 }
119 void startblit()
120 {
121 EnterCriticalSection(&cs);
122 }
124 void endblit()
125 {
126 LeaveCriticalSection(&cs);
127 }
129 void leave_fullscreen()
130 {
131 leave_fullscreen_flag = 1;
132 }
134 void mainthread(LPVOID param)
135 {
136 int t = 0;
137 int frames = 0;
138 DWORD old_time, new_time;
140 // Sleep(500);
141 drawits=0;
142 old_time = GetTickCount();
143 while (!quited)
144 {
145 if (updatestatus)
146 {
147 updatestatus = 0;
148 if (status_is_open)
149 SendMessage(status_hwnd, WM_USER, 0, 0);
150 }
151 new_time = GetTickCount();
152 drawits += new_time - old_time;
153 old_time = new_time;
154 if (drawits > 0 && !pause)
155 {
156 drawits-=10; if (drawits>50) drawits=0;
157 runpc();
158 frames++;
159 if (frames >= 200 && nvr_dosave)
160 {
161 frames = 0;
162 nvr_dosave = 0;
163 savenvr();
164 }
165 }
166 else
167 Sleep(1);
169 if (!video_fullscreen && win_doresize)
170 {
171 RECT r;
172 GetWindowRect(ghwnd, &r);
173 MoveWindow(ghwnd, r.left, r.top,
174 winsizex + (GetSystemMetrics(SM_CXFIXEDFRAME) * 2),
175 winsizey + (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 1,
176 TRUE);
177 win_doresize = 0;
178 }
180 if (leave_fullscreen_flag)
181 {
182 leave_fullscreen_flag = 0;
183 SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0);
184 }
185 }
186 }
188 void *thread_create(void (*thread_rout)(void *param), void *param)
189 {
190 return (void *)_beginthread(thread_rout, 0, param);
191 }
193 void thread_kill(void *handle)
194 {
195 TerminateThread(handle, 0);
196 }
198 void thread_sleep(int t)
199 {
200 Sleep(t);
201 }
203 typedef struct win_event_t
204 {
205 HANDLE handle;
206 } win_event_t;
208 event_t *thread_create_event()
209 {
210 win_event_t *event = malloc(sizeof(win_event_t));
212 event->handle = CreateEvent(NULL, FALSE, FALSE, NULL);
214 return (event_t *)event;
215 }
217 void thread_set_event(event_t *_event)
218 {
219 win_event_t *event = (win_event_t *)_event;
221 SetEvent(event->handle);
222 }
224 void thread_reset_event(event_t *_event)
225 {
226 win_event_t *event = (win_event_t *)_event;
228 ResetEvent(event->handle);
229 }
231 int thread_wait_event(event_t *_event, int timeout)
232 {
233 win_event_t *event = (win_event_t *)_event;
235 if (timeout == -1)
236 timeout = INFINITE;
238 if (WaitForSingleObject(event->handle, timeout))
239 return 1;
240 return 0;
241 }
243 void thread_destroy_event(event_t *_event)
244 {
245 win_event_t *event = (win_event_t *)_event;
247 CloseHandle(event->handle);
249 free(event);
250 }
252 static void initmenu(void)
253 {
254 int c;
255 HMENU m;
256 char s[32];
257 m=GetSubMenu(menu,2); /*Settings*/
258 m=GetSubMenu(m,1); /*CD-ROM*/
260 /* Loop through each Windows drive letter and test to see if
261 it's a CDROM */
262 for (c='A';c<='Z';c++)
263 {
264 sprintf(s,"%c:\\",c);
265 if (GetDriveType(s)==DRIVE_CDROM)
266 {
267 sprintf(s, "Host CD/DVD Drive (%c:)", c);
268 AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s);
269 }
270 }
271 }
273 void get_executable_name(char *s, int size)
274 {
275 GetModuleFileName(hinstance, s, size);
276 }
278 void set_window_title(char *s)
279 {
280 if (video_fullscreen)
281 return;
282 SetWindowText(ghwnd, s);
283 }
285 uint64_t timer_read()
286 {
287 LARGE_INTEGER qpc_time;
288 QueryPerformanceCounter(&qpc_time);
289 return qpc_time.QuadPart;
290 }
292 /* This is so we can disambiguate scan codes that would otherwise conflict and get
293 passed on incorrectly. */
294 UINT16 convert_scan_code(UINT16 scan_code)
295 {
296 switch (scan_code)
297 {
298 case 0xE001:
299 return 0xF001;
300 case 0xE002:
301 return 0xF002;
302 case 0xE005:
303 return 0xF005;
304 case 0xE006:
305 return 0xF006;
306 case 0xE007:
307 return 0xF007;
308 case 0xE071:
309 return 0xF008;
310 case 0xE072:
311 return 0xF009;
312 case 0xE07F:
313 return 0xF00A;
314 case 0xE0E1:
315 return 0xF00B;
316 case 0xE0EE:
317 return 0xF00C;
318 case 0xE0F1:
319 return 0xF00D;
320 case 0xE0FE:
321 return 0xF00E;
322 case 0xE0EF:
323 return 0xF00F;
325 default:
326 return scan_code;
327 }
328 }
330 void get_registry_key_map()
331 {
332 char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout";
333 char *valueName = "Scancode Map";
334 char buf[32768];
335 DWORD bufSize;
336 HKEY hKey;
337 int j;
339 /* First, prepare the default scan code map list which is 1:1.
340 Remappings will be inserted directly into it.
341 65536 bytes so scan codes fit in easily and it's easy to find what each maps too,
342 since each array element is a scan code and provides for E0, etc. ones too. */
343 for (j = 0; j < 65536; j++)
344 scancode_map[j] = convert_scan_code(j);
346 bufSize = 32768;
347 pclog("Preparing scan code map list...\n");
348 /* Get the scan code remappings from:
349 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */
350 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS)
351 {
352 if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS)
353 {
354 UINT32 *bufEx2 = (UINT32 *) buf;
355 int scMapCount = bufEx2[2];
356 pclog("%lu scan code mappings found!\n", scMapCount);
357 if ((bufSize != 0) && (scMapCount != 0))
358 {
359 UINT16 *bufEx = (UINT16 *) (buf + 12);
360 pclog("More than zero scan code mappings found, processing...\n");
361 for (j = 0; j < scMapCount*2; j += 2)
362 {
363 /* Each scan code is 32-bit: 16 bits of remapped scan code,
364 and 16 bits of original scan code. */
365 int scancode_unmapped = bufEx[j + 1];
366 int scancode_mapped = bufEx[j];
368 scancode_mapped = convert_scan_code(scancode_mapped);
370 scancode_map[scancode_unmapped] = scancode_mapped;
371 pclog("Scan code mapping %u detected: %X -> %X\n", scancode_unmapped, scancode_mapped, scancode_map[scancode_unmapped]);
372 }
373 pclog("Done processing!\n");
374 }
375 }
376 RegCloseKey(hKey);
377 }
378 pclog("Done preparing!\n");
379 }
381 int WINAPI WinMain (HINSTANCE hThisInstance,
382 HINSTANCE hPrevInstance,
383 LPSTR lpszArgument,
384 int nFunsterStil)
386 {
387 HWND hwnd; /* This is the handle for our window */
388 MSG messages; /* Here messages to the application are saved */
389 WNDCLASSEX wincl; /* Data structure for the windowclass */
390 int c, d;
391 LARGE_INTEGER qpc_freq;
393 hinstance=hThisInstance;
394 /* The Window structure */
395 wincl.hInstance = hThisInstance;
396 wincl.lpszClassName = szClassName;
397 wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
398 wincl.style = CS_DBLCLKS; /* Catch double-clicks */
399 wincl.cbSize = sizeof (WNDCLASSEX);
401 /* Use default icon and mouse-pointer */
402 wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
403 wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
404 wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW);
405 wincl.lpszMenuName = NULL; /* No menu */
406 wincl.cbClsExtra = 0; /* No extra bytes after the window class */
407 wincl.cbWndExtra = 0; /* structure or the window instance */
408 /* Use Windows's default color as the background of the window */
409 wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
411 /* Register the window class, and if it fails quit the program */
412 if (!RegisterClassEx(&wincl))
413 return 0;
415 wincl.lpszClassName = szSubClassName;
416 wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */
418 if (!RegisterClassEx(&wincl))
419 return 0;
421 menu = LoadMenu(hThisInstance, TEXT("MainMenu"));
422 initmenu();
424 /* The class is registered, let's create the program*/
425 hwnd = CreateWindowEx (
426 0, /* Extended possibilites for variation */
427 szClassName, /* Classname */
428 "PCem v8.1", /* Title Text */
429 WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */
430 CW_USEDEFAULT, /* Windows decides the position */
431 CW_USEDEFAULT, /* where the window ends up on the screen */
432 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */
433 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */
434 HWND_DESKTOP, /* The window is a child-window to desktop */
435 menu, /* Menu */
436 hThisInstance, /* Program Instance handler */
437 NULL /* No Window Creation data */
438 );
440 /* Make the window visible on the screen */
441 ShowWindow (hwnd, nFunsterStil);
443 // win_set_window(hwnd);
445 memset(rawinputkey, 0, sizeof(rawinputkey));
446 device.usUsagePage = 0x01;
447 device.usUsage = 0x06;
448 device.dwFlags = RIDEV_NOHOTKEYS;
449 device.hwndTarget = hwnd;
451 if (RegisterRawInputDevices(&device, 1, sizeof(device)))
452 pclog("Raw input registered!\n");
453 else
454 pclog("Raw input registration failed!\n");
456 get_registry_key_map();
458 ghwnd=hwnd;
460 midi_init();
461 atexit(midi_close);
463 initpc();
465 vid_apis[0][vid_api].init(ghwnd);
467 if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE);
468 else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE);
470 if (!cdrom_enabled)
471 CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED);
472 else
473 CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED);
474 if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED);
475 CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED);
476 CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED);
477 // set_display_switch_mode(SWITCH_BACKGROUND);
479 d=romset;
480 for (c=0;c<ROM_MAX;c++)
481 {
482 romset=c;
483 romspresent[c]=loadbios();
484 pclog("romset %i - %i\n", c, romspresent[c]);
485 }
487 for (c = 0; c < ROM_MAX; c++)
488 {
489 if (romspresent[c])
490 break;
491 }
492 if (c == ROM_MAX)
493 {
494 MessageBox(hwnd,"No ROMs present!\nYou must have at least one romset to use PCem.","PCem fatal error",MB_OK);
495 return 0;
496 }
498 romset=d;
499 c=loadbios();
501 if (!c)
502 {
503 if (romset!=-1) MessageBox(hwnd,"Configured romset not available.\nDefaulting to available romset.","PCem error",MB_OK);
504 for (c=0;c<ROM_MAX;c++)
505 {
506 if (romspresent[c])
507 {
508 romset = c;
509 model = model_getmodel(romset);
510 saveconfig();
511 resetpchard();
512 break;
513 }
514 }
515 }
518 for (c = 0; c < GFX_MAX; c++)
519 gfx_present[c] = video_card_available(video_old_to_new(c));
521 if (!video_card_available(video_old_to_new(gfxcard)))
522 {
523 if (romset!=-1) MessageBox(hwnd,"Configured video BIOS not available.\nDefaulting to available romset.","PCem error",MB_OK);
524 for (c = GFX_MAX-1; c >= 0; c--)
525 {
526 if (gfx_present[c])
527 {
528 gfxcard = c;
529 saveconfig();
530 resetpchard();
531 break;
532 }
533 }
534 }
536 loadbios();
538 timeBeginPeriod(1);
540 atexit(releasemouse);
542 // QueryPerformanceFrequency(&counter_base);
543 /// QueryPerformanceCounter(&counter_posold);
544 // counter_posold.QuadPart*=100;
546 InitializeCriticalSection(&cs);
547 mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL);
548 SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST);
551 updatewindowsize(640, 480);
553 QueryPerformanceFrequency(&qpc_freq);
554 timer_freq = qpc_freq.QuadPart;
556 // focus=1;
557 // setrefresh(100);
559 // ShowCursor(TRUE);
561 /* Run the message loop. It will run until GetMessage() returns 0 */
562 while (!quited)
563 {
564 /* if (infocus)
565 {
566 if (drawits)
567 {
568 drawits--;
569 if (drawits>10) drawits=0;
570 runpc();
571 }
572 //; else
573 // sleep(0);
574 if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture)
575 {
576 ClipCursor(&oldclip);
577 mousecapture=0;
578 }
579 }*/
581 while (GetMessage(&messages,NULL,0,0) && !quited)
582 {
583 if (messages.message==WM_QUIT) quited=1;
584 TranslateMessage(&messages);
585 DispatchMessage(&messages);
586 if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture)
587 {
588 ClipCursor(&oldclip);
589 ShowCursor(TRUE);
590 mousecapture=0;
591 }
592 }
594 quited=1;
595 // else
596 // sleep(10);
597 }
599 startblit();
600 // pclog("Sleep 1000\n");
601 Sleep(200);
602 // pclog("TerminateThread\n");
603 TerminateThread(mainthreadh,0);
604 // pclog("Quited? %i\n",quited);
605 // pclog("Closepc\n");
606 closepc();
607 // pclog("dumpregs\n");
609 vid_apis[video_fullscreen][vid_api].close();
611 timeEndPeriod(1);
612 // dumpregs();
613 if (mousecapture)
614 {
615 ClipCursor(&oldclip);
616 ShowCursor(TRUE);
617 }
619 UnregisterClass(szSubClassName, hinstance);
620 UnregisterClass(szClassName, hinstance);
622 // pclog("Ending! %i %i\n",messages.wParam,quited);
623 return messages.wParam;
624 }
626 char openfilestring[260];
627 int getfile(HWND hwnd, char *f, char *fn)
628 {
629 OPENFILENAME ofn; // common dialog box structure
630 BOOL r;
631 DWORD err;
633 // Initialize OPENFILENAME
634 ZeroMemory(&ofn, sizeof(ofn));
635 ofn.lStructSize = sizeof(ofn);
636 ofn.hwndOwner = hwnd;
637 ofn.lpstrFile = openfilestring;
638 //
639 // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
640 // use the contents of szFile to initialize itself.
641 //
642 // ofn.lpstrFile[0] = '\0';
643 strcpy(ofn.lpstrFile,fn);
644 ofn.nMaxFile = sizeof(openfilestring);
645 ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0";
646 ofn.nFilterIndex = 1;
647 ofn.lpstrFileTitle = NULL;
648 ofn.nMaxFileTitle = 0;
649 ofn.lpstrInitialDir = NULL;
650 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
652 // Display the Open dialog box.
654 pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile);
655 r = GetOpenFileName(&ofn);
656 if (r)
657 {
658 pclog("GetOpenFileName return true\n");
659 return 0;
660 }
661 pclog("GetOpenFileName return false\n");
662 err = CommDlgExtendedError();
663 pclog("CommDlgExtendedError return %04X\n", err);
664 return 1;
665 }
667 int getsfile(HWND hwnd, char *f, char *fn)
668 {
669 OPENFILENAME ofn; // common dialog box structure
670 BOOL r;
671 DWORD err;
673 // Initialize OPENFILENAME
674 ZeroMemory(&ofn, sizeof(ofn));
675 ofn.lStructSize = sizeof(ofn);
676 ofn.hwndOwner = hwnd;
677 ofn.lpstrFile = openfilestring;
678 //
679 // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
680 // use the contents of szFile to initialize itself.
681 //
682 // ofn.lpstrFile[0] = '\0';
683 strcpy(ofn.lpstrFile,fn);
684 ofn.nMaxFile = sizeof(openfilestring);
685 ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0";
686 ofn.nFilterIndex = 1;
687 ofn.lpstrFileTitle = NULL;
688 ofn.nMaxFileTitle = 0;
689 ofn.lpstrInitialDir = NULL;
690 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
692 // Display the Open dialog box.
694 pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile);
695 r = GetSaveFileName(&ofn);
696 if (r)
697 {
698 pclog("GetSaveFileName return true\n");
699 return 0;
700 }
701 pclog("GetSaveFileName return false\n");
702 err = CommDlgExtendedError();
703 pclog("CommDlgExtendedError return %04X\n", err);
704 return 1;
705 }
710 HHOOK hKeyboardHook;
712 LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
713 {
714 if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen))
715 return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam);
717 KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
719 if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab
720 if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab
721 if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys
722 if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape
723 BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed
724 if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape
726 return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam );
727 }
729 LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
730 {
731 HMENU hmenu;
732 RECT rect;
733 // pclog("Message %i %08X\n",message,message);
734 switch (message)
735 {
736 case WM_CREATE:
737 SetTimer(hwnd, TIMER_1SEC, 1000, NULL);
738 hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
739 break;
741 case WM_COMMAND:
742 // pclog("WM_COMMAND %i\n",LOWORD(wParam));
743 hmenu=GetMenu(hwnd);
744 switch (LOWORD(wParam))
745 {
746 case IDM_FILE_RESET:
747 pause=1;
748 Sleep(100);
749 resetpc();
750 pause=0;
751 break;
752 case IDM_FILE_HRESET:
753 pause=1;
754 Sleep(100);
755 resetpchard();
756 pause=0;
757 break;
758 case IDM_FILE_EXIT:
759 PostQuitMessage (0); /* send a WM_QUIT to the message queue */
760 break;
761 case IDM_DISC_A:
762 if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[0]))
763 {
764 savedisc(0);
765 loaddisc(0,openfilestring);
766 saveconfig();
767 }
768 break;
769 case IDM_DISC_B:
770 if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[1]))
771 {
772 savedisc(1);
773 loaddisc(1,openfilestring);
774 saveconfig();
775 }
776 break;
777 case IDM_EJECT_A:
778 savedisc(0);
779 ejectdisc(0);
780 saveconfig();
781 break;
782 case IDM_EJECT_B:
783 savedisc(1);
784 ejectdisc(1);
785 saveconfig();
786 break;
787 case IDM_HDCONF:
788 hdconf_open(hwnd);
789 break;
790 case IDM_CONFIG:
791 config_open(hwnd);
792 break;
793 case IDM_STATUS:
794 status_open(hwnd);
795 break;
797 case IDM_VID_RESIZE:
798 vid_resize=!vid_resize;
799 CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED);
800 if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE);
801 else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE);
802 GetWindowRect(hwnd,&rect);
803 SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED);
804 saveconfig();
805 break;
807 case IDM_VID_DDRAW: case IDM_VID_D3D:
808 startblit();
809 CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED);
810 vid_apis[0][vid_api].close();
811 vid_api = LOWORD(wParam) - IDM_VID_DDRAW;
812 CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED);
813 vid_apis[0][vid_api].init(ghwnd);
814 endblit();
815 saveconfig();
816 device_force_redraw();
817 break;
819 case IDM_VID_FULLSCREEN:
820 if (video_fullscreen_first)
821 {
822 video_fullscreen_first = 0;
823 MessageBox(hwnd, "Use CTRL + ALT + PAGE DOWN to return to windowed mode", "PCem", MB_OK);
824 }
825 startblit();
826 mouse_close();
827 vid_apis[0][vid_api].close();
828 video_fullscreen = 1;
829 vid_apis[1][vid_api].init(ghwnd);
830 mouse_init();
831 endblit();
832 device_force_redraw();
833 break;
835 case IDM_VID_FS_FULL:
836 case IDM_VID_FS_43:
837 case IDM_VID_FS_SQ:
838 case IDM_VID_FS_INT:
839 CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED);
840 video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL;
841 CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED);
842 saveconfig();
843 break;
845 case IDM_CONFIG_LOAD:
846 pause = 1;
847 if (!getfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", ""))
848 {
849 if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) == IDOK)
850 {
851 loadconfig(openfilestring);
852 config_save(config_file_default);
853 mem_resize();
854 loadbios();
855 resetpchard();
856 }
857 }
858 pause = 0;
859 break;
861 case IDM_CONFIG_SAVE:
862 pause = 1;
863 if (!getsfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", ""))
864 config_save(openfilestring);
865 pause = 0;
866 break;
868 case IDM_CDROM_DISABLED:
869 if (cdrom_enabled)
870 {
871 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
872 break;
873 }
874 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
875 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED);
876 CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED);
877 if (cdrom_enabled)
878 {
879 pause = 1;
880 Sleep(100);
881 cdrom_enabled = 0;
882 saveconfig();
883 resetpchard();
884 pause = 0;
885 }
886 break;
888 case IDM_CDROM_EMPTY:
889 if (!cdrom_enabled)
890 {
891 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
892 break;
893 }
894 atapi->exit();
895 ioctl_open(0);
896 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
897 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED);
898 cdrom_drive=0;
899 CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED);
900 saveconfig();
901 if (!cdrom_enabled)
902 {
903 pause = 1;
904 Sleep(100);
905 cdrom_enabled = 1;
906 saveconfig();
907 resetpchard();
908 pause = 0;
909 }
910 break;
911 default:
912 if (LOWORD(wParam)>=IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100))
913 {
914 if (!cdrom_enabled)
915 {
916 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
917 break;
918 }
919 atapi->exit();
920 ioctl_open(LOWORD(wParam)-IDM_CDROM_REAL);
921 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
922 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED);
923 cdrom_drive = LOWORD(wParam) - IDM_CDROM_REAL;
924 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED);
925 saveconfig();
926 if (!cdrom_enabled)
927 {
928 pause = 1;
929 Sleep(100);
930 cdrom_enabled = 1;
931 saveconfig();
932 resetpchard();
933 pause = 0;
934 }
935 }
936 break;
937 }
938 return 0;
940 case WM_INPUT:
941 {
942 UINT size;
943 RAWINPUT *raw;
945 if (!infocus)
946 break;
948 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
950 raw = malloc(size);
952 /* Here we read the raw input data for the keyboard */
953 GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER));
955 /* If the input is keyboard, we process it */
956 if (raw->header.dwType == RIM_TYPEKEYBOARD)
957 {
958 const RAWKEYBOARD rawKB = raw->data.keyboard;
959 USHORT scancode = rawKB.MakeCode;
961 // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e);
963 if (rawKB.VKey == VK_NUMLOCK)
964 {
965 /* This is for proper handling of Pause/Break and Num Lock */
966 scancode = (MapVirtualKey(rawKB.VKey, MAPVK_VK_TO_VSC) | 0x100);
967 }
968 /* If it's not a scan code that starts with 0xE1 */
969 if (!(rawKB.Flags & RI_KEY_E1))
970 {
971 if (rawKB.Flags & RI_KEY_E0)
972 scancode |= (0xE0 << 8);
974 /* Remap it according to the list from the Registry */
975 scancode = scancode_map[scancode];
977 if ((scancode >> 8) == 0xF0)
978 scancode |= 0x100; /* Extended key code in disambiguated format */
979 else if ((scancode >> 8) == 0xE0)
980 scancode |= 0x80; /* Normal extended key code */
982 /* If it's not 0 (therefore not 0xE1, 0xE2, etc),
983 then pass it on to the rawinputkey array */
984 if (!(scancode & 0xf00))
985 rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK);
986 }
987 }
988 free(raw);
990 }
991 break;
993 case WM_SETFOCUS:
994 infocus=1;
995 // QueryPerformanceCounter(&counter_posold);
996 // pclog("Set focus!\n");
997 break;
998 case WM_KILLFOCUS:
999 infocus=0;
1000 if (mousecapture)
1002 ClipCursor(&oldclip);
1003 ShowCursor(TRUE);
1004 mousecapture=0;
1006 // pclog("Lost focus!\n");
1007 memset(rawinputkey, 0, sizeof(rawinputkey));
1008 break;
1010 case WM_LBUTTONUP:
1011 if (!mousecapture && !video_fullscreen)
1013 RECT pcclip;
1015 GetClipCursor(&oldclip);
1016 GetWindowRect(hwnd, &pcclip);
1017 pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1018 pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1019 pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10;
1020 pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1021 ClipCursor(&pcclip);
1022 mousecapture = 1;
1023 ShowCursor(FALSE);
1025 break;
1027 case WM_MBUTTONUP:
1028 releasemouse();
1029 break;
1031 case WM_ENTERMENULOOP:
1032 // if (key[KEY_ALT] || key[KEY_ALTGR]) return 0;
1033 break;
1035 case WM_SIZE:
1036 winsizex=lParam&0xFFFF;
1037 winsizey=lParam>>16;
1039 if (vid_apis[video_fullscreen][vid_api].resize)
1041 startblit();
1042 vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey);
1043 endblit();
1046 if (mousecapture)
1048 RECT pcclip;
1050 GetWindowRect(hwnd, &pcclip);
1051 pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1052 pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1053 pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10;
1054 pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
1055 ClipCursor(&pcclip);
1057 break;
1059 case WM_TIMER:
1060 if (wParam == TIMER_1SEC)
1061 onesec();
1062 break;
1064 case WM_RESETD3D:
1065 startblit();
1066 if (video_fullscreen)
1067 d3d_fs_reset();
1068 else
1069 d3d_reset();
1070 endblit();
1071 break;
1073 case WM_LEAVEFULLSCREEN:
1074 startblit();
1075 mouse_close();
1076 vid_apis[1][vid_api].close();
1077 video_fullscreen = 0;
1078 vid_apis[0][vid_api].init(ghwnd);
1079 mouse_init();
1080 endblit();
1081 device_force_redraw();
1082 break;
1084 case WM_KEYDOWN:
1085 case WM_SYSKEYDOWN:
1086 case WM_KEYUP:
1087 case WM_SYSKEYUP:
1088 // if (mousecapture)
1089 return 0;
1090 // return DefWindowProc (hwnd, message, wParam, lParam);
1093 case WM_DESTROY:
1094 UnhookWindowsHookEx( hKeyboardHook );
1095 KillTimer(hwnd, TIMER_1SEC);
1096 PostQuitMessage (0); /* send a WM_QUIT to the message queue */
1097 break;
1099 case WM_SYSCOMMAND:
1100 if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture))
1101 return 0; /*disable ALT key for menu*/
1103 default:
1104 // pclog("Def %08X %i\n",message,message);
1105 return DefWindowProc (hwnd, message, wParam, lParam);
1107 return 0;
1110 LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1112 switch (message)
1114 default:
1115 return DefWindowProc(hwnd, message, wParam, lParam);
1117 return 0;