1 /* NetHack 3.7	mhmain.c	$NHDT-Date: 1596498352 2020/08/03 23:45:52 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.76 $ */
2 /* Copyright (C) 2001 by Alex Kompel 	 */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "winMS.h"
6 #include <commdlg.h>
7 #if !defined(CROSSCOMPILE)
8 #include "date.h"
9 #else
10 #include "config.h"
11 #endif
12 #if !defined(PATCHLEVEL_H)
13 #include "patchlevel.h"
14 #endif
15 #include "resource.h"
16 #include "mhmsg.h"
17 #include "mhinput.h"
18 #include "mhmain.h"
19 #include "mhmenu.h"
20 #include "mhstatus.h"
21 #include "mhmsgwnd.h"
22 #include "mhmap.h"
23 
24 typedef struct mswin_nethack_main_window {
25     int mapAcsiiModeSave;
26 } NHMainWindow, *PNHMainWindow;
27 
28 extern winid WIN_STATUS;
29 
30 static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
31 static TCHAR szTitle[MAX_LOADSTRING];
32 extern void mswin_display_splash_window(BOOL);
33 
34 LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
35 LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
36 static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
37 static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
38 static void register_main_window_class(void);
39 static int menuid2mapmode(int menuid);
40 static int mapmode2menuid(int map_mode);
41 static void nhlock_windows(BOOL lock);
42 static char *nh_compose_ascii_screenshot();
43 static void mswin_apply_window_style_all();
44 // returns strdup() created pointer - callee assumes the ownership
45 
46 HWND
mswin_init_main_window(void)47 mswin_init_main_window(void)
48 {
49     static int run_once = 0;
50     HWND ret;
51     WINDOWPLACEMENT wp;
52 
53     /* register window class */
54     if (!run_once) {
55         LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
56         register_main_window_class();
57         run_once = 1;
58     }
59 
60     /* create the main window */
61     ret =
62         CreateWindow(szMainWindowClass, /* registered class name */
63                      szTitle,           /* window name */
64                      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */
65                      CW_USEDEFAULT,    /* horizontal position of window */
66                      CW_USEDEFAULT,    /* vertical position of window */
67                      CW_USEDEFAULT,    /* window width */
68                      CW_USEDEFAULT,    /* window height */
69                      NULL,             /* handle to parent or owner window */
70                      NULL,             /* menu handle or child identifier */
71                      GetNHApp()->hApp, /* handle to application instance */
72                      NULL              /* window-creation data */
73                      );
74 
75     if (!ret)
76         panic("Cannot create main window");
77 
78     if (GetNHApp()->regMainMinX != CW_USEDEFAULT) {
79         wp.length = sizeof(wp);
80         wp.showCmd = GetNHApp()->regMainShowState;
81 
82         wp.ptMinPosition.x = GetNHApp()->regMainMinX;
83         wp.ptMinPosition.y = GetNHApp()->regMainMinY;
84 
85         wp.ptMaxPosition.x = GetNHApp()->regMainMaxX;
86         wp.ptMaxPosition.y = GetNHApp()->regMainMaxY;
87 
88         wp.rcNormalPosition.left = GetNHApp()->regMainLeft;
89         wp.rcNormalPosition.top = GetNHApp()->regMainTop;
90         wp.rcNormalPosition.right = GetNHApp()->regMainRight;
91         wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom;
92         SetWindowPlacement(ret, &wp);
93     } else
94         ShowWindow(ret, SW_SHOWDEFAULT);
95 
96     UpdateWindow(ret);
97     return ret;
98 }
99 
100 void
register_main_window_class(void)101 register_main_window_class(void)
102 {
103     WNDCLASS wcex;
104 
105     ZeroMemory(&wcex, sizeof(wcex));
106     wcex.style = CS_HREDRAW | CS_VREDRAW;
107     wcex.lpfnWndProc = (WNDPROC) MainWndProc;
108     wcex.cbClsExtra = 0;
109     wcex.cbWndExtra = 0;
110     wcex.hInstance = GetNHApp()->hApp;
111     wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_NETHACKW);
112     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
113     wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
114     wcex.lpszMenuName = (TCHAR *) IDC_NETHACKW;
115     wcex.lpszClassName = szMainWindowClass;
116 
117     RegisterClass(&wcex);
118 }
119 
120 /*
121  * Keypad keys are translated to the normal values below.
122  * Shifted keypad keys are translated to the
123  *    shift values below.
124  */
125 
126 enum KEY_INDEXES {
127     KEY_NW,
128     KEY_N,
129     KEY_NE,
130     KEY_MINUS,
131     KEY_W,
132     KEY_GOINTERESTING,
133     KEY_E,
134     KEY_PLUS,
135     KEY_SW,
136     KEY_S,
137     KEY_SE,
138     KEY_INV,
139     KEY_WAITLOOK,
140     KEY_LAST
141 };
142 
143 static const unsigned char
144     /* normal, shift, control */
145     keypad[KEY_LAST][3] =
146         {
147           { 'y', 'Y', C('y') },    /* 7 */
148           { 'k', 'K', C('k') },    /* 8 */
149           { 'u', 'U', C('u') },    /* 9 */
150           { 'm', C('p'), C('p') }, /* - */
151           { 'h', 'H', C('h') },    /* 4 */
152           { 'g', 'G', 'g' },       /* 5 */
153           { 'l', 'L', C('l') },    /* 6 */
154           { '+', 'P', C('p') },    /* + */
155           { 'b', 'B', C('b') },    /* 1 */
156           { 'j', 'J', C('j') },    /* 2 */
157           { 'n', 'N', C('n') },    /* 3 */
158           { 'i', 'I', C('i') },    /* Ins */
159           { '.', ':', ':' }        /* Del */
160         },
161     numpad[KEY_LAST][3] = {
162         { '7', M('7'), '7' },    /* 7 */
163         { '8', M('8'), '8' },    /* 8 */
164         { '9', M('9'), '9' },    /* 9 */
165         { 'm', C('p'), C('p') }, /* - */
166         { '4', M('4'), '4' },    /* 4 */
167         { '5', M('5'), '5' },    /* 5 */
168         { '6', M('6'), '6' },    /* 6 */
169         { '+', 'P', C('p') },    /* + */
170         { '1', M('1'), '1' },    /* 1 */
171         { '2', M('2'), '2' },    /* 2 */
172         { '3', M('3'), '3' },    /* 3 */
173         { '0', M('0'), '0' },    /* Ins */
174         { '.', ':', ':' }        /* Del */
175     };
176 
177 #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
178 #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
179 #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
180 #define KEYTABLE(x) \
181     (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
182 
183 static const char *extendedlist = "acdefijlmnopqrstuvw?2";
184 
185 #define SCANLO 0x02
186 static const char scanmap[] = {
187     /* ... */
188     '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, 0, 'q', 'w',
189     'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd',
190     'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
191     'b', 'n', 'm', ',', '.', '?' /* ... */
192 };
193 
194 #define IDT_FUZZ_TIMER 100
195 
196 /*
197 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
198 //
199 //  PURPOSE:  Processes messages for the main window.
200 */
201 LRESULT CALLBACK
MainWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)202 MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
203 {
204     PNHMainWindow data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
205 
206     switch (message) {
207     case WM_CREATE:
208         /* set window data */
209         data = (PNHMainWindow) malloc(sizeof(NHMainWindow));
210         if (!data)
211             panic("out of memory");
212         ZeroMemory(data, sizeof(NHMainWindow));
213         data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
214         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
215 
216         /* update menu items */
217         CheckMenuItem(
218             GetMenu(hWnd), IDM_SETTING_LOCKWINDOWS,
219             MF_BYCOMMAND
220                 | (GetNHApp()->bWindowsLocked ? MF_CHECKED : MF_UNCHECKED));
221 
222         CheckMenuItem(GetMenu(hWnd), IDM_SETTING_AUTOLAYOUT,
223                       GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
224 
225         /* store handle to the mane menu in the application record */
226         GetNHApp()->hMainWnd = hWnd;
227         break;
228 
229     case WM_MSNH_COMMAND:
230         onMSNHCommand(hWnd, wParam, lParam);
231         break;
232 
233     case WM_KEYDOWN: {
234 
235         /* translate arrow keys into nethack commands */
236         switch (wParam) {
237         case VK_LEFT:
238             if (STATEON(VK_CONTROL)) {
239                 /* scroll map window one line left */
240                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
241                             MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
242             } else {
243                 NHEVENT_KBD(KEYTABLE(KEY_W));
244             }
245             return 0;
246 
247         case VK_RIGHT:
248             if (STATEON(VK_CONTROL)) {
249                 /* scroll map window one line right */
250                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
251                             MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
252             } else {
253                 NHEVENT_KBD(KEYTABLE(KEY_E));
254             }
255             return 0;
256 
257         case VK_UP:
258             if (STATEON(VK_CONTROL)) {
259                 /* scroll map window one line up */
260                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
261                             MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
262             } else {
263                 NHEVENT_KBD(KEYTABLE(KEY_N));
264             }
265             return 0;
266 
267         case VK_DOWN:
268             if (STATEON(VK_CONTROL)) {
269                 /* scroll map window one line down */
270                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
271                             MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
272             } else {
273                 NHEVENT_KBD(KEYTABLE(KEY_S));
274             }
275             return 0;
276 
277         case VK_HOME:
278             if (STATEON(VK_CONTROL)) {
279                 /* scroll map window to upper left corner */
280                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
281                             MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
282 
283                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
284                             MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
285             } else {
286                 NHEVENT_KBD(KEYTABLE(KEY_NW));
287             }
288             return 0;
289 
290         case VK_END:
291             if (STATEON(VK_CONTROL)) {
292                 /* scroll map window to lower right corner */
293                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
294                             MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM) NULL);
295 
296                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
297                             MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM) NULL);
298             } else {
299                 NHEVENT_KBD(KEYTABLE(KEY_SW));
300             }
301             return 0;
302 
303         case VK_PRIOR:
304             if (STATEON(VK_CONTROL)) {
305                 /* scroll map window one page up */
306                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
307                             MAKEWPARAM(SB_PAGEUP, 0), (LPARAM) NULL);
308             } else {
309                 NHEVENT_KBD(KEYTABLE(KEY_NE));
310             }
311             return 0;
312 
313         case VK_NEXT:
314             if (STATEON(VK_CONTROL)) {
315                 /* scroll map window one page down */
316                 SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
317                             MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM) NULL);
318             } else {
319                 NHEVENT_KBD(KEYTABLE(KEY_SE));
320             }
321             return 0;
322 
323         case VK_DECIMAL:
324         case VK_DELETE:
325             NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
326             return 0;
327 
328         case VK_INSERT:
329             NHEVENT_KBD(KEYTABLE(KEY_INV));
330             return 0;
331 
332         case VK_SUBTRACT:
333             NHEVENT_KBD(KEYTABLE(KEY_MINUS));
334             return 0;
335 
336         case VK_ADD:
337             NHEVENT_KBD(KEYTABLE(KEY_PLUS));
338             return 0;
339 
340 #if defined(DEBUG) && defined(_MSC_VER)
341         case VK_PAUSE:
342             if (IsDebuggerPresent()) {
343                 iflags.debug_fuzzer = !iflags.debug_fuzzer;
344                 return 0;
345             }
346             break;
347 #endif
348 
349         case VK_CLEAR: /* This is the '5' key */
350             NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
351             return 0;
352 
353         case VK_F4:
354             if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
355                 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
356                                           ? data->mapAcsiiModeSave
357                                           : MAP_MODE_TILES);
358             } else {
359                 mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
360                                           ? MAP_MODE_ASCII_FIT_TO_SCREEN
361                                           : MAP_MODE_TILES_FIT_TO_SCREEN);
362             }
363             return 0;
364 
365         case VK_F5:
366             if (IS_MAP_ASCII(iflags.wc_map_mode)) {
367                 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
368                     mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
369                 } else {
370                     mswin_select_map_mode(MAP_MODE_TILES);
371                 }
372             } else {
373                 if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
374                     mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
375                 } else {
376                     mswin_select_map_mode(data->mapAcsiiModeSave);
377                 }
378             }
379             return 0;
380 
381         default: {
382             WORD c;
383             BYTE kbd_state[256];
384 
385             c = 0;
386             ZeroMemory(kbd_state, sizeof(kbd_state));
387             GetKeyboardState(kbd_state);
388 
389             if (ToAscii((UINT) wParam, (lParam >> 16) & 0xFF, kbd_state, &c, 0)) {
390                 NHEVENT_KBD(c & 0xFF);
391                 return 0;
392             } else {
393                 return 1;
394             }
395         }
396 
397         } /* end switch */
398     } break;
399 
400     case WM_SYSCHAR: /* Alt-char pressed */
401     {
402         /*
403           If not nethackmode, don't handle Alt-keys here.
404           If no Alt-key pressed it can never be an extended command
405         */
406         if (GetNHApp()->regNetHackMode && ((lParam & 1 << 29) != 0)) {
407             unsigned char c = (unsigned char) (wParam & 0xFF);
408             unsigned char scancode = (lParam >> 16) & 0xFF;
409             if (index(extendedlist, tolower(c)) != 0) {
410                 NHEVENT_KBD(M(tolower(c)));
411             } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) {
412                 NHEVENT_KBD(M('?'));
413             }
414             return 0;
415         }
416         return DefWindowProc(hWnd, message, wParam, lParam);
417     } break;
418 
419     case WM_COMMAND:
420         /* process commands - menu commands mostly */
421         if (onWMCommand(hWnd, wParam, lParam))
422             return DefWindowProc(hWnd, message, wParam, lParam);
423         else
424             return 0;
425 
426     case WM_MOVE:
427     case WM_SIZE: {
428         WINDOWPLACEMENT wp;
429 
430         mswin_layout_main_window(NULL);
431 
432         wp.length = sizeof(wp);
433         if (GetWindowPlacement(hWnd, &wp)) {
434             GetNHApp()->regMainShowState =
435                 (wp.showCmd == SW_SHOWMAXIMIZED ? SW_SHOWMAXIMIZED
436                                                 : SW_SHOWNORMAL);
437 
438             GetNHApp()->regMainMinX = wp.ptMinPosition.x;
439             GetNHApp()->regMainMinY = wp.ptMinPosition.y;
440 
441             GetNHApp()->regMainMaxX = wp.ptMaxPosition.x;
442             GetNHApp()->regMainMaxY = wp.ptMaxPosition.y;
443 
444             GetNHApp()->regMainLeft = wp.rcNormalPosition.left;
445             GetNHApp()->regMainTop = wp.rcNormalPosition.top;
446             GetNHApp()->regMainRight = wp.rcNormalPosition.right;
447             GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom;
448         }
449         break;
450     }
451     case WM_SETFOCUS:
452         /* if there is a menu window out there -
453            transfer input focus to it */
454         if (IsWindow(GetNHApp()->hPopupWnd)) {
455             SetFocus(GetNHApp()->hPopupWnd);
456         }
457         break;
458 
459     case WM_CLOSE: {
460         /* exit gracefully */
461         if (g.program_state.gameover) {
462             /* assume the user really meant this, as the game is already
463              * over... */
464             /* to make sure we still save bones, just set stop printing flag
465              */
466             g.program_state.stopprint++;
467             NHEVENT_KBD(
468                 '\033'); /* and send keyboard input as if user pressed ESC */
469             /* additional code for this is done in menu and rip windows */
470         } else if (!g.program_state.something_worth_saving) {
471             /* User exited before the game started, e.g. during splash display
472              */
473             /* Just get out. */
474             bail((char *) 0);
475         } else {
476             /* prompt user for action */
477             switch (NHMessageBox(hWnd, TEXT("Save?"),
478                                  MB_YESNOCANCEL | MB_ICONQUESTION)) {
479             case IDYES:
480 #ifdef SAFERHANGUP
481                 /* destroy popup window - it has its own loop and we need to
482                 return control to NetHack core at this point */
483                 if (IsWindow(GetNHApp()->hPopupWnd))
484                     SendMessage(GetNHApp()->hPopupWnd, WM_COMMAND, IDCANCEL,
485                                 0);
486 
487                 /* tell NetHack core that "hangup" is requested */
488                 hangup(1);
489 #else
490                 NHEVENT_KBD('y');
491                 dosave();
492 #endif
493                 break;
494             case IDNO:
495                 NHEVENT_KBD('q');
496                 done(QUIT);
497                 break;
498             case IDCANCEL:
499                 break;
500             }
501         }
502     }
503         return 0;
504 
505     case WM_DESTROY:
506         /* apparently we never get here
507            TODO: work on exit routines - need to send
508            WM_QUIT somehow */
509 
510         /* clean up */
511         free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA));
512         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
513 
514         // PostQuitMessage(0);
515         exit(1);
516         break;
517 
518     case WM_DPICHANGED: {
519         mswin_layout_main_window(NULL);
520     } break;
521 
522     default:
523         return DefWindowProc(hWnd, message, wParam, lParam);
524     }
525     return 0;
526 }
527 
528 void
onMSNHCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)529 onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
530 {
531     UNREFERENCED_PARAMETER(hWnd);
532     UNREFERENCED_PARAMETER(wParam);
533     UNREFERENCED_PARAMETER(lParam);
534 
535     switch (wParam) {
536     /* new window was just added */
537     case MSNH_MSG_ADDWND: {
538         PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd) lParam;
539         HWND child;
540 
541         if (GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP)
542             mswin_select_map_mode(iflags.wc_map_mode);
543 
544         child = GetNHApp()->windowlist[msg_param->wid].win;
545     } break;
546 
547     case MSNH_MSG_RANDOM_INPUT: {
548         nhassert(iflags.debug_fuzzer);
549         NHEVENT_KBD(randomkey());
550     } break;
551 
552     }
553 }
554 
555 /* adjust windows to fit main window layout
556    ---------------------------
557    |        Status           |
558    +-------------------------+
559    |                         |
560    |                         |
561    |          MAP            |
562    |                         |
563    |                         |
564    +-------------------------+
565    |       Messages          |
566    ---------------------------
567 */
568 void
mswin_layout_main_window(HWND changed_child)569 mswin_layout_main_window(HWND changed_child)
570 {
571     winid i;
572     RECT client_rt, wnd_rect;
573     POINT status_org;
574     SIZE status_size;
575     POINT msg_org;
576     SIZE msg_size;
577     POINT map_org;
578     SIZE map_size;
579     SIZE menu_size;
580     HWND wnd_status, wnd_msg;
581     PNHMainWindow data;
582 
583     if (GetNHApp()->bAutoLayout) {
584         GetClientRect(GetNHApp()->hMainWnd, &client_rt);
585         data = (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd,
586                                                 GWLP_USERDATA);
587 
588         /* get sizes of child windows */
589         wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
590         if (IsWindow(wnd_status)) {
591             mswin_status_window_size(wnd_status, &status_size);
592         } else {
593             status_size.cx = status_size.cy = 0;
594         }
595 
596         wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
597         if (IsWindow(wnd_msg)) {
598             mswin_message_window_size(wnd_msg, &msg_size);
599         } else {
600             msg_size.cx = msg_size.cy = 0;
601         }
602 
603         /* find all menu windows and calculate the size */
604         menu_size.cx = menu_size.cy = 0;
605         for (i = 0; i < MAXWINDOWS; i++) {
606             SIZE tmp_size;
607             if (GetNHApp()->windowlist[i].win
608                 && !GetNHApp()->windowlist[i].dead
609                 && GetNHApp()->windowlist[i].type == NHW_MENU) {
610                 mswin_menu_window_size(GetNHApp()->windowlist[i].win,
611                                        &tmp_size);
612                 menu_size.cx = max(menu_size.cx, tmp_size.cx);
613                 menu_size.cy = max(menu_size.cy, tmp_size.cy);
614             }
615         }
616 
617         /* set window positions */
618         SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right,
619                 client_rt.bottom);
620         switch (iflags.wc_align_status) {
621         case ALIGN_LEFT:
622             status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
623             status_size.cy =
624                 (wnd_rect.bottom - wnd_rect.top); // that won't look good
625             status_org.x = wnd_rect.left;
626             status_org.y = wnd_rect.top;
627             wnd_rect.left += status_size.cx;
628             break;
629 
630         case ALIGN_RIGHT:
631             status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
632             status_size.cy =
633                 (wnd_rect.bottom - wnd_rect.top); // that won't look good
634             status_org.x = wnd_rect.right - status_size.cx;
635             status_org.y = wnd_rect.top;
636             wnd_rect.right -= status_size.cx;
637             break;
638 
639         case ALIGN_TOP:
640             status_size.cx = (wnd_rect.right - wnd_rect.left);
641             status_org.x = wnd_rect.left;
642             status_org.y = wnd_rect.top;
643             wnd_rect.top += status_size.cy;
644             break;
645 
646         case ALIGN_BOTTOM:
647         default:
648             status_size.cx = (wnd_rect.right - wnd_rect.left);
649             status_org.x = wnd_rect.left;
650             status_org.y = wnd_rect.bottom - status_size.cy;
651             wnd_rect.bottom -= status_size.cy;
652             break;
653         }
654 
655         switch (iflags.wc_align_message) {
656         case ALIGN_LEFT:
657             msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
658             msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
659             msg_org.x = wnd_rect.left;
660             msg_org.y = wnd_rect.top;
661             wnd_rect.left += msg_size.cx;
662             break;
663 
664         case ALIGN_RIGHT:
665             msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
666             msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
667             msg_org.x = wnd_rect.right - msg_size.cx;
668             msg_org.y = wnd_rect.top;
669             wnd_rect.right -= msg_size.cx;
670             break;
671 
672         case ALIGN_TOP:
673             msg_size.cx = (wnd_rect.right - wnd_rect.left);
674             msg_org.x = wnd_rect.left;
675             msg_org.y = wnd_rect.top;
676             wnd_rect.top += msg_size.cy;
677             break;
678 
679         case ALIGN_BOTTOM:
680         default:
681             msg_size.cx = (wnd_rect.right - wnd_rect.left);
682             msg_org.x = wnd_rect.left;
683             msg_org.y = wnd_rect.bottom - msg_size.cy;
684             wnd_rect.bottom -= msg_size.cy;
685             break;
686         }
687 
688         /* map window */
689         map_org.x = wnd_rect.left;
690         map_org.y = wnd_rect.top;
691         map_size.cx = wnd_rect.right - wnd_rect.left;
692         map_size.cy = wnd_rect.bottom - wnd_rect.top;
693 
694         GetNHApp()->rtStatusWindow.left = status_org.x;
695         GetNHApp()->rtStatusWindow.top = status_org.y;
696         GetNHApp()->rtStatusWindow.right = status_org.x + status_size.cx;
697         GetNHApp()->rtStatusWindow.bottom = status_org.y + status_size.cy;
698 
699         GetNHApp()->rtTextWindow.left = map_org.x;
700         GetNHApp()->rtTextWindow.top = map_org.y;
701         GetNHApp()->rtTextWindow.right =
702             map_org.x + (wnd_rect.right - wnd_rect.left);
703         GetNHApp()->rtTextWindow.bottom = map_org.y + map_size.cy;
704 
705         GetNHApp()->rtMapWindow.left = map_org.x;
706         GetNHApp()->rtMapWindow.top = map_org.y;
707         GetNHApp()->rtMapWindow.right = map_org.x + map_size.cx;
708         GetNHApp()->rtMapWindow.bottom = map_org.y + map_size.cy;
709 
710         GetNHApp()->rtMsgWindow.left = msg_org.x;
711         GetNHApp()->rtMsgWindow.top = msg_org.y;
712         GetNHApp()->rtMsgWindow.right = msg_org.x + msg_size.cx;
713         GetNHApp()->rtMsgWindow.bottom = msg_org.y + msg_size.cy;
714 
715         /*  map_width/4 < menu_width < map_width*2/3 */
716         GetNHApp()->rtMenuWindow.left =
717             GetNHApp()->rtMapWindow.right
718             - min(map_size.cx * 2 / 3, max(map_size.cx / 4, menu_size.cx));
719         GetNHApp()->rtMenuWindow.top = GetNHApp()->rtMapWindow.top;
720         GetNHApp()->rtMenuWindow.right = GetNHApp()->rtMapWindow.right;
721         GetNHApp()->rtMenuWindow.bottom = GetNHApp()->rtMapWindow.bottom;
722 
723         GetNHApp()->rtInvenWindow.left = GetNHApp()->rtMenuWindow.left;
724         GetNHApp()->rtInvenWindow.top = GetNHApp()->rtMenuWindow.top;
725         GetNHApp()->rtInvenWindow.right = GetNHApp()->rtMenuWindow.right;
726         GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom;
727 
728         /* adjust map window size only if perm_invent is set */
729         if (iflags.perm_invent)
730             GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left;
731     }
732 
733     /* go through the windows list and adjust sizes */
734     for (i = 0; i < MAXWINDOWS; i++) {
735         if (GetNHApp()->windowlist[i].win
736             && !GetNHApp()->windowlist[i].dead) {
737             RECT rt;
738             /* kludge - inventory window should have its own type (same as
739                menu-text
740                as a matter of fact) */
741             if (iflags.perm_invent && i == WIN_INVEN) {
742                 mswin_get_window_placement(NHW_INVEN, &rt);
743             } else {
744                 mswin_get_window_placement(GetNHApp()->windowlist[i].type,
745                                            &rt);
746             }
747 
748             MoveWindow(GetNHApp()->windowlist[i].win, rt.left, rt.top,
749                        rt.right - rt.left, rt.bottom - rt.top, TRUE);
750         }
751     }
752     if (IsWindow(changed_child))
753         SetForegroundWindow(changed_child);
754 }
755 
FuzzTimerProc(_In_ HWND hwnd,_In_ UINT uMsg,_In_ UINT_PTR idEvent,_In_ DWORD dwTime)756 VOID CALLBACK FuzzTimerProc(
757 	_In_ HWND     hwnd,
758 	_In_ UINT     uMsg,
759 	_In_ UINT_PTR idEvent,
760 	_In_ DWORD    dwTime
761 	)
762 {
763 	INPUT input[16];
764 	int i_pos = 0;
765 	int c = randomkey();
766 	SHORT k = VkKeyScanA(c);
767 	BOOL gen_alt = (rn2(50) == 0) && isalpha(c);
768 
769 	if (!iflags.debug_fuzzer) {
770 		KillTimer(hwnd, IDT_FUZZ_TIMER);
771 		return;
772 	}
773 
774 	if (!GetFocus())
775             return;
776 
777 	ZeroMemory(input, sizeof(input));
778 	if (gen_alt) {
779 		input[i_pos].type = INPUT_KEYBOARD;
780 		input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
781 		input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
782 		i_pos++;
783 	}
784 
785 	if (HIBYTE(k) & 1) {
786 		input[i_pos].type = INPUT_KEYBOARD;
787 		input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
788 		input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
789 		i_pos++;
790 	}
791 
792 	input[i_pos].type = INPUT_KEYBOARD;
793 	input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
794 	input[i_pos].ki.wScan = MapVirtualKey(LOBYTE(k), 0);
795 	i_pos++;
796 
797 	if (HIBYTE(k) & 1) {
798 		input[i_pos].type = INPUT_KEYBOARD;
799 		input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
800 		input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
801 		i_pos++;
802 	}
803 	if (gen_alt) {
804 		input[i_pos].type = INPUT_KEYBOARD;
805 		input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
806 		input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
807 		i_pos++;
808 	}
809 	SendInput(i_pos, input, sizeof(input[0]));
810 }
811 
812 LRESULT
onWMCommand(HWND hWnd,WPARAM wParam,LPARAM lParam)813 onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
814 {
815     int wmId, wmEvent;
816     PNHMainWindow data;
817 
818     UNREFERENCED_PARAMETER(lParam);
819 
820     data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
821     wmId = LOWORD(wParam);
822     wmEvent = HIWORD(wParam);
823 
824     // Parse the menu selections:
825     switch (wmId) {
826     case IDM_ABOUT:
827         mswin_display_splash_window(TRUE);
828         break;
829 
830     case IDM_FUZZ:
831         if (iflags.debug_fuzzer)
832             KillTimer(hWnd, IDT_FUZZ_TIMER);
833         else
834             SetTimer(hWnd, IDT_FUZZ_TIMER, 10, FuzzTimerProc);
835         iflags.debug_fuzzer = !iflags.debug_fuzzer;
836         break;
837     case IDM_EXIT:
838         if (iflags.debug_fuzzer)
839             break;
840         done2();
841         break;
842 
843     case IDM_SAVE:
844         if (iflags.debug_fuzzer)
845             break;
846         if (!g.program_state.gameover && !g.program_state.done_hup)
847             dosave();
848         else
849             MessageBeep(0);
850         break;
851 
852     case IDM_MAP_TILES:
853     case IDM_MAP_ASCII4X6:
854     case IDM_MAP_ASCII6X8:
855     case IDM_MAP_ASCII8X8:
856     case IDM_MAP_ASCII16X8:
857     case IDM_MAP_ASCII7X12:
858     case IDM_MAP_ASCII8X12:
859     case IDM_MAP_ASCII12X16:
860     case IDM_MAP_ASCII16X12:
861     case IDM_MAP_ASCII10X18:
862         mswin_select_map_mode(menuid2mapmode(wmId));
863         break;
864 
865     case IDM_MAP_FIT_TO_SCREEN:
866         if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
867             mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
868                                       ? data->mapAcsiiModeSave
869                                       : MAP_MODE_TILES);
870         } else {
871             mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
872                                       ? MAP_MODE_ASCII_FIT_TO_SCREEN
873                                       : MAP_MODE_TILES_FIT_TO_SCREEN);
874         }
875         break;
876 
877     case IDM_SETTING_SCREEN_TO_CLIPBOARD: {
878         char *p;
879         size_t len;
880         HANDLE hglbCopy;
881         char *p_copy;
882 
883         p = nh_compose_ascii_screenshot();
884         if (!p)
885             return 0;
886         len = strlen(p);
887 
888         if (!OpenClipboard(hWnd)) {
889             NHMessageBox(hWnd, TEXT("Cannot open clipboard"),
890                          MB_OK | MB_ICONERROR);
891             free(p);
892             return 0;
893         }
894 
895         EmptyClipboard();
896 
897         hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char));
898         if (hglbCopy == NULL) {
899             CloseClipboard();
900             free(p);
901             return FALSE;
902         }
903 
904         p_copy = (char *) GlobalLock(hglbCopy);
905         strncpy(p_copy, p, len);
906         p_copy[len] = 0; // null character
907         GlobalUnlock(hglbCopy);
908 
909         SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy);
910 
911         CloseClipboard();
912 
913         free(p);
914     } break;
915 
916     case IDM_SETTING_SCREEN_TO_FILE: {
917         OPENFILENAME ofn;
918         TCHAR filename[1024];
919         TCHAR whackdir[MAX_PATH];
920         FILE *pFile;
921         char *text;
922         wchar_t *wtext;
923         int tlen = 0;
924 
925         if (iflags.debug_fuzzer)
926             break;
927 
928         ZeroMemory(filename, sizeof(filename));
929         ZeroMemory(&ofn, sizeof(ofn));
930         ofn.lStructSize = sizeof(OPENFILENAME);
931         ofn.hwndOwner = hWnd;
932         ofn.hInstance = GetNHApp()->hApp;
933         ofn.lpstrFilter = TEXT("Text Files (*.txt)\x0*.txt\x0")
934             TEXT("All Files (*.*)\x0*.*\x0") TEXT("\x0\x0");
935         ofn.lpstrCustomFilter = NULL;
936         ofn.nMaxCustFilter = 0;
937         ofn.nFilterIndex = 1;
938         ofn.lpstrFile = filename;
939         ofn.nMaxFile = SIZE(filename);
940         ofn.lpstrFileTitle = NULL;
941         ofn.nMaxFileTitle = 0;
942         ofn.lpstrInitialDir = NH_A2W(g.hackdir, whackdir, MAX_PATH);
943         ofn.lpstrTitle = NULL;
944         ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
945         ofn.nFileOffset = 0;
946         ofn.nFileExtension = 0;
947         ofn.lpstrDefExt = TEXT("txt");
948         ofn.lCustData = 0;
949         ofn.lpfnHook = 0;
950         ofn.lpTemplateName = 0;
951 
952         if (!GetSaveFileName(&ofn))
953             return FALSE;
954 
955         text = nh_compose_ascii_screenshot();
956         if (!text)
957             return FALSE;
958 
959         pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8"));
960         if (!pFile) {
961             TCHAR buf[4096];
962             _stprintf(buf, TEXT("Cannot open %s for writing!"), filename);
963             NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR);
964             free(text);
965             return FALSE;
966         }
967 
968         tlen = strlen(text);
969         wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t));
970         if (!wtext)
971             panic("out of memory");
972         MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen);
973         fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile);
974         fclose(pFile);
975         free(text);
976         free(wtext);
977     } break;
978 
979     case IDM_NHMODE: {
980         GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1;
981         mswin_menu_check_intf_mode();
982         mswin_apply_window_style_all();
983         break;
984     }
985     case IDM_CLEARSETTINGS: {
986         mswin_destroy_reg();
987         /* Notify the user that windows settings will not be saved this time.
988          */
989         NHMessageBox(GetNHApp()->hMainWnd,
990                      TEXT("Your Windows Settings will not be stored when you "
991                           "exit this time."),
992                      MB_OK | MB_ICONINFORMATION);
993         break;
994     }
995 
996     case IDM_SETTING_AUTOLAYOUT:
997         GetNHApp()->bAutoLayout = !GetNHApp()->bAutoLayout;
998         mswin_layout_main_window(NULL);
999 
1000         /* Update menu item check-mark */
1001         CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_AUTOLAYOUT,
1002                       GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
1003         break;
1004 
1005     case IDM_SETTING_LOCKWINDOWS:
1006         nhlock_windows(!GetNHApp()->bWindowsLocked);
1007         break;
1008 
1009     case IDM_HELP_LONG:
1010         display_file(HELP, TRUE);
1011         break;
1012 
1013     case IDM_HELP_COMMANDS:
1014         display_file(SHELP, TRUE);
1015         break;
1016 
1017     case IDM_HELP_HISTORY:
1018         (void) dohistory();
1019         break;
1020 
1021     case IDM_HELP_INFO_CHAR:
1022         (void) dowhatis();
1023         break;
1024 
1025     case IDM_HELP_INFO_KEY:
1026         (void) dowhatdoes();
1027         break;
1028 
1029     case IDM_HELP_OPTIONS:
1030         option_help();
1031         break;
1032 
1033     case IDM_HELP_OPTIONS_LONG:
1034         display_file(OPTIONFILE, TRUE);
1035         break;
1036 
1037     case IDM_HELP_EXTCMD:
1038         (void) doextlist();
1039         break;
1040 
1041     case IDM_HELP_LICENSE:
1042         display_file(LICENSE, TRUE);
1043         break;
1044 
1045     case IDM_HELP_PORTHELP:
1046         display_file(PORT_HELP, TRUE);
1047         break;
1048 
1049     default:
1050         return 1;
1051     }
1052     return 0;
1053 }
1054 
1055 // Mesage handler for about box.
1056 LRESULT CALLBACK
About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1057 About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1058 {
1059     char buf[BUFSZ];
1060     TCHAR wbuf[BUFSZ];
1061     RECT main_rt, dlg_rt;
1062     SIZE dlg_sz;
1063 
1064     UNREFERENCED_PARAMETER(lParam);
1065 
1066     switch (message) {
1067     case WM_INITDIALOG:
1068         getversionstring(buf);
1069         SetDlgItemText(hDlg, IDC_ABOUT_VERSION,
1070                        NH_A2W(buf, wbuf, sizeof(wbuf)));
1071 
1072         Sprintf(buf, "%s\n%s\n%s\n%s",
1073                 COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B,
1074                 COPYRIGHT_BANNER_C, COPYRIGHT_BANNER_D);
1075         SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
1076                        NH_A2W(buf, wbuf, sizeof(wbuf)));
1077 
1078         /* center dialog in the main window */
1079         GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
1080         GetWindowRect(hDlg, &dlg_rt);
1081         dlg_sz.cx = dlg_rt.right - dlg_rt.left;
1082         dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
1083 
1084         dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
1085         dlg_rt.right = dlg_rt.left + dlg_sz.cx;
1086         dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
1087         dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
1088         MoveWindow(hDlg, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
1089                    (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
1090                    dlg_sz.cy, TRUE);
1091 
1092         return TRUE;
1093 
1094     case WM_COMMAND:
1095         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
1096             EndDialog(hDlg, LOWORD(wParam));
1097             return TRUE;
1098         }
1099         break;
1100     }
1101     return FALSE;
1102 }
1103 
1104 void
mswin_menu_check_intf_mode(void)1105 mswin_menu_check_intf_mode(void)
1106 {
1107     HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
1108 
1109     if (GetNHApp()->regNetHackMode)
1110         CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
1111     else
1112         CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
1113 }
1114 
1115 void
mswin_select_map_mode(int mode)1116 mswin_select_map_mode(int mode)
1117 {
1118     PNHMainWindow data;
1119     winid map_id;
1120 
1121     map_id = WIN_MAP;
1122     data =
1123         (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd, GWLP_USERDATA);
1124 
1125     /* set map mode menu mark */
1126     if (IS_MAP_ASCII(mode)) {
1127         CheckMenuRadioItem(
1128             GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18,
1129             mapmode2menuid(IS_MAP_FIT_TO_SCREEN(mode) ? data->mapAcsiiModeSave
1130                                                       : mode),
1131             MF_BYCOMMAND);
1132     } else {
1133         CheckMenuRadioItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES,
1134                            IDM_MAP_ASCII10X18, mapmode2menuid(MAP_MODE_TILES),
1135                            MF_BYCOMMAND);
1136     }
1137 
1138     /* set fit-to-screen mode mark */
1139     CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_FIT_TO_SCREEN,
1140                   MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode) ? MF_CHECKED
1141                                                              : MF_UNCHECKED));
1142 
1143     if (IS_MAP_ASCII(iflags.wc_map_mode)
1144         && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
1145         data->mapAcsiiModeSave = iflags.wc_map_mode;
1146     }
1147 
1148     iflags.wc_map_mode = mode;
1149 
1150     /*
1151     ** first, check if WIN_MAP has been inialized.
1152     ** If not - attempt to retrieve it by type, then check it again
1153     */
1154     if (map_id == WIN_ERR)
1155         map_id = mswin_winid_from_type(NHW_MAP);
1156     if (map_id != WIN_ERR)
1157         mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
1158 }
1159 
1160 static struct t_menu2mapmode {
1161     int menuID;
1162     int mapMode;
1163 } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES },
1164                       { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
1165                       { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
1166                       { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
1167                       { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
1168                       { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
1169                       { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
1170                       { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
1171                       { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
1172                       { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
1173                       { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
1174                       { -1, -1 } };
1175 
1176 int
menuid2mapmode(int menuid)1177 menuid2mapmode(int menuid)
1178 {
1179     struct t_menu2mapmode *p;
1180     for (p = _menu2mapmode; p->mapMode != -1; p++)
1181         if (p->menuID == menuid)
1182             return p->mapMode;
1183     return -1;
1184 }
1185 
1186 int
mapmode2menuid(int map_mode)1187 mapmode2menuid(int map_mode)
1188 {
1189     struct t_menu2mapmode *p;
1190     for (p = _menu2mapmode; p->mapMode != -1; p++)
1191         if (p->mapMode == map_mode)
1192             return p->menuID;
1193     return -1;
1194 }
1195 
1196 void
nhlock_windows(BOOL lock)1197 nhlock_windows(BOOL lock)
1198 {
1199     /* update menu */
1200     GetNHApp()->bWindowsLocked = lock;
1201     CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_LOCKWINDOWS,
1202                   MF_BYCOMMAND | (lock ? MF_CHECKED : MF_UNCHECKED));
1203 
1204     /* restyle windows */
1205     mswin_apply_window_style_all();
1206 }
1207 
1208 void
mswin_apply_window_style(HWND hwnd)1209 mswin_apply_window_style(HWND hwnd) {
1210     DWORD style = 0, exstyle = 0;
1211 
1212     style = GetWindowLong(hwnd, GWL_STYLE);
1213     exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
1214 
1215     if( !GetNHApp()->bWindowsLocked ) {
1216         style = WS_CHILD|WS_CLIPSIBLINGS|WS_CAPTION|WS_SIZEBOX|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1217         exstyle = WS_EX_WINDOWEDGE;
1218     } else if (GetNHApp()->regNetHackMode) {
1219         /* do away borders */
1220         style = WS_CHILD|WS_CLIPSIBLINGS|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1221         exstyle = 0;
1222     } else {
1223         style = WS_CHILD|WS_CLIPSIBLINGS|WS_THICKFRAME|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
1224         exstyle = WS_EX_WINDOWEDGE;
1225     }
1226 
1227     SetWindowLong(hwnd, GWL_STYLE, style);
1228     SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
1229     SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
1230                  SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
1231 }
1232 
1233 void
mswin_apply_window_style_all(void)1234 mswin_apply_window_style_all(void)
1235 {
1236     int i;
1237     for (i = 0; i < MAXWINDOWS; i++) {
1238         if (IsWindow(GetNHApp()->windowlist[i].win)
1239             && !GetNHApp()->windowlist[i].dead) {
1240             mswin_apply_window_style(GetNHApp()->windowlist[i].win);
1241         }
1242     }
1243     mswin_layout_main_window(NULL);
1244 }
1245 
1246 // returns strdup() created pointer - callee assumes the ownership
1247 char *
nh_compose_ascii_screenshot(void)1248 nh_compose_ascii_screenshot(void)
1249 {
1250     char *retval;
1251     PMSNHMsgGetText text;
1252 
1253     retval = (char *) malloc(3 * TEXT_BUFFER_SIZE);
1254 
1255     text =
1256         (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE);
1257     text->max_size =
1258         TEXT_BUFFER_SIZE
1259         - 1; /* make sure we always have 0 at the end of the buffer */
1260 
1261     ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1262     SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
1263                 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1264     strcpy(retval, text->buffer);
1265 
1266     ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1267     SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND,
1268                 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1269     strcat(retval, text->buffer);
1270 
1271     ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
1272     SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
1273                 (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
1274     strcat(retval, text->buffer);
1275 
1276     free(text);
1277     return retval;
1278 }
1279