1 /* NetHack 3.6 mswproc.c $NHDT-Date: 1433806606 2015/06/08 23:36:46 $ $NHDT-Branch: master $:$NHDT-Revision: 1.60 $ */
2 /* Copyright (C) 2001 by Alex Kompel */
3 /* NetHack may be freely redistributed. See license for details. */
6 * This file implements the interface between the window port specific
7 * code in the mswin port and the rest of the nethack game engine.
31 extern void logDebug(const char *fmt, ...);
34 logDebug(const char *fmt, ...)
39 static void mswin_main_loop();
40 static BOOL initMapTiles(void);
41 static void prompt_for_player_selection(void);
43 /* Interface definition, for windows.c */
44 struct window_procs mswin_procs = {
46 WC_COLOR | WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_INVERSE
47 | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS
48 | WC_FONT_MENU | WC_FONT_TEXT | WC_FONT_MAP | WC_FONTSIZ_MESSAGE
49 | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT
50 | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE | WC_VARY_MSGCOUNT
51 | WC_WINDOWCOLORS | WC_PLAYER_SELECTION,
52 WC2_FULLSCREEN | WC2_SOFTKEYBOARD | WC2_WRAPTEXT, mswin_init_nhwindows,
53 mswin_player_selection, mswin_askname, mswin_get_nh_event,
54 mswin_exit_nhwindows, mswin_suspend_nhwindows, mswin_resume_nhwindows,
55 mswin_create_nhwindow, mswin_clear_nhwindow, mswin_display_nhwindow,
56 mswin_destroy_nhwindow, mswin_curs, mswin_putstr, genl_putmixed,
57 mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu,
59 genl_message_menu, /* no need for X-specific handling */
60 mswin_update_inventory, mswin_mark_synch, mswin_wait_synch,
67 mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch,
68 mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function,
69 mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output,
70 #ifdef CHANGE_COLOR /* only a Mac option currently */
71 mswin, mswin_change_background,
73 /* other defs that really should go away (they're tty specific) */
74 mswin_start_screen, mswin_end_screen, mswin_outrip,
75 mswin_preference_update, genl_getmsghistory, genl_putmsghistory,
76 genl_status_init, genl_status_finish, genl_status_enablefield,
82 init_nhwindows(int* argcp, char** argv)
83 -- Initialize the windows used by NetHack. This can also
84 create the standard windows listed at the top, but does
86 -- Any commandline arguments relevant to the windowport
87 should be interpreted, and *argcp and *argv should
88 be changed to remove those arguments.
89 -- When the message window is created, the variable
90 iflags.window_inited needs to be set to TRUE. Otherwise
91 all plines() will be done via raw_print().
92 ** Why not have init_nhwindows() create all of the "standard"
93 ** windows? Or at least all but WIN_INFO? -dean
96 mswin_init_nhwindows(int *argc, char **argv)
99 logDebug("mswin_init_nhwindows()\n");
103 /* truncate trace file */
104 FILE *dfp = fopen("nhtrace.log", "w");
109 /* intialize input subsystem */
110 mswin_nh_input_init();
112 /* read registry settings */
115 /* set it to WIN_ERR so we can detect attempts to
116 use this ID before it is inialized */
119 /* check default values */
120 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
121 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
122 iflags.wc_fontsiz_status = NHFONT_STATUS_DEFAULT_SIZE;
124 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
125 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
126 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
128 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
129 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
130 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
132 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
133 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
134 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
136 if (iflags.wc_align_message == 0)
137 iflags.wc_align_message = ALIGN_BOTTOM;
138 if (iflags.wc_align_status == 0)
139 iflags.wc_align_status = ALIGN_TOP;
140 if (iflags.wc_scroll_margin == 0)
141 iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN;
142 if (iflags.wc_tile_width == 0)
143 iflags.wc_tile_width = TILE_X;
144 if (iflags.wc_tile_height == 0)
145 iflags.wc_tile_height = TILE_Y;
147 if (iflags.wc_vary_msgcount == 0)
148 iflags.wc_vary_msgcount = 3;
150 /* force tabs in menus */
151 iflags.menu_tab_sep = 1;
153 /* force toptenwin to be true. toptenwin is the option that decides
155 * write output to a window or stdout. stdout doesn't make sense on
157 * non-console applications
159 iflags.toptenwin = 1;
160 set_option_mod_status("toptenwin", SET_IN_FILE);
162 /* initialize map tiles bitmap */
165 /* set tile-related options to readonly */
166 set_wc_option_mod_status(WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE,
169 /* init color table */
170 mswin_init_color_table();
172 /* set font-related options to change in the game */
173 set_wc_option_mod_status(
174 WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_MARGIN
175 | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU
176 | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS
177 | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT,
181 set_wc2_option_mod_status(WC2_FULLSCREEN | WC2_SOFTKEYBOARD, SET_IN_FILE);
182 GetNHApp()->bFullScreen = iflags.wc2_fullscreen;
183 GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
185 set_wc2_option_mod_status(WC2_WRAPTEXT, SET_IN_GAME);
186 GetNHApp()->bWrapText = iflags.wc2_wraptext;
188 /* create the main nethack window */
189 hWnd = mswin_init_main_window();
191 panic("Cannot create the main window.");
192 ShowWindow(hWnd, GetNHApp()->nCmdShow);
194 GetNHApp()->hMainWnd = hWnd;
196 /* set Full screen if requested */
197 mswin_set_fullscreen(GetNHApp()->bFullScreen);
199 /* let nethack code know that the window subsystem is ready */
200 iflags.window_inited = TRUE;
203 /* Do a window-port specific player type selection. If player_selection()
204 offers a Quit option, it is its responsibility to clean up and terminate
205 the process. You need to fill in pl_character[0].
208 mswin_player_selection(void)
210 logDebug("mswin_player_selection()\n");
212 #if defined(WIN_CE_SMARTPHONE)
213 /* SmartPhone does not supprt combo-boxes therefor we cannot
214 use dialog for player selection */
215 prompt_for_player_selection();
217 if (iflags.wc_player_selection == VIA_DIALOG) {
220 /* pick player type randomly (use pre-selected
221 * role/race/gender/alignment) */
222 if (flags.randomall) {
223 if (flags.initrole < 0) {
224 flags.initrole = pick_role(flags.initrace, flags.initgend,
225 flags.initalign, PICK_RANDOM);
226 if (flags.initrole < 0) {
227 raw_print("Incompatible role!");
228 flags.initrole = randrole(FALSE);
232 if (flags.initrace < 0
233 || !validrace(flags.initrole, flags.initrace)) {
234 flags.initrace = pick_race(flags.initrole, flags.initgend,
235 flags.initalign, PICK_RANDOM);
236 if (flags.initrace < 0) {
237 raw_print("Incompatible race!");
238 flags.initrace = randrace(flags.initrole);
242 if (flags.initgend < 0
243 || !validgend(flags.initrole, flags.initrace,
245 flags.initgend = pick_gend(flags.initrole, flags.initrace,
246 flags.initalign, PICK_RANDOM);
247 if (flags.initgend < 0) {
248 raw_print("Incompatible gender!");
249 flags.initgend = randgend(flags.initrole, flags.initrace);
253 if (flags.initalign < 0
254 || !validalign(flags.initrole, flags.initrace,
256 flags.initalign = pick_align(flags.initrole, flags.initrace,
257 flags.initgend, PICK_RANDOM);
258 if (flags.initalign < 0) {
259 raw_print("Incompatible alignment!");
261 randalign(flags.initrole, flags.initrace);
266 if (mswin_player_selection_window(&nRole) == IDCANCEL) {
270 } else { /* iflags.wc_player_selection == VIA_PROMPTS */
271 prompt_for_player_selection();
273 #endif /* defined(WIN_CE_SMARTPHONE) */
277 prompt_for_player_selection(void)
280 char pick4u = 'n', thisch, lastch = 0;
281 char pbuf[QBUFSZ], plbuf[QBUFSZ];
284 menu_item *selected = 0;
288 logDebug("prompt_for_player_selection()\n");
290 /* prevent an unnecessary prompt */
293 /* Should we randomly pick for the player? */
295 && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE
296 || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) {
298 char *prompt = build_plselection_prompt(
299 pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend,
302 /* tty_putstr(BASE_WINDOW, 0, ""); */
303 /* echoline = wins[BASE_WINDOW]->cury; */
304 box_result = MessageBox(NULL, NH_A2W(prompt, wbuf, BUFSZ),
305 TEXT("NetHack for Windows"),
306 #if defined(WIN_CE_SMARTPHONE)
307 MB_YESNO | MB_DEFBUTTON1
309 MB_YESNOCANCEL | MB_DEFBUTTON1
314 (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033';
315 /* tty_putstr(BASE_WINDOW, 0, prompt); */
317 /* pick4u = lowc(readchar()); */
318 if (index(quitchars, pick4u))
320 } while (!index(ynqchars, pick4u));
321 if ((int) strlen(prompt) + 1 < CO) {
322 /* Echo choice and move back down line */
323 /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline,
325 /* tty_putstr(BASE_WINDOW, 0, ""); */
327 /* Otherwise it's hard to tell where to echo, and things are
328 * wrapping a bit messily anyway, so (try to) make sure the next
329 * question shows up well and doesn't get wrapped at the
330 * bottom of the window.
332 /* tty_clear_nhwindow(BASE_WINDOW) */;
334 if (pick4u != 'y' && pick4u != 'n') {
337 free((genericptr_t) selected);
344 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
345 flags.initrace, flags.initgend,
348 /* Select a role, if necessary */
349 /* we'll try to be compatible with pre-selected race/gender/alignment,
350 * but may not succeed */
351 if (flags.initrole < 0) {
352 char rolenamebuf[QBUFSZ];
353 /* Process the choice */
354 if (pick4u == 'y' || flags.initrole == ROLE_RANDOM
355 || flags.randomall) {
356 /* Pick a random role */
357 flags.initrole = pick_role(flags.initrace, flags.initgend,
358 flags.initalign, PICK_RANDOM);
359 if (flags.initrole < 0) {
360 /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */
361 flags.initrole = randrole(FALSE);
364 /* tty_clear_nhwindow(BASE_WINDOW); */
365 /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */
366 /* Prompt for a role */
367 win = create_nhwindow(NHW_MENU);
369 any.a_void = 0; /* zero out all bits */
370 for (i = 0; roles[i].name.m; i++) {
371 if (ok_role(i, flags.initrace, flags.initgend,
373 any.a_int = i + 1; /* must be non-zero */
374 thisch = lowc(roles[i].name.m[0]);
375 if (thisch == lastch)
376 thisch = highc(thisch);
377 if (flags.initgend != ROLE_NONE
378 && flags.initgend != ROLE_RANDOM) {
379 if (flags.initgend == 1 && roles[i].name.f)
380 Strcpy(rolenamebuf, roles[i].name.f);
382 Strcpy(rolenamebuf, roles[i].name.m);
384 if (roles[i].name.f) {
385 Strcpy(rolenamebuf, roles[i].name.m);
386 Strcat(rolenamebuf, "/");
387 Strcat(rolenamebuf, roles[i].name.f);
389 Strcpy(rolenamebuf, roles[i].name.m);
391 add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE,
392 an(rolenamebuf), MENU_UNSELECTED);
396 any.a_int = pick_role(flags.initrace, flags.initgend,
397 flags.initalign, PICK_RANDOM) + 1;
398 if (any.a_int == 0) /* must be non-zero */
399 any.a_int = randrole(FALSE) + 1;
400 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
402 any.a_int = i + 1; /* must be non-zero */
403 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
405 Sprintf(pbuf, "Pick a role for your %s", plbuf);
407 n = select_menu(win, PICK_ONE, &selected);
408 destroy_nhwindow(win);
410 /* Process the choice */
411 if (n != 1 || selected[0].item.a_int == any.a_int)
412 goto give_up; /* Selected quit */
414 flags.initrole = selected[0].item.a_int - 1;
415 free((genericptr_t) selected), selected = 0;
417 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
418 flags.initrace, flags.initgend,
422 /* Select a race, if necessary */
423 /* force compatibility with role, try for compatibility with
424 * pre-selected gender/alignment */
425 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
426 /* pre-selected race not valid */
427 if (pick4u == 'y' || flags.initrace == ROLE_RANDOM
428 || flags.randomall) {
429 flags.initrace = pick_race(flags.initrole, flags.initgend,
430 flags.initalign, PICK_RANDOM);
431 if (flags.initrace < 0) {
432 /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */
433 flags.initrace = randrace(flags.initrole);
435 } else { /* pick4u == 'n' */
436 /* Count the number of valid races */
437 n = 0; /* number valid */
438 k = 0; /* valid race */
439 for (i = 0; races[i].noun; i++) {
440 if (ok_race(flags.initrole, i, flags.initgend,
447 for (i = 0; races[i].noun; i++) {
448 if (validrace(flags.initrole, i)) {
455 /* Permit the user to pick, if there is more than one */
457 /* tty_clear_nhwindow(BASE_WINDOW); */
458 /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */
459 win = create_nhwindow(NHW_MENU);
461 any.a_void = 0; /* zero out all bits */
462 for (i = 0; races[i].noun; i++)
463 if (ok_race(flags.initrole, i, flags.initgend,
465 any.a_int = i + 1; /* must be non-zero */
466 add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0,
467 ATR_NONE, races[i].noun, MENU_UNSELECTED);
469 any.a_int = pick_race(flags.initrole, flags.initgend,
470 flags.initalign, PICK_RANDOM) + 1;
471 if (any.a_int == 0) /* must be non-zero */
472 any.a_int = randrace(flags.initrole) + 1;
473 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
475 any.a_int = i + 1; /* must be non-zero */
476 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
478 Sprintf(pbuf, "Pick the race of your %s", plbuf);
480 n = select_menu(win, PICK_ONE, &selected);
481 destroy_nhwindow(win);
482 if (n != 1 || selected[0].item.a_int == any.a_int)
483 goto give_up; /* Selected quit */
485 k = selected[0].item.a_int - 1;
486 free((genericptr_t) selected), selected = 0;
490 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
491 flags.initrace, flags.initgend,
495 /* Select a gender, if necessary */
496 /* force compatibility with role/race, try for compatibility with
497 * pre-selected alignment */
498 if (flags.initgend < 0
499 || !validgend(flags.initrole, flags.initrace, flags.initgend)) {
500 /* pre-selected gender not valid */
501 if (pick4u == 'y' || flags.initgend == ROLE_RANDOM
502 || flags.randomall) {
503 flags.initgend = pick_gend(flags.initrole, flags.initrace,
504 flags.initalign, PICK_RANDOM);
505 if (flags.initgend < 0) {
506 /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */
507 flags.initgend = randgend(flags.initrole, flags.initrace);
509 } else { /* pick4u == 'n' */
510 /* Count the number of valid genders */
511 n = 0; /* number valid */
512 k = 0; /* valid gender */
513 for (i = 0; i < ROLE_GENDERS; i++) {
514 if (ok_gend(flags.initrole, flags.initrace, i,
521 for (i = 0; i < ROLE_GENDERS; i++) {
522 if (validgend(flags.initrole, flags.initrace, i)) {
529 /* Permit the user to pick, if there is more than one */
531 /* tty_clear_nhwindow(BASE_WINDOW); */
532 /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */
533 win = create_nhwindow(NHW_MENU);
535 any.a_void = 0; /* zero out all bits */
536 for (i = 0; i < ROLE_GENDERS; i++)
537 if (ok_gend(flags.initrole, flags.initrace, i,
540 add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0,
541 ATR_NONE, genders[i].adj, MENU_UNSELECTED);
543 any.a_int = pick_gend(flags.initrole, flags.initrace,
544 flags.initalign, PICK_RANDOM) + 1;
545 if (any.a_int == 0) /* must be non-zero */
546 any.a_int = randgend(flags.initrole, flags.initrace) + 1;
547 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
549 any.a_int = i + 1; /* must be non-zero */
550 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
552 Sprintf(pbuf, "Pick the gender of your %s", plbuf);
554 n = select_menu(win, PICK_ONE, &selected);
555 destroy_nhwindow(win);
556 if (n != 1 || selected[0].item.a_int == any.a_int)
557 goto give_up; /* Selected quit */
559 k = selected[0].item.a_int - 1;
560 free((genericptr_t) selected), selected = 0;
564 (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole,
565 flags.initrace, flags.initgend,
569 /* Select an alignment, if necessary */
570 /* force compatibility with role/race/gender */
571 if (flags.initalign < 0
572 || !validalign(flags.initrole, flags.initrace, flags.initalign)) {
573 /* pre-selected alignment not valid */
574 if (pick4u == 'y' || flags.initalign == ROLE_RANDOM
575 || flags.randomall) {
576 flags.initalign = pick_align(flags.initrole, flags.initrace,
577 flags.initgend, PICK_RANDOM);
578 if (flags.initalign < 0) {
579 /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */
580 flags.initalign = randalign(flags.initrole, flags.initrace);
582 } else { /* pick4u == 'n' */
583 /* Count the number of valid alignments */
584 n = 0; /* number valid */
585 k = 0; /* valid alignment */
586 for (i = 0; i < ROLE_ALIGNS; i++) {
587 if (ok_align(flags.initrole, flags.initrace, flags.initgend,
594 for (i = 0; i < ROLE_ALIGNS; i++) {
595 if (validalign(flags.initrole, flags.initrace, i)) {
602 /* Permit the user to pick, if there is more than one */
604 /* tty_clear_nhwindow(BASE_WINDOW); */
605 /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */
606 win = create_nhwindow(NHW_MENU);
608 any.a_void = 0; /* zero out all bits */
609 for (i = 0; i < ROLE_ALIGNS; i++)
610 if (ok_align(flags.initrole, flags.initrace,
611 flags.initgend, i)) {
613 add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0,
614 ATR_NONE, aligns[i].adj, MENU_UNSELECTED);
616 any.a_int = pick_align(flags.initrole, flags.initrace,
617 flags.initgend, PICK_RANDOM) + 1;
618 if (any.a_int == 0) /* must be non-zero */
619 any.a_int = randalign(flags.initrole, flags.initrace) + 1;
620 add_menu(win, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random",
622 any.a_int = i + 1; /* must be non-zero */
623 add_menu(win, NO_GLYPH, &any, 'q', 0, ATR_NONE, "Quit",
625 Sprintf(pbuf, "Pick the alignment of your %s", plbuf);
627 n = select_menu(win, PICK_ONE, &selected);
628 destroy_nhwindow(win);
629 if (n != 1 || selected[0].item.a_int == any.a_int)
630 goto give_up; /* Selected quit */
632 k = selected[0].item.a_int - 1;
633 free((genericptr_t) selected), selected = 0;
639 /* tty_display_nhwindow(BASE_WINDOW, FALSE); */
642 /* Ask the user for a player name. */
646 logDebug("mswin_askname()\n");
648 if (mswin_getlin_window("who are you?", plname, PL_NSIZ) == IDCANCEL) {
654 /* Does window event processing (e.g. exposure events).
655 A noop for the tty and X window-ports.
658 mswin_get_nh_event(void)
660 logDebug("mswin_get_nh_event()\n");
664 /* Exits the window system. This should dismiss all windows,
665 except the "window" used for raw_print(). str is printed if possible.
668 mswin_exit_nhwindows(const char *str)
670 logDebug("mswin_exit_nhwindows(%s)\n", str);
672 /* Write Window settings to the registry */
675 // Don't do any of this (?) - exit_nhwindows does not terminate
677 // DestroyWindow(GetNHApp()->hMainWnd);
678 // nh_terminate(EXIT_SUCCESS);
681 /* Prepare the window to be suspended. */
683 mswin_suspend_nhwindows(const char *str)
685 logDebug("mswin_suspend_nhwindows(%s)\n", str);
689 /* Restore the windows after being suspended. */
691 mswin_resume_nhwindows()
693 logDebug("mswin_resume_nhwindows()\n");
697 /* Create a window of type "type" which can be
698 NHW_MESSAGE (top line)
699 NHW_STATUS (bottom lines)
700 NHW_MAP (main dungeon)
701 NHW_MENU (inventory or other "corner" windows)
702 NHW_TEXT (help/text, full screen paged window)
705 mswin_create_nhwindow(int type)
710 logDebug("mswin_create_nhwindow(%d)\n", type);
712 /* Return the next available winid
715 for (i = 1; i < MAXWINDOWS; i++)
716 if (GetNHApp()->windowlist[i].win == NULL
717 && !GetNHApp()->windowlist[i].dead)
720 panic("ERROR: No windows available...\n");
724 GetNHApp()->windowlist[i].win = mswin_init_map_window();
725 GetNHApp()->windowlist[i].type = type;
726 GetNHApp()->windowlist[i].dead = 0;
730 GetNHApp()->windowlist[i].win = mswin_init_message_window();
731 GetNHApp()->windowlist[i].type = type;
732 GetNHApp()->windowlist[i].dead = 0;
736 GetNHApp()->windowlist[i].win = mswin_init_status_window();
737 GetNHApp()->windowlist[i].type = type;
738 GetNHApp()->windowlist[i].dead = 0;
742 GetNHApp()->windowlist[i].win = NULL; // will create later
743 GetNHApp()->windowlist[i].type = type;
744 GetNHApp()->windowlist[i].dead = 1;
748 GetNHApp()->windowlist[i].win = mswin_init_text_window();
749 GetNHApp()->windowlist[i].type = type;
750 GetNHApp()->windowlist[i].dead = 0;
755 ZeroMemory(&data, sizeof(data));
757 SendMessage(GetNHApp()->hMainWnd, WM_MSNH_COMMAND,
758 (WPARAM) MSNH_MSG_ADDWND, (LPARAM) &data);
762 /* Clear the given window, when asked to. */
764 mswin_clear_nhwindow(winid wid)
766 logDebug("mswin_clear_nhwindow(%d)\n", wid);
768 if ((wid >= 0) && (wid < MAXWINDOWS)
769 && (GetNHApp()->windowlist[wid].win != NULL)) {
770 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
771 if (Is_rogue_level(&u.uz))
772 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
773 ROGUE_LEVEL_MAP_MODE);
775 mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP),
779 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
780 (WPARAM) MSNH_MSG_CLEAR_WINDOW, (LPARAM) NULL);
784 /* -- Display the window on the screen. If there is data
785 pending for output in that window, it should be sent.
786 If blocking is TRUE, display_nhwindow() will not
787 return until the data has been displayed on the screen,
788 and acknowledged by the user where appropriate.
789 -- All calls are blocking in the tty window-port.
790 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
791 --more--, if necessary, in the tty window-port.
794 mswin_display_nhwindow(winid wid, BOOLEAN_P block)
796 logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block);
797 if (GetNHApp()->windowlist[wid].win != NULL) {
798 if (GetNHApp()->windowlist[wid].type == NHW_MENU) {
800 mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win,
803 if (GetNHApp()->windowlist[wid].type == NHW_TEXT) {
804 mswin_display_text_window(GetNHApp()->windowlist[wid].win);
806 if (GetNHApp()->windowlist[wid].type == NHW_RIP) {
807 mswin_display_RIP_window(GetNHApp()->windowlist[wid].win);
810 UpdateWindow(GetNHApp()->windowlist[wid].win);
812 if (GetNHApp()->windowlist[wid].type == NHW_MAP) {
813 (void) mswin_nhgetch();
817 SetFocus(GetNHApp()->hMainWnd);
822 mswin_hwnd_from_winid(winid wid)
824 if (wid >= 0 && wid < MAXWINDOWS) {
825 return GetNHApp()->windowlist[wid].win;
832 mswin_winid_from_handle(HWND hWnd)
836 for (i = 1; i < MAXWINDOWS; i++)
837 if (GetNHApp()->windowlist[i].win == hWnd)
843 mswin_winid_from_type(int type)
847 for (i = 1; i < MAXWINDOWS; i++)
848 if (GetNHApp()->windowlist[i].type == type)
854 mswin_window_mark_dead(winid wid)
856 if (wid >= 0 && wid < MAXWINDOWS) {
857 GetNHApp()->windowlist[wid].win = NULL;
858 GetNHApp()->windowlist[wid].dead = 1;
862 /* Destroy will dismiss the window if the window has not
863 * already been dismissed.
866 mswin_destroy_nhwindow(winid wid)
868 logDebug("mswin_destroy_nhwindow(%d)\n", wid);
870 if ((GetNHApp()->windowlist[wid].type == NHW_MAP)
871 || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE)
872 || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) {
873 /* main windows is going to take care of those */
878 if (!GetNHApp()->windowlist[wid].dead
879 && GetNHApp()->windowlist[wid].win != NULL)
880 DestroyWindow(GetNHApp()->windowlist[wid].win);
881 GetNHApp()->windowlist[wid].win = NULL;
882 GetNHApp()->windowlist[wid].type = 0;
883 GetNHApp()->windowlist[wid].dead = 0;
887 /* Next output to window will start at (x,y), also moves
888 displayable cursor to (x,y). For backward compatibility,
889 1 <= x < cols, 0 <= y < rows, where cols and rows are
893 mswin_curs(winid wid, int x, int y)
895 logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y);
897 if ((wid >= 0) && (wid < MAXWINDOWS)
898 && (GetNHApp()->windowlist[wid].win != NULL)) {
902 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
903 (WPARAM) MSNH_MSG_CURSOR, (LPARAM) &data);
908 putstr(window, attr, str)
909 -- Print str on the window with the given attribute. Only
910 printable ASCII characters (040-0126) must be supported.
911 Multiple putstr()s are output on separate lines.
919 If a window-port does not support all of these, it may map
920 unsupported attributes to a supported one (e.g. map them
921 all to ATR_INVERSE). putstr() may compress spaces out of
922 str, break str, or truncate str, if necessary for the
923 display. Where putstr() breaks a line, it has to clear
925 -- putstr should be implemented such that if two putstr()s
926 are done consecutively the user will see the first and
927 then the second. In the tty port, pline() achieves this
928 by calling more() or displaying both on the same line.
931 mswin_putstr(winid wid, int attr, const char *text)
933 logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text);
935 mswin_putstr_ex(wid, attr, text, 0);
939 mswin_putstr_ex(winid wid, int attr, const char *text, boolean app)
941 if ((wid >= 0) && (wid < MAXWINDOWS)) {
942 if (GetNHApp()->windowlist[wid].win == NULL
943 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
944 GetNHApp()->windowlist[wid].win =
945 mswin_init_menu_window(MENU_TYPE_TEXT);
946 GetNHApp()->windowlist[wid].dead = 0;
949 if (GetNHApp()->windowlist[wid].win != NULL) {
951 ZeroMemory(&data, sizeof(data));
955 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
956 (WPARAM) MSNH_MSG_PUTSTR, (LPARAM) &data);
961 /* Display the file named str. Complain about missing files
962 iff complain is TRUE.
965 mswin_display_file(const char *filename, BOOLEAN_P must_exist)
970 logDebug("mswin_display_file(%s, %d)\n", filename, must_exist);
972 f = dlb_fopen(filename, RDTMODE);
976 _stprintf(message, TEXT("Warning! Could not find file: %s\n"),
977 NH_A2W(filename, wbuf, sizeof(wbuf)));
978 MessageBox(GetNHApp()->hMainWnd, message, TEXT("ERROR"),
979 MB_OK | MB_ICONERROR);
985 text = mswin_create_nhwindow(NHW_TEXT);
987 while (dlb_fgets(line, LLEN, f)) {
990 if (line[len - 1] == '\n')
991 line[len - 1] = '\x0';
992 mswin_putstr(text, ATR_NONE, line);
994 (void) dlb_fclose(f);
996 mswin_display_nhwindow(text, 1);
997 mswin_destroy_nhwindow(text);
1001 /* Start using window as a menu. You must call start_menu()
1002 before add_menu(). After calling start_menu() you may not
1003 putstr() to the window. Only windows of type NHW_MENU may
1007 mswin_start_menu(winid wid)
1009 logDebug("mswin_start_menu(%d)\n", wid);
1010 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1011 if (GetNHApp()->windowlist[wid].win == NULL
1012 && GetNHApp()->windowlist[wid].type == NHW_MENU) {
1013 GetNHApp()->windowlist[wid].win =
1014 mswin_init_menu_window(MENU_TYPE_MENU);
1015 GetNHApp()->windowlist[wid].dead = 0;
1018 if (GetNHApp()->windowlist[wid].win != NULL) {
1019 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1020 (WPARAM) MSNH_MSG_STARTMENU, (LPARAM) NULL);
1026 add_menu(windid window, int glyph, const anything identifier,
1027 char accelerator, char groupacc,
1028 int attr, char *str, boolean preselected)
1029 -- Add a text line str to the given menu window. If
1031 is 0, then the line cannot be selected (e.g. a title).
1032 Otherwise, identifier is the value returned if the line is
1033 selected. Accelerator is a keyboard key that can be used
1034 to select the line. If the accelerator of a selectable
1035 item is 0, the window system is free to select its own
1036 accelerator. It is up to the window-port to make the
1037 accelerator visible to the user (e.g. put "a - " in front
1038 of str). The value attr is the same as in putstr().
1039 Glyph is an optional glyph to accompany the line. If
1040 window port cannot or does not want to display it, this
1041 is OK. If there is no glyph applicable, then this
1042 value will be NO_GLYPH.
1043 -- All accelerators should be in the range [A-Za-z].
1044 -- It is expected that callers do not mix accelerator
1045 choices. Either all selectable items have an accelerator
1046 or let the window system pick them. Don't do both.
1047 -- Groupacc is a group accelerator. It may be any character
1048 outside of the standard accelerator (see above) or a
1049 number. If 0, the item is unaffected by any group
1050 accelerator. If this accelerator conflicts with
1051 the menu command (or their user defined aliases), it loses.
1052 The menu commands and aliases take care not to interfere
1053 with the default object class symbols.
1054 -- If you want this choice to be preselected when the
1055 menu is displayed, set preselected to TRUE.
1058 mswin_add_menu(winid wid, int glyph, const ANY_P *identifier,
1059 CHAR_P accelerator, CHAR_P group_accel, int attr,
1060 const char *str, BOOLEAN_P presel)
1062 logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph,
1063 identifier, (char) accelerator, (char) group_accel, attr, str,
1065 if ((wid >= 0) && (wid < MAXWINDOWS)
1066 && (GetNHApp()->windowlist[wid].win != NULL)) {
1067 MSNHMsgAddMenu data;
1068 ZeroMemory(&data, sizeof(data));
1070 data.identifier = identifier;
1071 data.accelerator = accelerator;
1072 data.group_accel = group_accel;
1075 data.presel = presel;
1077 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1078 (WPARAM) MSNH_MSG_ADDMENU, (LPARAM) &data);
1083 end_menu(window, prompt)
1084 -- Stop adding entries to the menu and flushes the window
1085 to the screen (brings to front?). Prompt is a prompt
1086 to give the user. If prompt is NULL, no prompt will
1088 ** This probably shouldn't flush the window any more (if
1089 ** it ever did). That should be select_menu's job. -dean
1092 mswin_end_menu(winid wid, const char *prompt)
1094 logDebug("mswin_end_menu(%d, %s)\n", wid, prompt);
1095 if ((wid >= 0) && (wid < MAXWINDOWS)
1096 && (GetNHApp()->windowlist[wid].win != NULL)) {
1097 MSNHMsgEndMenu data;
1098 ZeroMemory(&data, sizeof(data));
1101 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1102 (WPARAM) MSNH_MSG_ENDMENU, (LPARAM) &data);
1107 int select_menu(windid window, int how, menu_item **selected)
1108 -- Return the number of items selected; 0 if none were chosen,
1109 -1 when explicitly cancelled. If items were selected, then
1110 selected is filled in with an allocated array of menu_item
1111 structures, one for each selected line. The caller must
1112 free this array when done with it. The "count" field
1113 of selected is a user supplied count. If the user did
1114 not supply a count, then the count field is filled with
1115 -1 (meaning all). A count of zero is equivalent to not
1116 being selected and should not be in the list. If no items
1117 were selected, then selected is NULL'ed out. How is the
1118 mode of the menu. Three valid values are PICK_NONE,
1119 PICK_ONE, and PICK_N, meaning: nothing is selectable,
1120 only one thing is selectable, and any number valid items
1121 may selected. If how is PICK_NONE, this function should
1122 never return anything but 0 or -1.
1123 -- You may call select_menu() on a window multiple times --
1124 the menu is saved until start_menu() or destroy_nhwindow()
1125 is called on the window.
1126 -- Note that NHW_MENU windows need not have select_menu()
1127 called for them. There is no way of knowing whether
1128 select_menu() will be called for the window at
1129 create_nhwindow() time.
1132 mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected)
1136 logDebug("mswin_select_menu(%d, %d)\n", wid, how);
1138 if ((wid >= 0) && (wid < MAXWINDOWS)
1139 && (GetNHApp()->windowlist[wid].win != NULL)) {
1140 nReturned = mswin_menu_window_select_menu(
1141 GetNHApp()->windowlist[wid].win, how, selected);
1147 -- Indicate to the window port that the inventory has been changed.
1148 -- Merely calls display_inventory() for window-ports that leave the
1149 window up, otherwise empty.
1152 mswin_update_inventory()
1154 logDebug("mswin_update_inventory()\n");
1158 mark_synch() -- Don't go beyond this point in I/O on any channel until
1159 all channels are caught up to here. Can be an empty call
1165 logDebug("mswin_mark_synch()\n");
1169 wait_synch() -- Wait until all pending output is complete (*flush*() for
1171 -- May also deal with exposure events etc. so that the
1172 display is OK when return from wait_synch().
1177 logDebug("mswin_wait_synch()\n");
1181 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
1182 screen if the playing area is larger than the screen.
1183 -- This function is only defined if CLIPPING is defined.
1186 mswin_cliparound(int x, int y)
1188 winid wid = WIN_MAP;
1190 logDebug("mswin_cliparound(%d, %d)\n", x, y);
1192 if ((wid >= 0) && (wid < MAXWINDOWS)
1193 && (GetNHApp()->windowlist[wid].win != NULL)) {
1194 MSNHMsgClipAround data;
1197 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1198 (WPARAM) MSNH_MSG_CLIPAROUND, (LPARAM) &data);
1203 print_glyph(window, x, y, glyph, bkglyph)
1204 -- Print the glyph at (x,y) on the given window. Glyphs are
1205 integers at the interface, mapped to whatever the window-
1206 port wants (symbol, font, color, attributes, ...there's
1207 a 1-1 map between glyphs and distinct things on the map).
1210 mswin_print_glyph(winid wid, XCHAR_P x, XCHAR_P y, int glyph, int bkglyph)
1212 logDebug("mswin_print_glyph(%d, %d, %d, %d, %d)\n", wid, x, y, glyph, bkglyph);
1214 if ((wid >= 0) && (wid < MAXWINDOWS)
1215 && (GetNHApp()->windowlist[wid].win != NULL)) {
1216 MSNHMsgPrintGlyph data;
1218 ZeroMemory(&data, sizeof(data));
1222 SendMessage(GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND,
1223 (WPARAM) MSNH_MSG_PRINT_GLYPH, (LPARAM) &data);
1228 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
1229 the user sees str. raw_print() appends a newline to str.
1230 It need not recognize ASCII control characters. This is
1231 used during startup (before windowing system initialization
1232 -- maybe this means only error startup messages are raw),
1233 for error messages, and maybe other "msg" uses. E.g.
1234 updating status for micros (i.e, "saving").
1237 mswin_raw_print(const char *str)
1240 logDebug("mswin_raw_print(%s)\n", str);
1242 MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1243 TEXT("NetHack"), MB_OK);
1248 -- Like raw_print(), but prints in bold/standout (if
1252 mswin_raw_print_bold(const char *str)
1255 logDebug("mswin_raw_print_bold(%s)\n", str);
1257 MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)),
1258 TEXT("NetHack"), MB_OK);
1262 int nhgetch() -- Returns a single character input from the user.
1263 -- In the tty window-port, nhgetch() assumes that tgetch()
1264 will be the routine the OS provides to read a character.
1265 Returned character _must_ be non-zero.
1273 logDebug("mswin_nhgetch()\n");
1275 while ((event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR)
1278 key = event->kbd.ch;
1283 int nh_poskey(int *x, int *y, int *mod)
1284 -- Returns a single character input from the user or a
1285 a positioning event (perhaps from a mouse). If the
1286 return value is non-zero, a character was typed, else,
1287 a position in the MAP window is returned in x, y and mod.
1290 CLICK_1 -- mouse click type 1
1291 CLICK_2 -- mouse click type 2
1293 The different click types can map to whatever the
1294 hardware supports. If no mouse is supported, this
1295 routine always returns a non-zero character.
1298 mswin_nh_poskey(int *x, int *y, int *mod)
1303 logDebug("mswin_nh_poskey()\n");
1305 while ((event = mswin_input_pop()) == NULL)
1308 if (event->type == NHEVENT_MOUSE) {
1309 *mod = event->ms.mod;
1314 key = event->kbd.ch;
1320 nhbell() -- Beep at user. [This will exist at least until sounds are
1321 redone, since sounds aren't attributable to windows
1327 logDebug("mswin_nhbell()\n");
1332 -- Display previous messages. Used by the ^P command.
1333 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1336 mswin_doprev_message()
1338 logDebug("mswin_doprev_message()\n");
1339 SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL,
1340 MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
1345 char yn_function(const char *ques, const char *choices, char default)
1346 -- Print a prompt made up of ques, choices and default.
1347 Read a single character response that is contained in
1348 choices or default. If choices is NULL, all possible
1349 inputs are accepted and returned. This overrides
1350 everything else. The choices are expected to be in
1351 lower case. Entering ESC always maps to 'q', or 'n',
1352 in that order, if present in choices, otherwise it maps
1353 to default. Entering any other quit character (SPACE,
1354 RETURN, NEWLINE) maps to default.
1355 -- If the choices string contains ESC, then anything after
1356 it is an acceptable response, but the ESC and whatever
1357 follows is not included in the prompt.
1358 -- If the choices string contains a '#' then accept a count.
1359 Place this value in the global "yn_number" and return '#'.
1360 -- This uses the top line in the tty window-port, other
1361 ports might use a popup.
1364 mswin_yn_function(const char *question, const char *choices, CHAR_P def)
1368 char yn_esc_map = '\033';
1369 char message[BUFSZ];
1372 logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def);
1375 char *cb, choicebuf[QBUFSZ];
1376 Strcpy(choicebuf, choices);
1377 if ((cb = index(choicebuf, '\033')) != 0) {
1378 /* anything beyond <esc> is hidden */
1381 (void) strncpy(message, question, QBUFSZ - 1);
1382 message[QBUFSZ - 1] = '\0';
1383 sprintf(eos(message), " [%s]", choicebuf);
1385 sprintf(eos(message), " (%c)", def);
1386 Strcat(message, " ");
1387 /* escape maps to 'q' or 'n' or default, in that order */
1389 (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def));
1391 Strcpy(message, question);
1394 #if defined(WIN_CE_SMARTPHONE)
1397 ZeroMemory(buf, sizeof(buf));
1399 if (!index(choices, '\033'))
1400 buf[0] = '\033'; /* make sure ESC is always available */
1401 strncat(buf, choices, sizeof(buf) - 2);
1402 NHSPhoneSetKeypadFromString(buf);
1404 /* sometimes choices are included in the message itself, e.g.
1407 p1 = strchr(question, '[');
1408 p2 = strrchr(question, ']');
1409 if (p1 && p2 && p1 < p2) {
1410 buf[0] = '\033'; /* make sure ESC is always available */
1411 strncat(buf, p1 + 1, p2 - p1 - 1);
1412 NHSPhoneSetKeypadFromString(buf);
1413 } else if (strstr(question, "direction")) {
1414 /* asking for direction here */
1415 NHSPhoneSetKeypadDirection();
1418 NHSPhoneSetKeypadFromString("\0330-9a-zA-Z");
1422 #endif /* defined(WIN_CE_SMARTPHONE) */
1424 mswin_putstr(WIN_MESSAGE, ATR_BOLD, message);
1426 /* Only here if main window is not present */
1427 while (result < 0) {
1428 ch = mswin_nhgetch();
1430 result = yn_esc_map;
1431 } else if (choices && !index(choices, ch)) {
1432 /* FYI: ch==-115 is for KP_ENTER */
1434 && (ch == ' ' || ch == '\r' || ch == '\n' || ch == -115)) {
1438 /* and try again... */
1445 /* display selection in the message window */
1449 mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1);
1452 /* prevent "--more--" prompt from appearing when several
1453 questions being asked in the same loop (like selling
1454 something in the shop)
1455 It does not really clears the window - mhmsgwnd.c */
1456 mswin_clear_nhwindow(WIN_MESSAGE);
1458 #if defined(WIN_CE_SMARTPHONE)
1459 NHSPhoneSetKeypadDefault();
1465 getlin(const char *ques, char *input)
1466 -- Prints ques as a prompt and reads a single line of text,
1467 up to a newline. The string entered is returned without the
1468 newline. ESC is used to cancel, in which case the string
1469 "\033\000" is returned.
1470 -- getlin() must call flush_screen(1) before doing anything.
1471 -- This uses the top line in the tty window-port, other
1472 ports might use a popup.
1475 mswin_getlin(const char *question, char *input)
1477 logDebug("mswin_getlin(%s, %p)\n", question, input);
1478 if (mswin_getlin_window(question, input, BUFSZ) == IDCANCEL) {
1479 strcpy(input, "\033");
1484 int get_ext_cmd(void)
1485 -- Get an extended command in a window-port specific way.
1486 An index into extcmdlist[] is returned on a successful
1487 selection, -1 otherwise.
1493 logDebug("mswin_get_ext_cmd()\n");
1495 if (mswin_ext_cmd_window(&ret) == IDCANCEL)
1503 -- Initialize the number pad to the given state.
1506 mswin_number_pad(int state)
1509 logDebug("mswin_number_pad(%d)\n", state);
1513 delay_output() -- Causes a visible delay of 50ms in the output.
1514 Conceptually, this is similar to wait_synch() followed
1515 by a nap(50ms), but allows asynchronous operation.
1518 mswin_delay_output()
1520 logDebug("mswin_delay_output()\n");
1525 mswin_change_color()
1527 logDebug("mswin_change_color()\n");
1531 mswin_get_color_string()
1533 logDebug("mswin_get_color_string()\n");
1538 start_screen() -- Only used on Unix tty ports, but must be declared for
1539 completeness. Sets up the tty to work in full-screen
1540 graphics mode. Look at win/tty/termcap.c for an
1541 example. If your window-port does not need this function
1542 just declare an empty function.
1545 mswin_start_screen()
1548 logDebug("mswin_start_screen()\n");
1552 end_screen() -- Only used on Unix tty ports, but must be declared for
1553 completeness. The complement of start_screen().
1559 logDebug("mswin_end_screen()\n");
1563 outrip(winid, int, when)
1564 -- The tombstone code. If you want the traditional code use
1565 genl_outrip for the value and check the #if in rip.c.
1568 mswin_outrip(winid wid, int how, time_t when)
1570 logDebug("mswin_outrip(%d, %d, %ld)\n", wid, how, (long) when);
1571 if ((wid >= 0) && (wid < MAXWINDOWS)) {
1572 DestroyWindow(GetNHApp()->windowlist[wid].win);
1573 GetNHApp()->windowlist[wid].win = mswin_init_RIP_window();
1574 GetNHApp()->windowlist[wid].type = NHW_RIP;
1575 GetNHApp()->windowlist[wid].dead = 0;
1577 genl_outrip(wid, how, when);
1580 /* handle options updates here */
1582 mswin_preference_update(const char *pref)
1586 if (_stricmp(pref, "font_menu") == 0
1587 || _stricmp(pref, "font_size_menu") == 0) {
1588 if (iflags.wc_fontsiz_menu < NHFONT_SIZE_MIN
1589 || iflags.wc_fontsiz_menu > NHFONT_SIZE_MAX)
1590 iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE;
1592 hdc = GetDC(GetNHApp()->hMainWnd);
1593 mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE);
1594 mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE);
1595 mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE);
1596 mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE);
1597 mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE);
1598 mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE);
1599 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1601 mswin_layout_main_window(NULL);
1605 if (_stricmp(pref, "font_status") == 0
1606 || _stricmp(pref, "font_size_status") == 0) {
1607 if (iflags.wc_fontsiz_status < NHFONT_SIZE_MIN
1608 || iflags.wc_fontsiz_status > NHFONT_SIZE_MAX)
1609 iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE;
1611 hdc = GetDC(GetNHApp()->hMainWnd);
1612 mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE);
1613 mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE);
1614 mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE);
1615 mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE);
1616 mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE);
1617 mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE);
1618 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1620 mswin_layout_main_window(NULL);
1624 if (_stricmp(pref, "font_message") == 0
1625 || _stricmp(pref, "font_size_message") == 0) {
1626 if (iflags.wc_fontsiz_message < NHFONT_SIZE_MIN
1627 || iflags.wc_fontsiz_message > NHFONT_SIZE_MAX)
1628 iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE;
1630 hdc = GetDC(GetNHApp()->hMainWnd);
1631 mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE);
1632 mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE);
1633 mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE);
1634 mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE);
1635 mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE);
1636 mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE);
1637 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1639 mswin_layout_main_window(NULL);
1643 if (_stricmp(pref, "font_text") == 0
1644 || _stricmp(pref, "font_size_text") == 0) {
1645 if (iflags.wc_fontsiz_text < NHFONT_SIZE_MIN
1646 || iflags.wc_fontsiz_text > NHFONT_SIZE_MAX)
1647 iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE;
1649 hdc = GetDC(GetNHApp()->hMainWnd);
1650 mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE);
1651 mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE);
1652 mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE);
1653 mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE);
1654 mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE);
1655 mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE);
1656 ReleaseDC(GetNHApp()->hMainWnd, hdc);
1658 mswin_layout_main_window(NULL);
1662 if (_stricmp(pref, "scroll_margin") == 0) {
1663 mswin_cliparound(u.ux, u.uy);
1667 if (_stricmp(pref, "map_mode") == 0) {
1668 mswin_select_map_mode(iflags.wc_map_mode);
1672 if (_stricmp(pref, "hilite_pet") == 0) {
1673 InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE);
1677 if (_stricmp(pref, "align_message") == 0
1678 || _stricmp(pref, "align_status") == 0) {
1679 mswin_layout_main_window(NULL);
1683 if (_stricmp(pref, "vary_msgcount") == 0) {
1684 InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE);
1685 mswin_layout_main_window(NULL);
1689 if (_stricmp(pref, "fullscreen") == 0) {
1690 mswin_set_fullscreen(iflags.wc2_fullscreen);
1694 if (_stricmp(pref, "softkeyboard") == 0) {
1695 GetNHApp()->bUseSIP = iflags.wc2_softkeyboard;
1699 if (_stricmp(pref, "wraptext") == 0) {
1700 GetNHApp()->bWrapText = iflags.wc2_wraptext;
1710 while (!mswin_have_input() && GetMessage(&msg, NULL, 0, 0) != 0) {
1711 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) {
1712 TranslateMessage(&msg);
1713 DispatchMessage(&msg);
1718 /* clean up and quit */
1720 bail(const char *mesg)
1723 mswin_exit_nhwindows(mesg);
1724 nh_terminate(EXIT_SUCCESS);
1733 TCHAR wbuf[MAX_PATH];
1736 extern int total_tiles_used;
1738 /* no file - no tile */
1739 if (!(iflags.wc_tile_file && *iflags.wc_tile_file))
1743 hBmp = SHLoadDIBitmap(NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH));
1746 "Cannot load tiles from the file. Reverting back to default.");
1750 /* calculate tile dimensions */
1751 GetObject(hBmp, sizeof(BITMAP), (LPVOID) &bm);
1752 if (bm.bmWidth % iflags.wc_tile_width
1753 || bm.bmHeight % iflags.wc_tile_height) {
1755 raw_print("Tiles bitmap does not match tile_width and tile_height "
1756 "options. Reverting back to default.");
1760 tl_num = (bm.bmWidth / iflags.wc_tile_width)
1761 * (bm.bmHeight / iflags.wc_tile_height);
1762 if (tl_num < total_tiles_used) {
1764 raw_print("Number of tiles in the bitmap is less than required by "
1765 "the game. Reverting back to default.");
1769 /* set the tile information */
1770 if (GetNHApp()->bmpMapTiles != GetNHApp()->bmpTiles) {
1771 DeleteObject(GetNHApp()->bmpMapTiles);
1774 GetNHApp()->bmpMapTiles = hBmp;
1775 GetNHApp()->mapTile_X = iflags.wc_tile_width;
1776 GetNHApp()->mapTile_Y = iflags.wc_tile_height;
1777 GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width;
1779 map_size.cx = GetNHApp()->mapTile_X * COLNO;
1780 map_size.cy = GetNHApp()->mapTile_Y * ROWNO;
1781 mswin_map_stretch(mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE);
1786 mswin_popup_display(HWND hWnd, int *done_indicator)
1791 /* activate the menu window */
1792 GetNHApp()->hPopupWnd = hWnd;
1794 mswin_layout_main_window(hWnd);
1796 /* disable game windows */
1797 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
1798 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
1800 EnableWindow(hChild, FALSE);
1802 #if defined(WIN_CE_SMARTPHONE)
1803 ShowWindow(GetNHApp()->hMenuBar, SW_HIDE);
1804 ShowWindow(SHFindMenuBar(hWnd), SW_SHOW);
1806 EnableWindow(GetNHApp()->hMenuBar, FALSE);
1809 /* bring menu window on top */
1810 SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0,
1811 SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
1813 /* go into message loop */
1815 *done_indicator = 0;
1816 while (IsWindow(hWnd) && (done_indicator == NULL || !*done_indicator)
1817 && GetMessage(&msg, NULL, 0, 0) != 0) {
1818 if (!IsDialogMessage(hWnd, &msg)) {
1819 if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable,
1821 TranslateMessage(&msg);
1822 DispatchMessage(&msg);
1829 mswin_popup_destroy(HWND hWnd)
1833 /* enable game windows */
1834 for (hChild = GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild;
1835 hChild = GetWindow(hChild, GW_HWNDNEXT)) {
1836 if (hChild != hWnd) {
1837 EnableWindow(hChild, TRUE);
1840 #if defined(WIN_CE_SMARTPHONE)
1841 ShowWindow(SHFindMenuBar(hWnd), SW_HIDE);
1842 ShowWindow(GetNHApp()->hMenuBar, SW_SHOW);
1844 EnableWindow(GetNHApp()->hMenuBar, TRUE);
1847 SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0,
1848 SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
1849 GetNHApp()->hPopupWnd = NULL;
1850 mswin_window_mark_dead(mswin_winid_from_handle(hWnd));
1851 DestroyWindow(hWnd);
1853 mswin_layout_main_window(hWnd);
1855 SetFocus(GetNHApp()->hMainWnd);
1859 mswin_set_fullscreen(BOOL is_fullscreen)
1861 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
1862 SetForegroundWindow(GetNHApp()->hMainWnd);
1863 if (is_fullscreen) {
1864 SHFullScreen(GetNHApp()->hMainWnd,
1865 SHFS_HIDETASKBAR | SHFS_HIDESTARTICON);
1866 MoveWindow(GetNHApp()->hMainWnd, 0, 0, GetSystemMetrics(SM_CXSCREEN),
1867 GetSystemMetrics(SM_CYSCREEN), FALSE);
1870 SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
1871 SHFullScreen(GetNHApp()->hMainWnd,
1872 SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON);
1873 MoveWindow(GetNHApp()->hMainWnd, rc.left, rc.top, rc.right - rc.left,
1874 rc.bottom - rc.top, FALSE);
1876 GetNHApp()->bFullScreen = is_fullscreen;
1878 GetNHApp()->bFullScreen = FALSE;
1882 #if defined(WIN_CE_SMARTPHONE)
1884 NHSPhoneDialogSetup(HWND hDlg, UINT nToolBarId, BOOL is_edit,
1891 // Create our MenuBar
1892 ZeroMemory(&mbi, sizeof(SHMENUBARINFO));
1893 mbi.cbSize = sizeof(mbi);
1894 mbi.hwndParent = hDlg;
1895 mbi.nToolBarId = nToolBarId;
1896 mbi.hInstRes = GetNHApp()->hApp;
1897 if (!SHCreateMenuBar(&mbi)) {
1898 error("cannot create dialog menu");
1901 if (is_fullscreen) {
1902 SHINITDLGINFO shidi;
1904 shidi.dwMask = SHIDIM_FLAGS;
1905 shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN;
1907 SHInitDialog(&shidi);
1909 GetWindowRect(GetNHApp()->hMainWnd, &main_wnd_rect);
1910 MoveWindow(hDlg, main_wnd_rect.left, main_wnd_rect.top,
1911 main_wnd_rect.right - main_wnd_rect.left,
1912 main_wnd_rect.bottom - main_wnd_rect.top, FALSE);
1915 /* hide OK and CANCEL buttons */
1916 hOK = GetDlgItem(hDlg, IDOK);
1917 hCancel = GetDlgItem(hDlg, IDCANCEL);
1919 if (IsWindow(hCancel))
1920 ShowWindow(hCancel, SW_HIDE);
1921 if (IsWindow(hOK)) {
1922 GetWindowRect(hOK, &rtOK);
1923 GetWindowRect(hDlg, &rtDlg);
1925 rtDlg.bottom -= rtOK.bottom - rtOK.top;
1926 ShowWindow(hOK, SW_HIDE);
1927 SetWindowPos(hDlg, HWND_TOP, 0, 0, rtDlg.right - rtDlg.left,
1928 rtDlg.bottom - rtDlg.top,
1929 SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER);
1932 /* override "Back" button for edit box dialogs */
1934 SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK,
1935 MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY,
1936 SHMBOF_NODEFAULT | SHMBOF_NOTIFY));
1938 #endif /* defined(WIN_CE_SMARTPHONE) */
1941 mswin_read_reg(void)
1946 mswin_destroy_reg(void)
1951 mswin_write_reg(void)
1955 /* check HKCU\Software\\Microsoft\\Shell\HasKeyboard for keyboard presence,
1956 if the key is not there assume older device and no keyboard */
1958 mswin_has_keyboard(void)
1961 #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE)
1964 DWORD dwSize = sizeof(dwHasKB);
1965 if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Shell"), 0,
1966 0, &hKey) == ERROR_SUCCESS) {
1967 if (RegQueryValueEx(hKey, _T("HasKeyboard"), NULL, &dwType,
1968 (LPBYTE) &dwHasKB, &dwSize) != ERROR_SUCCESS) {
1974 return (dwHasKB == 1);
1981 logDebug(const char *fmt, ...)
1983 FILE *dfp = fopen("nhtrace.log", "a");
1988 va_start(args, fmt);
1989 vfprintf(dfp, fmt, args);