PCem

view src/win.c @ 154:d0d530adce12

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