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