1 /* NetHack 3.6 mhmain.c $NHDT-Date: 1432512811 2015/05/25 00:13:31 $ $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2021 */
8 /* JNetHack may be freely redistributed. See license for details. */
13 #include "patchlevel.h"
23 typedef struct mswin_nethack_main_window {
25 } NHMainWindow, *PNHMainWindow;
27 extern winid WIN_STATUS;
29 static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
30 static TCHAR szTitle[MAX_LOADSTRING];
31 extern void mswin_display_splash_window(BOOL);
33 LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
34 LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
35 static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
36 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
37 static void register_main_window_class(void);
38 static int menuid2mapmode(int menuid);
39 static int mapmode2menuid(int map_mode);
40 static void nhlock_windows(BOOL lock);
41 static char *nh_compose_ascii_screenshot();
42 static void mswin_apply_window_style_all();
43 // returns strdup() created pointer - callee assumes the ownership
46 mswin_init_main_window()
48 static int run_once = 0;
52 /* register window class */
54 LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
55 register_main_window_class();
59 /* create the main window */
61 CreateWindow(szMainWindowClass, /* registered class name */
62 szTitle, /* window name */
63 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */
64 CW_USEDEFAULT, /* horizontal position of window */
65 CW_USEDEFAULT, /* vertical position of window */
66 CW_USEDEFAULT, /* window width */
67 CW_USEDEFAULT, /* window height */
68 NULL, /* handle to parent or owner window */
69 NULL, /* menu handle or child identifier */
70 GetNHApp()->hApp, /* handle to application instance */
71 NULL /* window-creation data */
75 panic("Cannot create main window");
77 if (GetNHApp()->regMainMinX != CW_USEDEFAULT) {
78 wp.length = sizeof(wp);
79 wp.showCmd = GetNHApp()->regMainShowState;
81 wp.ptMinPosition.x = GetNHApp()->regMainMinX;
82 wp.ptMinPosition.y = GetNHApp()->regMainMinY;
84 wp.ptMaxPosition.x = GetNHApp()->regMainMaxX;
85 wp.ptMaxPosition.y = GetNHApp()->regMainMaxY;
87 wp.rcNormalPosition.left = GetNHApp()->regMainLeft;
88 wp.rcNormalPosition.top = GetNHApp()->regMainTop;
89 wp.rcNormalPosition.right = GetNHApp()->regMainRight;
90 wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom;
91 SetWindowPlacement(ret, &wp);
93 ShowWindow(ret, SW_SHOWDEFAULT);
100 register_main_window_class()
104 ZeroMemory(&wcex, sizeof(wcex));
105 wcex.style = CS_HREDRAW | CS_VREDRAW;
106 wcex.lpfnWndProc = (WNDPROC) MainWndProc;
109 wcex.hInstance = GetNHApp()->hApp;
110 wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_NETHACKW);
111 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
112 wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
113 wcex.lpszMenuName = (TCHAR *) IDC_NETHACKW;
114 wcex.lpszClassName = szMainWindowClass;
116 RegisterClass(&wcex);
120 * Keypad keys are translated to the normal values below.
121 * Shifted keypad keys are translated to the
122 * shift values below.
142 static const unsigned char
143 /* normal, shift, control */
144 keypad[KEY_LAST][3] =
146 { 'y', 'Y', C('y') }, /* 7 */
147 { 'k', 'K', C('k') }, /* 8 */
148 { 'u', 'U', C('u') }, /* 9 */
149 { 'm', C('p'), C('p') }, /* - */
150 { 'h', 'H', C('h') }, /* 4 */
151 { 'g', 'G', 'g' }, /* 5 */
152 { 'l', 'L', C('l') }, /* 6 */
153 { '+', 'P', C('p') }, /* + */
154 { 'b', 'B', C('b') }, /* 1 */
155 { 'j', 'J', C('j') }, /* 2 */
156 { 'n', 'N', C('n') }, /* 3 */
157 { 'i', 'I', C('i') }, /* Ins */
158 { '.', ':', ':' } /* Del */
160 numpad[KEY_LAST][3] = {
161 { '7', M('7'), '7' }, /* 7 */
162 { '8', M('8'), '8' }, /* 8 */
163 { '9', M('9'), '9' }, /* 9 */
164 { 'm', C('p'), C('p') }, /* - */
165 { '4', M('4'), '4' }, /* 4 */
166 { '5', M('5'), '5' }, /* 5 */
167 { '6', M('6'), '6' }, /* 6 */
168 { '+', 'P', C('p') }, /* + */
169 { '1', M('1'), '1' }, /* 1 */
170 { '2', M('2'), '2' }, /* 2 */
171 { '3', M('3'), '3' }, /* 3 */
172 { '0', M('0'), '0' }, /* Ins */
173 { '.', ':', ':' } /* Del */
176 #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
177 #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
178 #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
179 #define KEYTABLE(x) \
180 (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
182 static const char *extendedlist = "acdefijlmnopqrstuvw?2";
185 static const char scanmap[] = {
187 '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, 0, 'q', 'w',
188 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd',
189 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
190 'b', 'n', 'm', ',', '.', '?' /* ... */
193 #define IDT_FUZZ_TIMER 100
196 // FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
198 // PURPOSE: Processes messages for the main window.
201 MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
203 PNHMainWindow data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
205 static int doublebyte = 0;
210 /* set window data */
211 data = (PNHMainWindow) malloc(sizeof(NHMainWindow));
213 panic("out of memory");
214 ZeroMemory(data, sizeof(NHMainWindow));
215 data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
216 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
218 /* update menu items */
220 GetMenu(hWnd), IDM_SETTING_LOCKWINDOWS,
222 | (GetNHApp()->bWindowsLocked ? MF_CHECKED : MF_UNCHECKED));
224 CheckMenuItem(GetMenu(hWnd), IDM_SETTING_AUTOLAYOUT,
225 GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
227 /* store handle to the mane menu in the application record */
228 GetNHApp()->hMainWnd = hWnd;
231 case WM_MSNH_COMMAND:
232 onMSNHCommand(hWnd, wParam, lParam);
237 /* translate arrow keys into nethack commands */
240 if (STATEON(VK_CONTROL)) {
241 /* scroll map window one line left */
242 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
243 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
245 NHEVENT_KBD(KEYTABLE(KEY_W));
250 if (STATEON(VK_CONTROL)) {
251 /* scroll map window one line right */
252 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
253 MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
255 NHEVENT_KBD(KEYTABLE(KEY_E));
260 if (STATEON(VK_CONTROL)) {
261 /* scroll map window one line up */
262 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
263 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
265 NHEVENT_KBD(KEYTABLE(KEY_N));
270 if (STATEON(VK_CONTROL)) {
271 /* scroll map window one line down */
272 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
273 MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
275 NHEVENT_KBD(KEYTABLE(KEY_S));
280 if (STATEON(VK_CONTROL)) {
281 /* scroll map window to upper left corner */
282 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
283 MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
285 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
286 MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
288 NHEVENT_KBD(KEYTABLE(KEY_NW));
293 if (STATEON(VK_CONTROL)) {
294 /* scroll map window to lower right corner */
295 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
296 MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM) NULL);
298 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
299 MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM) NULL);
301 NHEVENT_KBD(KEYTABLE(KEY_SW));
306 if (STATEON(VK_CONTROL)) {
307 /* scroll map window one page up */
308 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
309 MAKEWPARAM(SB_PAGEUP, 0), (LPARAM) NULL);
311 NHEVENT_KBD(KEYTABLE(KEY_NE));
316 if (STATEON(VK_CONTROL)) {
317 /* scroll map window one page down */
318 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
319 MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM) NULL);
321 NHEVENT_KBD(KEYTABLE(KEY_SE));
327 NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
331 NHEVENT_KBD(KEYTABLE(KEY_INV));
335 NHEVENT_KBD(KEYTABLE(KEY_MINUS));
339 NHEVENT_KBD(KEYTABLE(KEY_PLUS));
342 #if defined(DEBUG) && defined(_MSC_VER)
344 if (IsDebuggerPresent()) {
345 iflags.debug_fuzzer = !iflags.debug_fuzzer;
351 case VK_CLEAR: /* This is the '5' key */
352 NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
356 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
357 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
358 ? data->mapAcsiiModeSave
361 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
362 ? MAP_MODE_ASCII_FIT_TO_SCREEN
363 : MAP_MODE_TILES_FIT_TO_SCREEN);
368 if (IS_MAP_ASCII(iflags.wc_map_mode)) {
369 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
370 mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
372 mswin_select_map_mode(MAP_MODE_TILES);
375 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
376 mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
378 mswin_select_map_mode(data->mapAcsiiModeSave);
388 ZeroMemory(kbd_state, sizeof(kbd_state));
389 GetKeyboardState(kbd_state);
391 if (ToAscii((UINT) wParam, (lParam >> 16) & 0xFF, kbd_state, &c, 0)) {
392 NHEVENT_KBD(c & 0xFF);
402 #if 1 /*JP*//*
\91S
\8ap
\95¶
\8e\9a\91ÃŽ
\89\9e*/
405 if (doublebyte == 1) {
406 NHEVENT_KBD(wParam & 0xFF);
409 } else if (is_kanji(wParam)) {
410 NHEVENT_KBD(wParam & 0xFF);
417 case WM_SYSCHAR: /* Alt-char pressed */
420 If not nethackmode, don't handle Alt-keys here.
421 If no Alt-key pressed it can never be an extended command
423 if (GetNHApp()->regNetHackMode && ((lParam & 1 << 29) != 0)) {
424 unsigned char c = (unsigned char) (wParam & 0xFF);
425 unsigned char scancode = (lParam >> 16) & 0xFF;
426 if (index(extendedlist, tolower(c)) != 0) {
427 NHEVENT_KBD(M(tolower(c)));
428 } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) {
433 return DefWindowProc(hWnd, message, wParam, lParam);
437 /* process commands - menu commands mostly */
438 if (onWMCommand(hWnd, wParam, lParam))
439 return DefWindowProc(hWnd, message, wParam, lParam);
447 mswin_layout_main_window(NULL);
449 wp.length = sizeof(wp);
450 if (GetWindowPlacement(hWnd, &wp)) {
451 GetNHApp()->regMainShowState =
452 (wp.showCmd == SW_SHOWMAXIMIZED ? SW_SHOWMAXIMIZED
455 GetNHApp()->regMainMinX = wp.ptMinPosition.x;
456 GetNHApp()->regMainMinY = wp.ptMinPosition.y;
458 GetNHApp()->regMainMaxX = wp.ptMaxPosition.x;
459 GetNHApp()->regMainMaxY = wp.ptMaxPosition.y;
461 GetNHApp()->regMainLeft = wp.rcNormalPosition.left;
462 GetNHApp()->regMainTop = wp.rcNormalPosition.top;
463 GetNHApp()->regMainRight = wp.rcNormalPosition.right;
464 GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom;
469 /* if there is a menu window out there -
470 transfer input focus to it */
471 if (IsWindow(GetNHApp()->hPopupWnd)) {
472 SetFocus(GetNHApp()->hPopupWnd);
477 /* exit gracefully */
478 if (program_state.gameover) {
479 /* assume the user really meant this, as the game is already
481 /* to make sure we still save bones, just set stop printing flag
483 program_state.stopprint++;
485 '\033'); /* and send keyboard input as if user pressed ESC */
486 /* additional code for this is done in menu and rip windows */
487 } else if (!program_state.something_worth_saving) {
488 /* User exited before the game started, e.g. during splash display
493 /* prompt user for action */
495 switch (NHMessageBox(hWnd, TEXT("Save?"),
497 switch (NHMessageBox(hWnd, TEXT("
\95Û
\91¶
\82µ
\82Ä
\8fI
\97¹
\82µ
\82Ü
\82·
\82©
\81H"),
499 MB_YESNOCANCEL | MB_ICONQUESTION)) {
502 /* destroy popup window - it has its own loop and we need to
503 return control to NetHack core at this point */
504 if (IsWindow(GetNHApp()->hPopupWnd))
505 SendMessage(GetNHApp()->hPopupWnd, WM_COMMAND, IDCANCEL,
508 /* tell NetHack core that "hangup" is requested */
527 /* apparently we never get here
528 TODO: work on exit routines - need to send
532 free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA));
533 SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
535 // PostQuitMessage(0);
539 case WM_DPICHANGED: {
540 mswin_layout_main_window(NULL);
544 return DefWindowProc(hWnd, message, wParam, lParam);
550 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
552 UNREFERENCED_PARAMETER(hWnd);
553 UNREFERENCED_PARAMETER(wParam);
554 UNREFERENCED_PARAMETER(lParam);
557 /* new window was just added */
558 case MSNH_MSG_ADDWND: {
559 PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd) lParam;
562 if (GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP)
563 mswin_select_map_mode(iflags.wc_map_mode);
565 child = GetNHApp()->windowlist[msg_param->wid].win;
568 case MSNH_MSG_RANDOM_INPUT: {
569 nhassert(iflags.debug_fuzzer);
570 NHEVENT_KBD(randomkey());
576 /* adjust windows to fit main window layout
577 ---------------------------
579 +-------------------------+
585 +-------------------------+
587 ---------------------------
590 mswin_layout_main_window(HWND changed_child)
593 RECT client_rt, wnd_rect;
601 HWND wnd_status, wnd_msg;
604 if (GetNHApp()->bAutoLayout) {
605 GetClientRect(GetNHApp()->hMainWnd, &client_rt);
606 data = (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd,
609 /* get sizes of child windows */
610 wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
611 if (IsWindow(wnd_status)) {
612 mswin_status_window_size(wnd_status, &status_size);
614 status_size.cx = status_size.cy = 0;
617 wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
618 if (IsWindow(wnd_msg)) {
619 mswin_message_window_size(wnd_msg, &msg_size);
621 msg_size.cx = msg_size.cy = 0;
624 /* find all menu windows and calculate the size */
625 menu_size.cx = menu_size.cy = 0;
626 for (i = 0; i < MAXWINDOWS; i++) {
628 if (GetNHApp()->windowlist[i].win
629 && !GetNHApp()->windowlist[i].dead
630 && GetNHApp()->windowlist[i].type == NHW_MENU) {
631 mswin_menu_window_size(GetNHApp()->windowlist[i].win,
633 menu_size.cx = max(menu_size.cx, tmp_size.cx);
634 menu_size.cy = max(menu_size.cy, tmp_size.cy);
638 /* set window positions */
639 SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right,
641 switch (iflags.wc_align_status) {
643 status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
645 (wnd_rect.bottom - wnd_rect.top); // that won't look good
646 status_org.x = wnd_rect.left;
647 status_org.y = wnd_rect.top;
648 wnd_rect.left += status_size.cx;
652 status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
654 (wnd_rect.bottom - wnd_rect.top); // that won't look good
655 status_org.x = wnd_rect.right - status_size.cx;
656 status_org.y = wnd_rect.top;
657 wnd_rect.right -= status_size.cx;
661 status_size.cx = (wnd_rect.right - wnd_rect.left);
662 status_org.x = wnd_rect.left;
663 status_org.y = wnd_rect.top;
664 wnd_rect.top += status_size.cy;
669 status_size.cx = (wnd_rect.right - wnd_rect.left);
670 status_org.x = wnd_rect.left;
671 status_org.y = wnd_rect.bottom - status_size.cy;
672 wnd_rect.bottom -= status_size.cy;
676 switch (iflags.wc_align_message) {
678 msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
679 msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
680 msg_org.x = wnd_rect.left;
681 msg_org.y = wnd_rect.top;
682 wnd_rect.left += msg_size.cx;
686 msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
687 msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
688 msg_org.x = wnd_rect.right - msg_size.cx;
689 msg_org.y = wnd_rect.top;
690 wnd_rect.right -= msg_size.cx;
694 msg_size.cx = (wnd_rect.right - wnd_rect.left);
695 msg_org.x = wnd_rect.left;
696 msg_org.y = wnd_rect.top;
697 wnd_rect.top += msg_size.cy;
702 msg_size.cx = (wnd_rect.right - wnd_rect.left);
703 msg_org.x = wnd_rect.left;
704 msg_org.y = wnd_rect.bottom - msg_size.cy;
705 wnd_rect.bottom -= msg_size.cy;
710 map_org.x = wnd_rect.left;
711 map_org.y = wnd_rect.top;
712 map_size.cx = wnd_rect.right - wnd_rect.left;
713 map_size.cy = wnd_rect.bottom - wnd_rect.top;
715 GetNHApp()->rtStatusWindow.left = status_org.x;
716 GetNHApp()->rtStatusWindow.top = status_org.y;
717 GetNHApp()->rtStatusWindow.right = status_org.x + status_size.cx;
718 GetNHApp()->rtStatusWindow.bottom = status_org.y + status_size.cy;
720 GetNHApp()->rtTextWindow.left = map_org.x;
721 GetNHApp()->rtTextWindow.top = map_org.y;
722 GetNHApp()->rtTextWindow.right =
723 map_org.x + (wnd_rect.right - wnd_rect.left);
724 GetNHApp()->rtTextWindow.bottom = map_org.y + map_size.cy;
726 GetNHApp()->rtMapWindow.left = map_org.x;
727 GetNHApp()->rtMapWindow.top = map_org.y;
728 GetNHApp()->rtMapWindow.right = map_org.x + map_size.cx;
729 GetNHApp()->rtMapWindow.bottom = map_org.y + map_size.cy;
731 GetNHApp()->rtMsgWindow.left = msg_org.x;
732 GetNHApp()->rtMsgWindow.top = msg_org.y;
733 GetNHApp()->rtMsgWindow.right = msg_org.x + msg_size.cx;
734 GetNHApp()->rtMsgWindow.bottom = msg_org.y + msg_size.cy;
736 /* map_width/4 < menu_width < map_width*2/3 */
737 GetNHApp()->rtMenuWindow.left =
738 GetNHApp()->rtMapWindow.right
739 - min(map_size.cx * 2 / 3, max(map_size.cx / 4, menu_size.cx));
740 GetNHApp()->rtMenuWindow.top = GetNHApp()->rtMapWindow.top;
741 GetNHApp()->rtMenuWindow.right = GetNHApp()->rtMapWindow.right;
742 GetNHApp()->rtMenuWindow.bottom = GetNHApp()->rtMapWindow.bottom;
744 GetNHApp()->rtInvenWindow.left = GetNHApp()->rtMenuWindow.left;
745 GetNHApp()->rtInvenWindow.top = GetNHApp()->rtMenuWindow.top;
746 GetNHApp()->rtInvenWindow.right = GetNHApp()->rtMenuWindow.right;
747 GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom;
749 /* adjust map window size only if perm_invent is set */
750 if (iflags.perm_invent)
751 GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left;
754 /* go through the windows list and adjust sizes */
755 for (i = 0; i < MAXWINDOWS; i++) {
756 if (GetNHApp()->windowlist[i].win
757 && !GetNHApp()->windowlist[i].dead) {
759 /* kludge - inventory window should have its own type (same as
761 as a matter of fact) */
762 if (iflags.perm_invent && i == WIN_INVEN) {
763 mswin_get_window_placement(NHW_INVEN, &rt);
765 mswin_get_window_placement(GetNHApp()->windowlist[i].type,
769 MoveWindow(GetNHApp()->windowlist[i].win, rt.left, rt.top,
770 rt.right - rt.left, rt.bottom - rt.top, TRUE);
773 if (IsWindow(changed_child))
774 SetForegroundWindow(changed_child);
777 VOID CALLBACK FuzzTimerProc(
780 _In_ UINT_PTR idEvent,
787 SHORT k = VkKeyScanA(c);
788 BOOL gen_alt = (rn2(50) == 0) && isalpha(c);
790 if (!iflags.debug_fuzzer) {
791 KillTimer(hwnd, IDT_FUZZ_TIMER);
798 ZeroMemory(input, sizeof(input));
800 input[i_pos].type = INPUT_KEYBOARD;
801 input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
802 input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
807 input[i_pos].type = INPUT_KEYBOARD;
808 input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
809 input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
813 input[i_pos].type = INPUT_KEYBOARD;
814 input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
815 input[i_pos].ki.wScan = MapVirtualKey(LOBYTE(k), 0);
819 input[i_pos].type = INPUT_KEYBOARD;
820 input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
821 input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
825 input[i_pos].type = INPUT_KEYBOARD;
826 input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
827 input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
830 SendInput(i_pos, input, sizeof(input[0]));
834 onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
839 UNREFERENCED_PARAMETER(lParam);
841 data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
842 wmId = LOWORD(wParam);
843 wmEvent = HIWORD(wParam);
845 // Parse the menu selections:
848 mswin_display_splash_window(TRUE);
852 if (iflags.debug_fuzzer)
853 KillTimer(hWnd, IDT_FUZZ_TIMER);
855 SetTimer(hWnd, IDT_FUZZ_TIMER, 10, FuzzTimerProc);
856 iflags.debug_fuzzer = !iflags.debug_fuzzer;
859 if (iflags.debug_fuzzer)
865 if (iflags.debug_fuzzer)
867 if (!program_state.gameover && !program_state.done_hup)
874 case IDM_MAP_ASCII4X6:
875 case IDM_MAP_ASCII6X8:
876 case IDM_MAP_ASCII8X8:
877 case IDM_MAP_ASCII16X8:
878 case IDM_MAP_ASCII7X12:
879 case IDM_MAP_ASCII8X12:
880 case IDM_MAP_ASCII12X16:
881 case IDM_MAP_ASCII16X12:
882 case IDM_MAP_ASCII10X18:
883 mswin_select_map_mode(menuid2mapmode(wmId));
886 case IDM_MAP_FIT_TO_SCREEN:
887 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
888 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
889 ? data->mapAcsiiModeSave
892 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
893 ? MAP_MODE_ASCII_FIT_TO_SCREEN
894 : MAP_MODE_TILES_FIT_TO_SCREEN);
898 case IDM_SETTING_SCREEN_TO_CLIPBOARD: {
904 p = nh_compose_ascii_screenshot();
909 if (!OpenClipboard(hWnd)) {
910 NHMessageBox(hWnd, TEXT("Cannot open clipboard"),
911 MB_OK | MB_ICONERROR);
918 hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char));
919 if (hglbCopy == NULL) {
925 p_copy = (char *) GlobalLock(hglbCopy);
926 strncpy(p_copy, p, len);
927 p_copy[len] = 0; // null character
928 GlobalUnlock(hglbCopy);
930 SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy);
937 case IDM_SETTING_SCREEN_TO_FILE: {
939 TCHAR filename[1024];
940 TCHAR whackdir[MAX_PATH];
946 if (iflags.debug_fuzzer)
949 ZeroMemory(filename, sizeof(filename));
950 ZeroMemory(&ofn, sizeof(ofn));
951 ofn.lStructSize = sizeof(OPENFILENAME);
952 ofn.hwndOwner = hWnd;
953 ofn.hInstance = GetNHApp()->hApp;
954 ofn.lpstrFilter = TEXT("Text Files (*.txt)\x0*.txt\x0")
955 TEXT("All Files (*.*)\x0*.*\x0") TEXT("\x0\x0");
956 ofn.lpstrCustomFilter = NULL;
957 ofn.nMaxCustFilter = 0;
958 ofn.nFilterIndex = 1;
959 ofn.lpstrFile = filename;
960 ofn.nMaxFile = SIZE(filename);
961 ofn.lpstrFileTitle = NULL;
962 ofn.nMaxFileTitle = 0;
963 ofn.lpstrInitialDir = NH_A2W(hackdir, whackdir, MAX_PATH);
964 ofn.lpstrTitle = NULL;
965 ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
967 ofn.nFileExtension = 0;
968 ofn.lpstrDefExt = TEXT("txt");
971 ofn.lpTemplateName = 0;
973 if (!GetSaveFileName(&ofn))
976 text = nh_compose_ascii_screenshot();
980 pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8"));
983 _stprintf(buf, TEXT("Cannot open %s for writing!"), filename);
984 NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR);
990 wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t));
992 panic("out of memory");
993 MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen);
994 fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile);
1001 GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1;
1002 mswin_menu_check_intf_mode();
1003 mswin_apply_window_style_all();
1006 case IDM_CLEARSETTINGS: {
1007 mswin_destroy_reg();
1008 /* Notify the user that windows settings will not be saved this time.
1010 NHMessageBox(GetNHApp()->hMainWnd,
1011 TEXT("Your Windows Settings will not be stored when you "
1013 MB_OK | MB_ICONINFORMATION);
1017 case IDM_SETTING_AUTOLAYOUT:
1018 GetNHApp()->bAutoLayout = !GetNHApp()->bAutoLayout;
1019 mswin_layout_main_window(NULL);
1021 /* Update menu item check-mark */
1022 CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_AUTOLAYOUT,
1023 GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
1026 case IDM_SETTING_LOCKWINDOWS:
1027 nhlock_windows(!GetNHApp()->bWindowsLocked);
1031 display_file(HELP, TRUE);
1034 case IDM_HELP_COMMANDS:
1035 display_file(SHELP, TRUE);
1038 case IDM_HELP_HISTORY:
1042 case IDM_HELP_INFO_CHAR:
1046 case IDM_HELP_INFO_KEY:
1047 (void) dowhatdoes();
1050 case IDM_HELP_OPTIONS:
1054 case IDM_HELP_OPTIONS_LONG:
1055 display_file(OPTIONFILE, TRUE);
1058 case IDM_HELP_EXTCMD:
1062 case IDM_HELP_LICENSE:
1063 display_file(LICENSE, TRUE);
1066 case IDM_HELP_PORTHELP:
1067 display_file(PORT_HELP, TRUE);
1076 // Mesage handler for about box.
1078 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1082 RECT main_rt, dlg_rt;
1085 UNREFERENCED_PARAMETER(lParam);
1089 getversionstring(buf);
1090 SetDlgItemText(hDlg, IDC_ABOUT_VERSION,
1091 NH_A2W(buf, wbuf, sizeof(wbuf)));
1093 SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
1094 NH_A2W(COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B
1095 "\n" COPYRIGHT_BANNER_C
1096 "\n" COPYRIGHT_BANNER_D,
1099 /* center dialog in the main window */
1100 GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
1101 GetWindowRect(hDlg, &dlg_rt);
1102 dlg_sz.cx = dlg_rt.right - dlg_rt.left;
1103 dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
1105 dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
1106 dlg_rt.right = dlg_rt.left + dlg_sz.cx;
1107 dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
1108 dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
1109 MoveWindow(hDlg, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
1110 (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
1116 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
1117 EndDialog(hDlg, LOWORD(wParam));
1126 mswin_menu_check_intf_mode()
1128 HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
1130 if (GetNHApp()->regNetHackMode)
1131 CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
1133 CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
1137 mswin_select_map_mode(int mode)
1144 (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd, GWLP_USERDATA);
1146 /* override for Rogue level */
1147 if (Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode))
1150 /* set map mode menu mark */
1151 if (IS_MAP_ASCII(mode)) {
1153 GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18,
1154 mapmode2menuid(IS_MAP_FIT_TO_SCREEN(mode) ? data->mapAcsiiModeSave
1158 CheckMenuRadioItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES,
1159 IDM_MAP_ASCII10X18, mapmode2menuid(MAP_MODE_TILES),
1163 /* set fit-to-screen mode mark */
1164 CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_FIT_TO_SCREEN,
1165 MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode) ? MF_CHECKED
1168 if (IS_MAP_ASCII(iflags.wc_map_mode)
1169 && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
1170 data->mapAcsiiModeSave = iflags.wc_map_mode;
1173 iflags.wc_map_mode = mode;
1176 ** first, check if WIN_MAP has been inialized.
1177 ** If not - attempt to retrieve it by type, then check it again
1179 if (map_id == WIN_ERR)
1180 map_id = mswin_winid_from_type(NHW_MAP);
1181 if (map_id != WIN_ERR)
1182 mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
1185 static struct t_menu2mapmode {
1188 } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES },
1189 { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
1190 { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
1191 { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
1192 { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
1193 { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
1194 { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
1195 { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
1196 { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
1197 { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
1198 { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
1202 menuid2mapmode(int menuid)
1204 struct t_menu2mapmode *p;
1205 for (p = _menu2mapmode; p->mapMode != -1; p++)
1206 if (p->menuID == menuid)
1212 mapmode2menuid(int map_mode)
1214 struct t_menu2mapmode *p;
1215 for (p = _menu2mapmode; p->mapMode != -1; p++)
1216 if (p->mapMode == map_mode)
1222 nhlock_windows(BOOL lock)
1225 GetNHApp()->bWindowsLocked = lock;
1226 CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_LOCKWINDOWS,
1227 MF_BYCOMMAND | (lock ? MF_CHECKED : MF_UNCHECKED));
1229 /* restyle windows */
1230 mswin_apply_window_style_all();
1234 mswin_apply_window_style(HWND hwnd) {
1235 DWORD style = 0, exstyle = 0;
1237 style = GetWindowLong(hwnd, GWL_STYLE);
1238 exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
1240 if( !GetNHApp()->bWindowsLocked ) {
1241 style = WS_CHILD|WS_CLIPSIBLINGS|WS_CAPTION|WS_SIZEBOX|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1242 exstyle = WS_EX_WINDOWEDGE;
1243 } else if (GetNHApp()->regNetHackMode) {
1244 /* do away borders */
1245 style = WS_CHILD|WS_CLIPSIBLINGS|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1248 style = WS_CHILD|WS_CLIPSIBLINGS|WS_THICKFRAME|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1249 exstyle = WS_EX_WINDOWEDGE;
1252 SetWindowLong(hwnd, GWL_STYLE, style);
1253 SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
1254 SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
1255 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
1259 mswin_apply_window_style_all() {
1261 for (i = 0; i < MAXWINDOWS; i++) {
1262 if (IsWindow(GetNHApp()->windowlist[i].win)
1263 && !GetNHApp()->windowlist[i].dead) {
1264 mswin_apply_window_style(GetNHApp()->windowlist[i].win);
1267 mswin_layout_main_window(NULL);
1270 // returns strdup() created pointer - callee assumes the ownership
1271 #define TEXT_BUFFER_SIZE 4096
1273 nh_compose_ascii_screenshot()
1276 PMSNHMsgGetText text;
1278 retval = (char *) malloc(3 * TEXT_BUFFER_SIZE);
1281 (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE);
1284 - 1; /* make sure we always have 0 at the end of the buffer */
1286 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1287 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1288 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1289 strcpy(retval, text->buffer);
1291 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1292 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND,
1293 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1294 strcat(retval, text->buffer);
1296 ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1297 SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
1298 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1299 strcat(retval, text->buffer);