PCem

view src/win.c @ 124:457f666b38c1

Keyboard now uses raw input. Should fix international keyboard. Based on patch from Battler.
author TomW
date Fri Jul 11 20:35:37 2014 +0100
parents e4da69090d05
children aa5d4fdaceb6
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 "video.h"
18 #include "resources.h"
19 #include "cpu.h"
20 #include "ide.h"
21 #include "model.h"
22 #include "nvr.h"
23 #include "sound.h"
25 #include "plat-midi.h"
26 #include "plat-keyboard.h"
28 #include "win.h"
29 #include "win-ddraw.h"
30 #include "win-ddraw-fs.h"
31 #include "win-d3d.h"
32 #include "win-d3d-fs.h"
33 //#include "win-opengl.h"
35 #ifndef MAPVK_VK_TO_VSC
36 #define MAPVK_VK_TO_VSC 0
37 #endif
39 uint64_t timer_freq;
41 static RAWINPUTDEVICE device;
42 static uint16_t scancode_map[65536];
44 static struct
45 {
46 void (*init)(HWND h);
47 void (*close)();
48 void (*resize)(int x, int y);
49 } vid_apis[2][2] =
50 {
51 {
52 ddraw_init, ddraw_close, NULL,
53 d3d_init, d3d_close, d3d_resize
54 },
55 {
56 ddraw_fs_init, ddraw_fs_close, NULL,
57 d3d_fs_init, d3d_fs_close, NULL
58 },
59 };
61 #define TIMER_1SEC 1
63 int winsizex=640,winsizey=480;
64 int gfx_present[GFX_MAX];
65 #undef cs
66 CRITICAL_SECTION cs;
68 HANDLE mainthreadh;
70 int infocus=1;
72 int drawits=0;
74 int romspresent[ROM_MAX];
75 int quited=0;
77 RECT oldclip;
78 int mousecapture=0;
80 /* Declare Windows procedure */
81 LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
82 LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
84 HWND ghwnd;
86 HINSTANCE hinstance;
88 HMENU menu;
90 extern int updatestatus;
92 int pause=0;
94 static int win_doresize = 0;
96 static int leave_fullscreen_flag = 0;
98 void updatewindowsize(int x, int y)
99 {
100 RECT r;
101 if (vid_resize) return;
103 winsizex=x; winsizey=y;
104 win_doresize = 1;
105 }
107 void releasemouse()
108 {
109 if (mousecapture)
110 {
111 ClipCursor(&oldclip);
112 ShowCursor(TRUE);
113 mousecapture = 0;
114 }
115 }
117 void startblit()
118 {
119 EnterCriticalSection(&cs);
120 }
122 void endblit()
123 {
124 LeaveCriticalSection(&cs);
125 }
127 void leave_fullscreen()
128 {
129 leave_fullscreen_flag = 1;
130 }
132 void mainthread(LPVOID param)
133 {
134 int t = 0;
135 int frames = 0;
136 DWORD old_time, new_time;
138 // Sleep(500);
139 drawits=0;
140 old_time = GetTickCount();
141 while (!quited)
142 {
143 if (updatestatus)
144 {
145 updatestatus = 0;
146 if (status_is_open)
147 SendMessage(status_hwnd, WM_USER, 0, 0);
148 }
149 new_time = GetTickCount();
150 drawits += new_time - old_time;
151 old_time = new_time;
152 if (drawits > 0 && !pause)
153 {
154 drawits-=10; if (drawits>50) drawits=0;
155 runpc();
156 frames++;
157 if (frames >= 200 && nvr_dosave)
158 {
159 frames = 0;
160 nvr_dosave = 0;
161 savenvr();
162 }
163 }
164 else
165 Sleep(1);
167 if (!video_fullscreen && win_doresize)
168 {
169 RECT r;
170 GetWindowRect(ghwnd, &r);
171 MoveWindow(ghwnd, r.left, r.top,
172 winsizex + (GetSystemMetrics(SM_CXFIXEDFRAME) * 2),
173 winsizey + (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 1,
174 TRUE);
175 win_doresize = 0;
176 }
178 if (leave_fullscreen_flag)
179 {
180 leave_fullscreen_flag = 0;
181 SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0);
182 }
183 }
184 }
186 static void initmenu(void)
187 {
188 int c;
189 HMENU m;
190 char s[32];
191 m=GetSubMenu(menu,2); /*Settings*/
192 m=GetSubMenu(m,1); /*CD-ROM*/
194 /* Loop through each Windows drive letter and test to see if
195 it's a CDROM */
196 for (c='A';c<='Z';c++)
197 {
198 sprintf(s,"%c:\\",c);
199 if (GetDriveType(s)==DRIVE_CDROM)
200 {
201 sprintf(s, "Host CD/DVD Drive (%c:)", c);
202 AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s);
203 }
204 }
205 }
207 void get_executable_name(char *s, int size)
208 {
209 GetModuleFileName(hinstance, s, size);
210 }
212 void set_window_title(char *s)
213 {
214 if (video_fullscreen)
215 return;
216 SetWindowText(ghwnd, s);
217 }
219 uint64_t timer_read()
220 {
221 LARGE_INTEGER qpc_time;
222 QueryPerformanceCounter(&qpc_time);
223 return qpc_time.QuadPart;
224 }
226 /* This is so we can disambiguate scan codes that would otherwise conflict and get
227 passed on incorrectly. */
228 UINT16 convert_scan_code(UINT16 scan_code)
229 {
230 switch (scan_code)
231 {
232 case 0xE001:
233 return 0xF001;
234 case 0xE002:
235 return 0xF002;
236 case 0xE005:
237 return 0xF005;
238 case 0xE006:
239 return 0xF006;
240 case 0xE007:
241 return 0xF007;
242 case 0xE071:
243 return 0xF008;
244 case 0xE072:
245 return 0xF009;
246 case 0xE07F:
247 return 0xF00A;
248 case 0xE0E1:
249 return 0xF00B;
250 case 0xE0EE:
251 return 0xF00C;
252 case 0xE0F1:
253 return 0xF00D;
254 case 0xE0FE:
255 return 0xF00E;
256 case 0xE0EF:
257 return 0xF00F;
259 default:
260 return scan_code;
261 }
262 }
264 void get_registry_key_map()
265 {
266 char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout";
267 char *valueName = "Scancode Map";
268 char buf[32768];
269 DWORD bufSize;
270 HKEY hKey;
271 int j;
273 /* First, prepare the default scan code map list which is 1:1.
274 Remappings will be inserted directly into it.
275 65536 bytes so scan codes fit in easily and it's easy to find what each maps too,
276 since each array element is a scan code and provides for E0, etc. ones too. */
277 for (j = 0; j < 65536; j++)
278 scancode_map[j] = convert_scan_code(j);
280 bufSize = 32768;
281 pclog("Preparing scan code map list...\n");
282 /* Get the scan code remappings from:
283 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */
284 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS)
285 {
286 if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS)
287 {
288 UINT32 *bufEx2 = (UINT32 *) buf;
289 int scMapCount = bufEx2[2];
290 pclog("%lu scan code mappings found!\n", scMapCount);
291 if ((bufSize != 0) && (scMapCount != 0))
292 {
293 UINT16 *bufEx = (UINT16 *) (buf + 12);
294 pclog("More than zero scan code mappings found, processing...\n");
295 for (j = 0; j < scMapCount*2; j += 2)
296 {
297 /* Each scan code is 32-bit: 16 bits of remapped scan code,
298 and 16 bits of original scan code. */
299 int scancode_unmapped = bufEx[j + 1];
300 int scancode_mapped = bufEx[j];
302 scancode_mapped = convert_scan_code(scancode_mapped);
304 scancode_map[scancode_unmapped] = scancode_mapped;
305 pclog("Scan code mapping %u detected: %X -> %X\n", scancode_unmapped, scancode_mapped, scancode_map[scancode_unmapped]);
306 }
307 pclog("Done processing!\n");
308 }
309 }
310 RegCloseKey(hKey);
311 }
312 pclog("Done preparing!\n");
313 }
315 int WINAPI WinMain (HINSTANCE hThisInstance,
316 HINSTANCE hPrevInstance,
317 LPSTR lpszArgument,
318 int nFunsterStil)
320 {
321 HWND hwnd; /* This is the handle for our window */
322 MSG messages; /* Here messages to the application are saved */
323 WNDCLASSEX wincl; /* Data structure for the windowclass */
324 int c, d;
325 LARGE_INTEGER qpc_freq;
327 hinstance=hThisInstance;
328 /* The Window structure */
329 wincl.hInstance = hThisInstance;
330 wincl.lpszClassName = szClassName;
331 wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
332 wincl.style = CS_DBLCLKS; /* Catch double-clicks */
333 wincl.cbSize = sizeof (WNDCLASSEX);
335 /* Use default icon and mouse-pointer */
336 wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
337 wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
338 wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW);
339 wincl.lpszMenuName = NULL; /* No menu */
340 wincl.cbClsExtra = 0; /* No extra bytes after the window class */
341 wincl.cbWndExtra = 0; /* structure or the window instance */
342 /* Use Windows's default color as the background of the window */
343 wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
345 /* Register the window class, and if it fails quit the program */
346 if (!RegisterClassEx(&wincl))
347 return 0;
349 wincl.lpszClassName = szSubClassName;
350 wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */
352 if (!RegisterClassEx(&wincl))
353 return 0;
355 menu = LoadMenu(hThisInstance, TEXT("MainMenu"));
356 initmenu();
358 /* The class is registered, let's create the program*/
359 hwnd = CreateWindowEx (
360 0, /* Extended possibilites for variation */
361 szClassName, /* Classname */
362 "PCem v8.1", /* Title Text */
363 WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */
364 CW_USEDEFAULT, /* Windows decides the position */
365 CW_USEDEFAULT, /* where the window ends up on the screen */
366 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */
367 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */
368 HWND_DESKTOP, /* The window is a child-window to desktop */
369 menu, /* Menu */
370 hThisInstance, /* Program Instance handler */
371 NULL /* No Window Creation data */
372 );
374 /* Make the window visible on the screen */
375 ShowWindow (hwnd, nFunsterStil);
377 // win_set_window(hwnd);
379 memset(rawinputkey, 0, sizeof(rawinputkey));
380 device.usUsagePage = 0x01;
381 device.usUsage = 0x06;
382 device.dwFlags = RIDEV_NOLEGACY;
383 device.hwndTarget = hwnd;
385 if (RegisterRawInputDevices(&device, 1, sizeof(device)))
386 pclog("Raw input registered!\n");
387 else
388 pclog("Raw input registration failed!\n");
390 get_registry_key_map();
392 ghwnd=hwnd;
394 midi_init();
395 atexit(midi_close);
397 initpc();
399 vid_apis[0][vid_api].init(ghwnd);
401 if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE);
402 else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE);
404 if (!cdrom_enabled)
405 CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED);
406 else
407 CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED);
408 if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED);
409 CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED);
410 CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED);
411 // set_display_switch_mode(SWITCH_BACKGROUND);
413 d=romset;
414 for (c=0;c<ROM_MAX;c++)
415 {
416 romset=c;
417 romspresent[c]=loadbios();
418 pclog("romset %i - %i\n", c, romspresent[c]);
419 }
421 for (c = 0; c < ROM_MAX; c++)
422 {
423 if (romspresent[c])
424 break;
425 }
426 if (c == ROM_MAX)
427 {
428 MessageBox(hwnd,"No ROMs present!\nYou must have at least one romset to use PCem.","PCem fatal error",MB_OK);
429 return 0;
430 }
432 romset=d;
433 c=loadbios();
435 if (!c)
436 {
437 if (romset!=-1) MessageBox(hwnd,"Configured romset not available.\nDefaulting to available romset.","PCem error",MB_OK);
438 for (c=0;c<ROM_MAX;c++)
439 {
440 if (romspresent[c])
441 {
442 romset = c;
443 model = model_getmodel(romset);
444 saveconfig();
445 resetpchard();
446 break;
447 }
448 }
449 }
452 for (c = 0; c < GFX_MAX; c++)
453 gfx_present[c] = video_card_available(video_old_to_new(c));
455 if (!video_card_available(video_old_to_new(gfxcard)))
456 {
457 if (romset!=-1) MessageBox(hwnd,"Configured video BIOS not available.\nDefaulting to available romset.","PCem error",MB_OK);
458 for (c = GFX_MAX-1; c >= 0; c--)
459 {
460 if (gfx_present[c])
461 {
462 gfxcard = c;
463 saveconfig();
464 resetpchard();
465 break;
466 }
467 }
468 }
470 loadbios();
472 timeBeginPeriod(1);
474 atexit(releasemouse);
476 // QueryPerformanceFrequency(&counter_base);
477 /// QueryPerformanceCounter(&counter_posold);
478 // counter_posold.QuadPart*=100;
480 InitializeCriticalSection(&cs);
481 mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL);
482 SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST);
485 updatewindowsize(640, 480);
487 QueryPerformanceFrequency(&qpc_freq);
488 timer_freq = qpc_freq.QuadPart;
490 // focus=1;
491 // setrefresh(100);
493 // ShowCursor(TRUE);
495 /* Run the message loop. It will run until GetMessage() returns 0 */
496 while (!quited)
497 {
498 /* if (infocus)
499 {
500 if (drawits)
501 {
502 drawits--;
503 if (drawits>10) drawits=0;
504 runpc();
505 }
506 //; else
507 // sleep(0);
508 if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture)
509 {
510 ClipCursor(&oldclip);
511 mousecapture=0;
512 }
513 }*/
515 while (GetMessage(&messages,NULL,0,0) && !quited)
516 {
517 if (messages.message==WM_QUIT) quited=1;
518 TranslateMessage(&messages);
519 DispatchMessage(&messages);
520 if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture)
521 {
522 ClipCursor(&oldclip);
523 ShowCursor(TRUE);
524 mousecapture=0;
525 }
526 }
528 quited=1;
529 // else
530 // sleep(10);
531 }
533 startblit();
534 // pclog("Sleep 1000\n");
535 Sleep(200);
536 // pclog("TerminateThread\n");
537 TerminateThread(mainthreadh,0);
538 // pclog("Quited? %i\n",quited);
539 // pclog("Closepc\n");
540 closepc();
541 // pclog("dumpregs\n");
543 vid_apis[video_fullscreen][vid_api].close();
545 timeEndPeriod(1);
546 // dumpregs();
547 if (mousecapture)
548 {
549 ClipCursor(&oldclip);
550 ShowCursor(TRUE);
551 }
553 UnregisterClass(szSubClassName, hinstance);
554 UnregisterClass(szClassName, hinstance);
556 // pclog("Ending! %i %i\n",messages.wParam,quited);
557 return messages.wParam;
558 }
560 char openfilestring[260];
561 int getfile(HWND hwnd, char *f, char *fn)
562 {
563 OPENFILENAME ofn; // common dialog box structure
564 BOOL r;
565 DWORD err;
567 // Initialize OPENFILENAME
568 ZeroMemory(&ofn, sizeof(ofn));
569 ofn.lStructSize = sizeof(ofn);
570 ofn.hwndOwner = hwnd;
571 ofn.lpstrFile = openfilestring;
572 //
573 // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
574 // use the contents of szFile to initialize itself.
575 //
576 // ofn.lpstrFile[0] = '\0';
577 strcpy(ofn.lpstrFile,fn);
578 ofn.nMaxFile = sizeof(openfilestring);
579 ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0";
580 ofn.nFilterIndex = 1;
581 ofn.lpstrFileTitle = NULL;
582 ofn.nMaxFileTitle = 0;
583 ofn.lpstrInitialDir = NULL;
584 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
586 // Display the Open dialog box.
588 pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile);
589 r = GetOpenFileName(&ofn);
590 if (r)
591 {
592 pclog("GetOpenFileName return true\n");
593 return 0;
594 }
595 pclog("GetOpenFileName return false\n");
596 err = CommDlgExtendedError();
597 pclog("CommDlgExtendedError return %04X\n", err);
598 return 1;
599 }
601 int getsfile(HWND hwnd, char *f, char *fn)
602 {
603 OPENFILENAME ofn; // common dialog box structure
604 BOOL r;
605 DWORD err;
607 // Initialize OPENFILENAME
608 ZeroMemory(&ofn, sizeof(ofn));
609 ofn.lStructSize = sizeof(ofn);
610 ofn.hwndOwner = hwnd;
611 ofn.lpstrFile = openfilestring;
612 //
613 // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
614 // use the contents of szFile to initialize itself.
615 //
616 // ofn.lpstrFile[0] = '\0';
617 strcpy(ofn.lpstrFile,fn);
618 ofn.nMaxFile = sizeof(openfilestring);
619 ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0";
620 ofn.nFilterIndex = 1;
621 ofn.lpstrFileTitle = NULL;
622 ofn.nMaxFileTitle = 0;
623 ofn.lpstrInitialDir = NULL;
624 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
626 // Display the Open dialog box.
628 pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile);
629 r = GetSaveFileName(&ofn);
630 if (r)
631 {
632 pclog("GetSaveFileName return true\n");
633 return 0;
634 }
635 pclog("GetSaveFileName return false\n");
636 err = CommDlgExtendedError();
637 pclog("CommDlgExtendedError return %04X\n", err);
638 return 1;
639 }
644 HHOOK hKeyboardHook;
646 LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
647 {
648 if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen))
649 return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam);
651 KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
653 if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab
654 if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab
655 if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys
656 if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape
657 BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed
658 if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape
660 return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam );
661 }
663 LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
664 {
665 HMENU hmenu;
666 RECT rect;
667 // pclog("Message %i %08X\n",message,message);
668 switch (message)
669 {
670 case WM_CREATE:
671 SetTimer(hwnd, TIMER_1SEC, 1000, NULL);
672 hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
673 break;
675 case WM_COMMAND:
676 // pclog("WM_COMMAND %i\n",LOWORD(wParam));
677 hmenu=GetMenu(hwnd);
678 switch (LOWORD(wParam))
679 {
680 case IDM_FILE_RESET:
681 pause=1;
682 Sleep(100);
683 resetpc();
684 pause=0;
685 break;
686 case IDM_FILE_HRESET:
687 pause=1;
688 Sleep(100);
689 resetpchard();
690 pause=0;
691 break;
692 case IDM_FILE_EXIT:
693 PostQuitMessage (0); /* send a WM_QUIT to the message queue */
694 break;
695 case IDM_DISC_A:
696 if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[0]))
697 {
698 savedisc(0);
699 loaddisc(0,openfilestring);
700 saveconfig();
701 }
702 break;
703 case IDM_DISC_B:
704 if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[1]))
705 {
706 savedisc(1);
707 loaddisc(1,openfilestring);
708 saveconfig();
709 }
710 break;
711 case IDM_EJECT_A:
712 savedisc(0);
713 ejectdisc(0);
714 saveconfig();
715 break;
716 case IDM_EJECT_B:
717 savedisc(1);
718 ejectdisc(1);
719 saveconfig();
720 break;
721 case IDM_HDCONF:
722 hdconf_open(hwnd);
723 break;
724 case IDM_CONFIG:
725 config_open(hwnd);
726 break;
727 case IDM_STATUS:
728 status_open(hwnd);
729 break;
731 case IDM_VID_RESIZE:
732 vid_resize=!vid_resize;
733 CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED);
734 if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE);
735 else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE);
736 GetWindowRect(hwnd,&rect);
737 SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED);
738 saveconfig();
739 break;
741 case IDM_VID_DDRAW: case IDM_VID_D3D:
742 startblit();
743 CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED);
744 vid_apis[0][vid_api].close();
745 vid_api = LOWORD(wParam) - IDM_VID_DDRAW;
746 CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED);
747 vid_apis[0][vid_api].init(ghwnd);
748 endblit();
749 saveconfig();
750 device_force_redraw();
751 break;
753 case IDM_VID_FULLSCREEN:
754 if (video_fullscreen_first)
755 {
756 video_fullscreen_first = 0;
757 MessageBox(hwnd, "Use CTRL + ALT + PAGE DOWN to return to windowed mode", "PCem", MB_OK);
758 }
759 startblit();
760 mouse_close();
761 vid_apis[0][vid_api].close();
762 video_fullscreen = 1;
763 vid_apis[1][vid_api].init(ghwnd);
764 mouse_init();
765 endblit();
766 device_force_redraw();
767 break;
769 case IDM_VID_FS_FULL:
770 case IDM_VID_FS_43:
771 case IDM_VID_FS_SQ:
772 case IDM_VID_FS_INT:
773 CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED);
774 video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL;
775 CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED);
776 saveconfig();
777 break;
779 case IDM_CDROM_DISABLED:
780 if (cdrom_enabled)
781 {
782 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
783 break;
784 }
785 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
786 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED);
787 CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED);
788 if (cdrom_enabled)
789 {
790 cdrom_enabled = 0;
791 saveconfig();
792 resetpchard();
793 }
794 break;
796 case IDM_CDROM_EMPTY:
797 if (!cdrom_enabled)
798 {
799 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
800 break;
801 }
802 atapi->exit();
803 ioctl_open(0);
804 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
805 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED);
806 cdrom_drive=0;
807 CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED);
808 saveconfig();
809 if (!cdrom_enabled)
810 {
811 cdrom_enabled = 1;
812 saveconfig();
813 resetpchard();
814 }
815 break;
816 default:
817 if (LOWORD(wParam)>=IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100))
818 {
819 if (!cdrom_enabled)
820 {
821 if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK)
822 break;
823 }
824 atapi->exit();
825 ioctl_open(LOWORD(wParam)-IDM_CDROM_REAL);
826 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED);
827 CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED);
828 cdrom_drive = LOWORD(wParam) - IDM_CDROM_REAL;
829 CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED);
830 saveconfig();
831 if (!cdrom_enabled)
832 {
833 cdrom_enabled = 1;
834 saveconfig();
835 resetpchard();
836 }
837 }
838 break;
839 }
840 return 0;
842 case WM_INPUT:
843 {
844 UINT size;
845 RAWINPUT *raw;
847 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
849 raw = malloc(size);
851 /* Here we read the raw input data for the keyboard */
852 GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER));
854 /* If the input is keyboard, we process it */
855 if (raw->header.dwType == RIM_TYPEKEYBOARD)
856 {
857 const RAWKEYBOARD rawKB = raw->data.keyboard;
858 USHORT scancode = rawKB.MakeCode;
860 // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e);
862 if (rawKB.VKey == VK_NUMLOCK)
863 {
864 /* This is for proper handling of Pause/Break and Num Lock */
865 scancode = (MapVirtualKey(rawKB.VKey, MAPVK_VK_TO_VSC) | 0x100);
866 }
867 /* If it's not a scan code that starts with 0xE1 */
868 if (!(rawKB.Flags & RI_KEY_E1))
869 {
870 if (rawKB.Flags & RI_KEY_E0)
871 scancode |= (0xE0 << 8);
873 /* Remap it according to the list from the Registry */
874 scancode = scancode_map[scancode];
876 if ((scancode >> 8) == 0xF0)
877 scancode |= 0x100; /* Extended key code in disambiguated format */
878 else if ((scancode >> 8) == 0xE0)
879 scancode |= 0x80; /* Normal extended key code */
881 /* If it's not 0 (therefore not 0xE1, 0xE2, etc),
882 then pass it on to the rawinputkey array */
883 if (!(scancode & 0xf00))
884 rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK);
885 }
886 }
887 free(raw);
889 }
890 break;
892 case WM_SETFOCUS:
893 infocus=1;
894 // QueryPerformanceCounter(&counter_posold);
895 // pclog("Set focus!\n");
896 break;
897 case WM_KILLFOCUS:
898 infocus=0;
899 if (mousecapture)
900 {
901 ClipCursor(&oldclip);
902 ShowCursor(TRUE);
903 mousecapture=0;
904 }
905 // pclog("Lost focus!\n");
906 break;
908 case WM_LBUTTONUP:
909 if (!mousecapture && !video_fullscreen)
910 {
911 RECT pcclip;
913 GetClipCursor(&oldclip);
914 GetWindowRect(hwnd, &pcclip);
915 pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
916 pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
917 pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10;
918 pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
919 ClipCursor(&pcclip);
920 mousecapture = 1;
921 ShowCursor(FALSE);
922 }
923 break;
925 case WM_MBUTTONUP:
926 releasemouse();
927 break;
929 case WM_ENTERMENULOOP:
930 // if (key[KEY_ALT] || key[KEY_ALTGR]) return 0;
931 break;
933 case WM_SIZE:
934 winsizex=lParam&0xFFFF;
935 winsizey=lParam>>16;
937 if (vid_apis[video_fullscreen][vid_api].resize)
938 {
939 startblit();
940 vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey);
941 endblit();
942 }
944 if (mousecapture)
945 {
946 RECT pcclip;
948 GetWindowRect(hwnd, &pcclip);
949 pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
950 pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
951 pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10;
952 pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10;
953 ClipCursor(&pcclip);
954 }
955 break;
957 case WM_TIMER:
958 if (wParam == TIMER_1SEC)
959 onesec();
960 break;
962 case WM_RESETD3D:
963 startblit();
964 if (video_fullscreen)
965 d3d_fs_reset();
966 else
967 d3d_reset();
968 endblit();
969 break;
971 case WM_LEAVEFULLSCREEN:
972 startblit();
973 mouse_close();
974 vid_apis[1][vid_api].close();
975 video_fullscreen = 0;
976 vid_apis[0][vid_api].init(ghwnd);
977 mouse_init();
978 endblit();
979 device_force_redraw();
980 break;
982 case WM_KEYDOWN:
983 case WM_SYSKEYDOWN:
984 case WM_KEYUP:
985 case WM_SYSKEYUP:
986 // if (mousecapture)
987 return 0;
988 // return DefWindowProc (hwnd, message, wParam, lParam);
991 case WM_DESTROY:
992 UnhookWindowsHookEx( hKeyboardHook );
993 KillTimer(hwnd, TIMER_1SEC);
994 PostQuitMessage (0); /* send a WM_QUIT to the message queue */
995 break;
997 case WM_SYSCOMMAND:
998 if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture))
999 return 0; /*disable ALT key for menu*/
1001 default:
1002 // pclog("Def %08X %i\n",message,message);
1003 return DefWindowProc (hwnd, message, wParam, lParam);
1005 return 0;
1008 LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1010 switch (message)
1012 default:
1013 return DefWindowProc(hwnd, message, wParam, lParam);
1015 return 0;