25 #define WINDOW_CLASS_NAME "Quake 2 Pro"
28 #define MODE_SIZE (1 << 0)
29 #define MODE_POS (1 << 1)
30 #define MODE_STYLE (1 << 2)
31 #define MODE_REPOSITION (1 << 3)
64 style = GetWindowLong(
win.wnd, GWL_STYLE);
65 style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP | WS_DLGFRAME);
68 if (
win.flags & QVF_FULLSCREEN) {
75 after = HWND_NOTOPMOST;
77 style |= WS_OVERLAPPED;
82 style |= WS_THICKFRAME;
85 style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
87 style |= WS_THICKFRAME;
95 r.right =
win.rc.width;
96 r.bottom =
win.rc.height;
98 AdjustWindowRect(&r, style, FALSE);
103 w = r.right - r.left;
104 h = r.bottom - r.top;
107 SetWindowLong(
win.wnd, GWL_STYLE, style);
108 SetWindowPos(
win.wnd, after, x, y, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
109 UpdateWindow(
win.wnd);
110 SetForegroundWindow(
win.wnd);
113 if (
win.mouse.grabbed) {
125 #if USE_REF == REF_SOFT
134 static int modecmp(
const void *p1,
const void *p2)
136 const DEVMODE *dm1 = (
const DEVMODE *)p1;
137 const DEVMODE *dm2 = (
const DEVMODE *)p2;
138 DWORD size1 = dm1->dmPelsWidth * dm1->dmPelsHeight;
139 DWORD size2 = dm2->dmPelsWidth * dm2->dmPelsHeight;
148 if (dm1->dmDisplayFrequency < dm2->dmDisplayFrequency)
150 if (dm1->dmDisplayFrequency > dm2->dmDisplayFrequency)
159 if (~dm->dmFields & (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY))
163 if (dm->dmDisplayFlags & (DM_GRAYSCALE | DM_INTERLACED))
167 if (dm->dmDisplayFrequency == 0 || dm->dmDisplayFrequency == 1)
178 if ((compare->dmFields & DM_PELSWIDTH) && base->dmPelsWidth != compare->dmPelsWidth)
181 if ((compare->dmFields & DM_PELSHEIGHT) && base->dmPelsHeight != compare->dmPelsHeight)
184 if ((compare->dmFields & DM_BITSPERPEL) && base->dmBitsPerPel != compare->dmBitsPerPel)
187 if ((compare->dmFields & DM_DISPLAYFREQUENCY) && base->dmDisplayFrequency != compare->dmDisplayFrequency)
200 DEVMODE desktop, dm, *modes;
201 int i, j, num_modes, max_modes;
205 memset(&desktop, 0,
sizeof(desktop));
206 desktop.dmSize =
sizeof(desktop);
208 if (!EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &desktop))
209 return Z_CopyString(VID_MODELIST);
214 for (i = 0; i < 4096; i++) {
215 memset(&dm, 0,
sizeof(dm));
216 dm.dmSize =
sizeof(dm);
217 if (!EnumDisplaySettings(NULL, i, &dm))
225 if (dm.dmBitsPerPel != desktop.dmBitsPerPel)
229 for (j = 0; j < num_modes; j++)
235 if (num_modes == max_modes) {
237 modes =
Z_Realloc(modes,
sizeof(modes[0]) * max_modes);
240 modes[num_modes++] = dm;
244 return Z_CopyString(VID_MODELIST);
246 qsort(modes, num_modes,
sizeof(modes[0]),
modecmp);
248 size = 8 + num_modes * 32 + 1;
249 buf = Z_Malloc(size);
252 for (i = 0; i < num_modes; i++) {
253 len +=
Q_scnprintf(buf + len, size - len,
"%lux%lu@%lu",
254 modes[i].dmPelsWidth,
255 modes[i].dmPelsHeight,
256 modes[i].dmDisplayFrequency);
257 if (len < size - 1 && i < num_modes - 1)
272 memset(¤t, 0,
sizeof(current));
273 current.dmSize =
sizeof(current);
275 if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, ¤t))
287 memset(&desktop, 0,
sizeof(desktop));
288 desktop.dmSize =
sizeof(desktop);
290 EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &desktop);
294 Com_DPrintf(
"...setting fullscreen mode: %dx%d\n",
295 win.rc.width,
win.rc.height);
297 win.rc.width = desktop.dmPelsWidth;
298 win.rc.height = desktop.dmPelsHeight;
299 Com_DPrintf(
"...falling back to desktop mode: %dx%d\n",
300 win.rc.width,
win.rc.height);
302 Com_DPrintf(
"...falling back to default mode: %dx%d\n",
303 win.rc.width,
win.rc.height);
306 memset(&dm, 0,
sizeof(dm));
307 dm.dmSize =
sizeof(dm);
308 dm.dmPelsWidth =
win.rc.width;
309 dm.dmPelsHeight =
win.rc.height;
310 dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
313 dm.dmDisplayFrequency = freq;
314 dm.dmFields |= DM_DISPLAYFREQUENCY;
315 Com_DPrintf(
"...using display frequency of %d\n", freq);
317 dm.dmDisplayFrequency = desktop.dmDisplayFrequency;
318 dm.dmFields |= DM_DISPLAYFREQUENCY;
319 Com_DPrintf(
"...using desktop display frequency of %d\n", freq);
323 dm.dmBitsPerPel = depth;
324 dm.dmFields |= DM_BITSPERPEL;
325 Com_DPrintf(
"...using bitdepth of %d\n", depth);
327 dm.dmBitsPerPel = desktop.dmBitsPerPel;
328 dm.dmFields |= DM_BITSPERPEL;
329 Com_DPrintf(
"...using desktop bitdepth of %lu\n", desktop.dmBitsPerPel);
333 Com_DPrintf(
"...skipping CDS\n");
334 ret = DISP_CHANGE_SUCCESSFUL;
336 Com_DPrintf(
"...calling CDS: ");
337 ret = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
338 if (ret != DISP_CHANGE_SUCCESSFUL) {
339 Com_DPrintf(
"failed with error %ld\n", ret);
346 win.flags |= QVF_FULLSCREEN;
348 win.mode_changed = 0;
366 case DISP_CHANGE_SUCCESSFUL:
368 case DISP_CHANGE_FAILED:
369 Com_EPrintf(
"Display driver failed the %dx%d video mode.\n",
win.rc.width,
win.rc.height);
371 case DISP_CHANGE_BADMODE:
372 Com_EPrintf(
"Video mode %dx%d is not supported.\n",
win.rc.width,
win.rc.height);
375 Com_EPrintf(
"Video mode %dx%d failed with error %ld.\n",
win.rc.width,
win.rc.height, ret);
383 ChangeDisplaySettings(NULL, 0);
393 if (
win.rc.width < 320)
win.rc.width = 320;
394 if (
win.rc.height < 240)
win.rc.height = 240;
396 Com_DPrintf(
"...setting windowed mode: %dx%d%+d%+d\n",
399 memset(&
win.dm, 0,
sizeof(
win.dm));
400 win.flags &= ~QVF_FULLSCREEN;
402 win.mode_changed = 0;
418 if (
win.flags & QVF_GAMMARAMP) {
419 for (i = 0; i < 256; i++) {
421 win.gamma_cust[0][i] = v;
422 win.gamma_cust[1][i] = v;
423 win.gamma_cust[2][i] = v;
426 SetDeviceGammaRamp(
win.dc,
win.gamma_cust);
432 if (!
win.alttab_disabled) {
433 RegisterHotKey(0, 0, MOD_ALT, VK_TAB);
434 RegisterHotKey(0, 1, MOD_ALT, VK_RETURN);
435 win.alttab_disabled = qtrue;
441 if (
win.alttab_disabled) {
442 UnregisterHotKey(0, 0);
443 UnregisterHotKey(0, 1);
444 win.alttab_disabled = qfalse;
461 if (HIWORD(wParam)) {
463 active = ACT_MINIMIZED;
465 if (LOWORD(wParam)) {
466 active = ACT_ACTIVATED;
468 active = ACT_RESTORED;
475 if (active == ACT_ACTIVATED) {
482 if (
win.flags & QVF_GAMMARAMP) {
483 if (active == ACT_ACTIVATED) {
484 SetDeviceGammaRamp(
win.dc,
win.gamma_cust);
486 SetDeviceGammaRamp(
win.dc,
win.gamma_orig);
490 if (
win.flags & QVF_FULLSCREEN) {
491 if (active == ACT_ACTIVATED) {
492 ShowWindow(
win.wnd, SW_RESTORE);
494 ShowWindow(
win.wnd, SW_MINIMIZE);
498 if (active == ACT_ACTIVATED) {
500 ChangeDisplaySettings(&
win.dm, CDS_FULLSCREEN);
503 ChangeDisplaySettings(NULL, 0);
508 if (active == ACT_ACTIVATED) {
509 SetForegroundWindow(
win.wnd);
515 PKBDLLHOOKSTRUCT kb = (PKBDLLHOOKSTRUCT)lParam;
518 if (nCode != HC_ACTION) {
522 switch (kb->vkCode) {
545 return CallNextHookEx(NULL, nCode, wParam, lParam);
553 Com_EPrintf(
"Couldn't set low-level keyboard hook, error %#lX\n", GetLastError());
558 UnhookWindowsHookEx(
win.kbdHook);
568 0, K_ESCAPE,
'1',
'2',
'3',
'4',
'5',
'6',
569 '7',
'8',
'9',
'0',
'-',
'=', K_BACKSPACE,K_TAB,
570 'q',
'w',
'e',
'r',
't',
'y',
'u',
'i',
571 'o',
'p',
'[',
']', K_ENTER, K_LCTRL,
'a',
's',
572 'd',
'f',
'g',
'h',
'j',
'k',
'l',
';',
573 '\'',
'`', K_LSHIFT,
'\\',
'z',
'x',
'c',
'v',
574 'b',
'n',
'm',
',',
'.',
'/', K_RSHIFT, K_KP_MULTIPLY,
575 K_LALT, K_SPACE, K_CAPSLOCK, K_F1, K_F2, K_F3, K_F4, K_F5,
576 K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, K_SCROLLOCK,K_KP_HOME,
577 K_KP_UPARROW, K_KP_PGUP, K_KP_MINUS, K_KP_LEFTARROW, K_KP_5, K_KP_RIGHTARROW,K_KP_PLUS, K_KP_END,
578 K_KP_DOWNARROW, K_KP_PGDN, K_KP_INS, K_KP_DEL, 0, 0, K_102ND, K_F11,
579 K_F12, 0, 0, 0, 0, 0, 0, 0,
582 0, 0, 0, 0, 0, 0, 0, 0,
583 0, 0, 0, 0, 0, 0, 0, 0,
584 0, 0, 0, 0, 0, 0, 0, 0,
585 0, 0, 0, 0, K_KP_ENTER, K_RCTRL, 0, 0,
586 0, 0, 0, 0, 0, 0, 0, 0,
587 0, 0, 0, 0, 0, 0, 0, 0,
588 0, 0, 0, 0, 0, K_KP_SLASH, 0, K_PRINTSCREEN,
589 K_RALT, 0, 0, 0, 0, 0, 0, 0,
590 0, 0, 0, 0, 0, K_NUMLOCK, 0, K_HOME,
591 K_UPARROW, K_PGUP, 0, K_LEFTARROW, 0, K_RIGHTARROW, 0, K_END,
592 K_DOWNARROW, K_PGDN, K_INS, K_DEL, 0, 0, 0, 0,
593 0, 0, 0, K_LWINKEY, K_RWINKEY, K_MENU, 0, 0,
600 int scancode = (lParam >> 16) & 255;
601 int extended = (lParam >> 24) & 1;
610 Com_DPrintf(
"%s: unknown %sscancode %d\n",
611 __func__, extended ?
"extended " :
"", scancode);
615 if (result == K_LALT || result == K_RALT)
617 else if (result == K_LCTRL || result == K_RCTRL)
619 else if (result == K_LSHIFT || result == K_RSHIFT)
632 }
else if (delta < 0) {
639 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0);
658 }
else if (delta < 0) {
672 int i, mask, temp = 0;
674 if (wParam & MK_LBUTTON)
677 if (wParam & MK_RBUTTON)
680 if (wParam & MK_MBUTTON)
683 if (wParam & MK_XBUTTON1)
686 if (wParam & MK_XBUTTON2)
689 if (temp ==
win.mouse.state)
693 for (i = 0, mask = 1; i < MOUSE_BUTTONS; i++, mask <<= 1) {
694 if ((temp & mask) && !(
win.mouse.state & mask)) {
697 if (!(temp & mask) && (
win.mouse.state & mask)) {
702 win.mouse.state = temp;
710 if (
win.mouse.grabbed)
713 if (!GetCursorPos(&pt))
716 return PtInRect(&
win.screen_rc, pt);
719 #define BTN_DN(i) (1<<(i*2+0))
720 #define BTN_UP(i) (1<<(i*2+1))
729 for (i = 0; i < MOUSE_BUTTONS; i++) {
730 if (rm->usButtonFlags &
BTN_UP(i)) {
737 if (rm->usButtonFlags) {
739 for (i = 0; i < MOUSE_BUTTONS; i++) {
740 if (rm->usButtonFlags &
BTN_DN(i)) {
743 if (rm->usButtonFlags &
BTN_UP(i)) {
748 if (rm->usButtonFlags & RI_MOUSE_WHEEL) {
753 if (rm->usButtonFlags & 0x0800) {
758 if ((rm->usFlags & (MOUSE_MOVE_RELATIVE | MOUSE_MOVE_ABSOLUTE)) == MOUSE_MOVE_RELATIVE) {
759 win.mouse.mx += rm->lLastX;
760 win.mouse.my += rm->lLastY;
770 len =
sizeof(buffer);
771 ret = GetRawInputData(
handle, RID_INPUT, buffer, &len,
sizeof(RAWINPUTHEADER));
772 if (ret == (
UINT) - 1) {
773 Com_EPrintf(
"GetRawInputData failed with error %#lx\n", GetLastError());
777 ri = (PRAWINPUT)buffer;
778 if (ri->header.dwType == RIM_TYPEMOUSE) {
785 int w, h, nc_w, nc_h;
789 if (
win.flags & QVF_FULLSCREEN)
792 if (pos->flags & SWP_NOSIZE)
795 style = GetWindowLong(wnd, GWL_STYLE);
803 AdjustWindowRect(&rc, style, FALSE);
805 nc_w = rc.right - rc.left - 1;
806 nc_h = rc.bottom - rc.top - 1;
809 w = (pos->cx - nc_w) & ~7;
810 h = (pos->cy - nc_h) & ~1;
813 if (w < 320) w = 320;
814 if (h < 240) h = 240;
826 GetWindowRect(wnd, &rc);
831 GetClientRect(wnd, &rc);
832 win.rc.width = rc.right - rc.left;
833 win.rc.height = rc.bottom - rc.top;
836 MapWindowPoints(wnd, NULL, (POINT *)&rc, 2);
838 win.center_x = (rc.right + rc.left) / 2;
839 win.center_y = (rc.top + rc.bottom) / 2;
842 if (
win.flags & QVF_FULLSCREEN)
850 if (!(pos->flags & SWP_NOSIZE))
853 if (!(pos->flags & SWP_NOMOVE))
862 if (
win.mouse.initialized == WIN_MOUSE_LEGACY)
867 if (
win.mouse.initialized == WIN_MOUSE_LEGACY)
872 if (
win.mouse.initialized)
884 if (
win.mouse.initialized == WIN_MOUSE_LEGACY)
892 if (wParam == RIM_INPUT &&
win.mouse.initialized == WIN_MOUSE_RAW)
904 case WM_WINDOWPOSCHANGING:
908 case WM_WINDOWPOSCHANGED:
912 case WM_STYLECHANGED:
913 case WM_THEMECHANGED:
918 switch (wParam & 0xFFF0) {
943 if (
win.flags & QVF_FULLSCREEN)
952 return DefWindowProc(hWnd, uMsg, wParam, lParam);
975 while (PeekMessage(&
msg, NULL, 0, 0, PM_REMOVE)) {
976 if (
msg.message == WM_QUIT) {
980 win.lastMsgTime =
msg.time;
981 TranslateMessage(&
msg);
982 DispatchMessage(&
msg);
985 if (
win.mode_changed) {
991 if (
win.mouse.grabbed) {
998 win.mode_changed = 0;
1004 if (
win.wnd && !(
win.flags & QVF_FULLSCREEN)) {
1037 memset(&wc, 0,
sizeof(wc));
1038 wc.cbSize =
sizeof(wc);
1042 IMAGE_ICON, 32, 32, LR_CREATEDIBSECTION);
1044 IMAGE_ICON, 16, 16, LR_CREATEDIBSECTION);
1045 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
1046 wc.hbrBackground = GetStockObject(BLACK_BRUSH);
1049 if (!RegisterClassEx(&wc)) {
1050 Com_Error(ERR_FATAL,
"Couldn't register main window class");
1054 win.wnd = CreateWindow(
1065 Com_Error(ERR_FATAL,
"Couldn't create main window");
1070 Com_Error(ERR_FATAL,
"Couldn't get DC of the main window");
1075 if (GetDeviceGammaRamp(
win.dc,
win.gamma_orig)) {
1076 Com_DPrintf(
"...enabling hardware gamma\n");
1077 win.flags |= QVF_GAMMARAMP;
1078 memcpy(
win.gamma_cust,
win.gamma_orig,
sizeof(
win.gamma_cust));
1080 Com_DPrintf(
"...hardware gamma not supported\n");
1093 if (
win.flags & QVF_GAMMARAMP) {
1094 SetDeviceGammaRamp(
win.dc,
win.gamma_orig);
1098 ShowWindow(
win.wnd, SW_SHOWNORMAL);
1099 ReleaseDC(
win.wnd,
win.dc);
1100 DestroyWindow(
win.wnd);
1104 UnhookWindowsHookEx(
win.kbdHook);
1107 if (
win.flags & QVF_FULLSCREEN) {
1108 ChangeDisplaySettings(NULL, 0);
1111 memset(&
win, 0,
sizeof(
win));
1124 while (ShowCursor(FALSE) >= 0)
1130 while (ShowCursor(TRUE) < 0)
1137 SetCursorPos(
win.center_x,
win.center_y);
1138 ClipCursor(&
win.screen_rc);
1146 if (
win.mouse.parmsvalid) {
1148 parms[0] = parms[1] = parms[2] = 0;
1150 parms[0] = parms[1] = 0;
1153 win.mouse.restoreparms = SystemParametersInfo(
1154 SPI_SETMOUSE, 0, parms, 0);
1158 SetCapture(
win.wnd);
1160 SetWindowText(
win.wnd,
"[" PRODUCT
"]");
1166 if (
win.mouse.restoreparms)
1167 SystemParametersInfo(SPI_SETMOUSE, 0,
win.mouse.originalparms, 0);
1169 SetCursorPos(
win.center_x,
win.center_y);
1174 SetWindowText(
win.wnd, PRODUCT);
1181 if (!
win.mouse.initialized) {
1185 if (!
win.mouse.grabbed) {
1189 if (
win.mouse.initialized == WIN_MOUSE_RAW) {
1198 if (!GetCursorPos(&pt)) {
1202 *dx = pt.x -
win.center_x;
1203 *dy = pt.y -
win.center_y;
1206 SetCursorPos(
win.center_x,
win.center_y);
1214 memset(&rid, 0,
sizeof(rid));
1215 rid.usUsagePage = 0x01;
1217 rid.dwFlags =
flags;
1218 rid.hwndTarget =
win.wnd;
1220 return RegisterRawInputDevices(&rid, 1,
sizeof(rid));
1225 if (!
win.mouse.initialized) {
1232 if (
win.mouse.initialized == WIN_MOUSE_RAW) {
1239 memset(&
win.mouse, 0,
sizeof(
win.mouse));
1244 if (
win.mouse.grabbed) {
1251 if (
win.mouse.initialized) {
1263 win.mouse.initialized = WIN_MOUSE_LEGACY;
1267 Com_EPrintf(
"RegisterRawInputDevices failed with error %#lx\n", GetLastError());
1270 Com_Printf(
"Raw mouse initialized.\n");
1271 win.mouse.initialized = WIN_MOUSE_RAW;
1275 if (
win.mouse.initialized == WIN_MOUSE_LEGACY) {
1276 win.mouse.parmsvalid = SystemParametersInfo(SPI_GETMOUSE, 0,
1277 win.mouse.originalparms, 0);
1279 Com_Printf(
"Legacy mouse initialized.\n");
1290 if (!
win.mouse.initialized) {
1294 if (
win.mouse.grabbed == grab) {
1295 if (
win.mouse.initialized == WIN_MOUSE_LEGACY) {
1296 SetCursorPos(
win.center_x,
win.center_y);
1311 win.mouse.grabbed = grab;
1312 win.mouse.state = 0;
1319 SetCursorPos(
win.screen_rc.left + x,
win.screen_rc.top + y);
1330 char *cliptext, *
data;
1332 if (!OpenClipboard(NULL)) {
1333 Com_DPrintf(
"Couldn't open clipboard.\n");
1338 if ((clipdata = GetClipboardData(CF_TEXT)) != NULL) {
1339 if ((cliptext = GlobalLock(clipdata)) != NULL) {
1340 data = Z_CopyString(cliptext);
1341 GlobalUnlock(clipdata);
1364 if (!OpenClipboard(NULL)) {
1365 Com_DPrintf(
"Couldn't open clipboard.\n");
1371 length = strlen(
data) + 1;
1372 if ((clipdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, length)) != NULL) {
1373 if ((cliptext = GlobalLock(clipdata)) != NULL) {
1374 memcpy(cliptext,
data, length);
1375 GlobalUnlock(clipdata);
1376 SetClipboardData(CF_TEXT, clipdata);
1394 api->GetEvents = NULL;