From 71bead4e3928805d27cf32f154c0bcbb59a0fd19 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 May 2018 19:43:10 -0400 Subject: [PATCH 01/42] do some performance optimizations on highlighting of tty status --- src/botl.c | 7 ++- win/tty/wintty.c | 156 +++++++++++++++++++++++++++++------------------ 2 files changed, 100 insertions(+), 63 deletions(-) diff --git a/src/botl.c b/src/botl.c index f58c45947..5b573d856 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1506903619 2017/10/02 00:20:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1525563781 2018/05/05 23:43:01 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.90 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -858,7 +858,10 @@ boolean : TRUE; fieldname = initblstats[i].fldname; - fieldfmt = initblstats[i].fldfmt; + if (fld == BL_TITLE && iflags.wc2_hitpointbar) + fieldfmt = "%-30s"; + else + fieldfmt = initblstats[i].fldfmt; status_enablefield(fld, fieldname, fieldfmt, fldenabled); } update_all = TRUE; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 63d1aac8c..d0f364574 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1520825319 2018/03/12 03:28:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1525563766 2018/05/05 23:42:46 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.144 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -66,7 +66,7 @@ struct window_procs tty_procs = { | WC2_SELECTSAVED #endif #if defined(STATUS_HILITES) - | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_HILITE_STATUS | WC2_HITPOINTBAR #endif | WC2_DARKGRAY), tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, @@ -177,6 +177,21 @@ STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); +#ifdef STATUS_HILITES +static long tty_condition_bits; +static struct tty_status_fields { + int color; + int attr; + coord loc; + boolean valid; +} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; +static int st_fld; +int hpbar_percent, hpbar_color; + +static int FDECL(condcolor, (long, unsigned long *)); +static int FDECL(condattr, (long, unsigned long *)); +#endif /* STATUS_HILITES */ + /* * A string containing all the default commands -- to add to a list * of acceptable inputs. @@ -2491,6 +2506,7 @@ const char *str; register char *ob; register const char *nb; register long i, j, n0; + boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- * probably a panic message @@ -2530,16 +2546,19 @@ const char *str; str = nb - 2; } nb = str; +#ifdef STATUS_HILITES + if (prev_tty_status[st_fld].valid + && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x + && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y + && tty_status[st_fld].color == prev_tty_status[st_fld].color + && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) +#endif + attr_match = TRUE; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES if (*ob || context.botlx) { #else - /* STATUS_HILITES will call cl_end() when finished - * its sequence of putstr's. We don't want to call - * cl_end() with each putstr() which may cause flashing - * in the Windows port - */ if (context.botlx) { #endif /* last char printed may be in middle of line */ @@ -2548,17 +2567,14 @@ const char *str; } break; } + if (*ob != *nb || !attr_match) { #ifdef STATUS_HILITES - /* Don't optimize the putsym away, in case it happens - to be the same character but different color/attr. - We don't optimize on iflags.use_status_hilites either, - in case old chars were written with highlighting and - that option has just now been toggled off. [We could - do better by tracking color/attr more closely.] */ -#else - if (*ob != *nb) + tty_curs(WIN_STATUS, + tty_status[st_fld].loc.x, + tty_status[st_fld].loc.y); #endif tty_putsym(WIN_STATUS, i, cw->cury, *nb); + } if (*ob) ob++; } @@ -3426,7 +3442,7 @@ char *posbar; video_update_positionbar(posbar); #endif } -#endif +#endif /* POSITIONBAR */ /* * The following data structures come from the genl_ routines in @@ -3439,23 +3455,20 @@ extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; -#ifdef STATUS_HILITES -static long tty_condition_bits; -static int tty_status_colors[MAXBLSTATS]; -int hpbar_percent, hpbar_color; - -static int FDECL(condcolor, (long, unsigned long *)); -static int FDECL(condattr, (long, unsigned long *)); -#endif /* STATUS_HILITES */ - void tty_status_init() { #ifdef STATUS_HILITES int i; - for (i = 0; i < MAXBLSTATS; ++i) - tty_status_colors[i] = NO_COLOR; /* no color */ + for (i = 0; i < MAXBLSTATS; ++i) { + tty_status[i].color = NO_COLOR; /* no color */ + tty_status[i].attr = ATR_NONE; + tty_status[i].loc.x = 0; + tty_status[i].loc.y = 0; + tty_status[i].valid = FALSE; + prev_tty_status[i] = tty_status[i]; + } tty_condition_bits = 0L; hpbar_percent = 0, hpbar_color = NO_COLOR; #endif /* STATUS_HILITES */ @@ -3552,14 +3565,14 @@ tty_status_init() #ifdef TEXTCOLOR #define MaybeDisplayCond(bm,txt) \ if (tty_condition_bits & (bm)) { \ - putstr(WIN_STATUS, 0, " "); \ + tty_putstr(WIN_STATUS, 0, " "); \ if (iflags.hilite_delta) { \ attrmask = condattr(bm, colormasks); \ Begin_Attr(attrmask); \ if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ term_start_color(coloridx); \ } \ - putstr(WIN_STATUS, 0, txt); \ + tty_putstr(WIN_STATUS, 0, txt); \ if (iflags.hilite_delta) { \ if (coloridx != NO_COLOR) \ term_end_color(); \ @@ -3569,17 +3582,23 @@ tty_status_init() #else #define MaybeDisplayCond(bm,txt) \ if (tty_condition_bits & (bm)) { \ - putstr(WIN_STATUS, 0, " "); \ + tty_putstr(WIN_STATUS, 0, " "); \ if (iflags.hilite_delta) { \ attrmask = condattr(bm, colormasks); \ Begin_Attr(attrmask); \ } \ - putstr(WIN_STATUS, 0, txt); \ + tty_putstr(WIN_STATUS, 0, txt); \ if (iflags.hilite_delta) { \ End_Attr(attrmask); \ } \ } #endif +#define status_putstr(s) \ + tty_status[st_fld].loc.x = (xchar) cw->curx; \ + tty_status[st_fld].loc.y = (xchar) cw->cury; \ + tty_status[st_fld].valid = TRUE; \ + tty_putstr(WIN_STATUS, 0, s); + void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) @@ -3592,6 +3611,8 @@ unsigned long *colormasks; #ifdef TEXTCOLOR int coloridx = NO_COLOR; #endif + struct WinDesc *cw = 0; + char *text = (char *) ptr; static boolean oncearound = FALSE; /* prevent premature partial display */ enum statusfields fieldorder[2][15] = { @@ -3602,53 +3623,62 @@ unsigned long *colormasks; BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; - int attridx = 0; + int attridx = 0; + st_fld = fldidx; if (fldidx != BL_FLUSH) { if (!status_activefields[fldidx]) return; switch (fldidx) { - case BL_CONDITION: - tty_condition_bits = *condptr; - oncearound = TRUE; - break; - default: - Sprintf(status_vals[fldidx], - (fldidx == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" : - status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", + case BL_CONDITION: + tty_condition_bits = *condptr; + oncearound = TRUE; + break; + default: + Sprintf(status_vals[fldidx], + status_fieldfmt[fldidx] ? + status_fieldfmt[fldidx] : "%s", text); #ifdef TEXTCOLOR - tty_status_colors[fldidx] = color; + tty_status[fldidx].color = (color & 0x00FF); #else - tty_status_colors[fldidx] = NO_COLOR; + tty_status[fldidx].color = NO_COLOR; #endif - if (iflags.wc2_hitpointbar && fldidx == BL_HP) { - hpbar_percent = percent; + tty_status[fldidx].attr = (color & 0xFF00) >> 8; + + if (iflags.wc2_hitpointbar && fldidx == BL_HP) { + hpbar_percent = percent; #ifdef TEXTCOLOR - hpbar_color = color; + hpbar_color = color; #else - hpbar_color = NO_COLOR; + hpbar_color = NO_COLOR; #endif - } - break; + } + break; } } if (!oncearound) return; + if (WIN_STATUS == WIN_ERR + || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { + paniclog("status", "WIN_ERR on status window."); + return; + } + curs(WIN_STATUS, 1, 0); for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { int fldidx1 = fieldorder[0][i]; if (status_activefields[fldidx1]) { if (fldidx1 != BL_TITLE || !iflags.wc2_hitpointbar) { #ifdef TEXTCOLOR - coloridx = tty_status_colors[fldidx1] & 0x00FF; + coloridx = tty_status[fldidx1].color; #endif - attridx = (tty_status_colors[fldidx1] & 0xFF00) >> 8; + attridx = tty_status[fldidx1].attr; text = status_vals[fldidx1]; if (iflags.hilite_delta) { if (*text == ' ') { - putstr(WIN_STATUS, 0, " "); + status_putstr(" "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3659,7 +3689,7 @@ unsigned long *colormasks; #endif } - putstr(WIN_STATUS, 0, text); + status_putstr(text); if (iflags.hilite_delta) { #ifdef TEXTCOLOR @@ -3692,7 +3722,7 @@ unsigned long *colormasks; } } if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - putstr(WIN_STATUS, 0, "["); + status_putstr("["); #ifdef TEXTCOLOR coloridx = hpbar_color & 0x00FF; /* attridx = (hpbar_color & 0xFF00) >> 8; */ @@ -3700,7 +3730,7 @@ unsigned long *colormasks; term_start_color(coloridx); #endif term_start_attr(ATR_INVERSE); - putstr(WIN_STATUS, 0, bar); + tty_putstr(WIN_STATUS, 0, bar); term_end_attr(ATR_INVERSE); #ifdef TEXTCOLOR if (coloridx != NO_COLOR) @@ -3708,11 +3738,11 @@ unsigned long *colormasks; #endif if (twoparts) { *bar2 = savedch; - putstr(WIN_STATUS, 0, bar2); + tty_putstr(WIN_STATUS, 0, bar2); } - putstr(WIN_STATUS, 0, "]"); + tty_putstr(WIN_STATUS, 0, "]"); } else - putstr(WIN_STATUS, 0, text); + tty_putstr(WIN_STATUS, 0, text); } } } @@ -3724,13 +3754,13 @@ unsigned long *colormasks; if (status_activefields[fldidx2]) { if (fldidx2 != BL_CONDITION) { #ifdef TEXTCOLOR - coloridx = tty_status_colors[fldidx2] & 0x00FF; + coloridx = tty_status[fldidx2].color; #endif - attridx = (tty_status_colors[fldidx2] & 0xFF00) >> 8; + attridx = tty_status[fldidx2].attr; text = status_vals[fldidx2]; if (iflags.hilite_delta) { if (*text == ' ') { - putstr(WIN_STATUS, 0, " "); + tty_putstr(WIN_STATUS, 0, " "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3742,10 +3772,13 @@ unsigned long *colormasks; } if (fldidx2 == BL_GOLD) { + tty_status[st_fld].loc.x = (xchar) cw->curx; + tty_status[st_fld].loc.y = (xchar) cw->cury; + tty_status[st_fld].valid = TRUE; \ /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); } else { - putstr(WIN_STATUS, 0, text); + status_putstr(text); } if (iflags.hilite_delta) { @@ -3771,6 +3804,7 @@ unsigned long *colormasks; MaybeDisplayCond(BL_MASK_RIDE, "Ride"); } } + prev_tty_status[st_fld] = tty_status[st_fld]; /* copy struct */ } cl_end(); return; From e9483c7bbaf0dae95eec963358d1caae086dcf20 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 May 2018 20:42:55 -0400 Subject: [PATCH 02/42] uncomment BETA for fix-test binary --- include/global.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/global.h b/include/global.h index 420cd8491..831717c36 100644 --- a/include/global.h +++ b/include/global.h @@ -8,7 +8,7 @@ #include -/* #define BETA */ /* development or beta testing [MRS] */ +#define BETA /* development or beta testing [MRS] */ #define DEBUG From d6f9790d797c2686e58f25bd868eab69cd640c0c Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:13:30 -0700 Subject: [PATCH 03/42] Implemented a fix to the lag problems that are occuring with the Win32 console port. The fix implements a console back buffer which significantly reduces the number of calls made to WriteConsoleOutputXXX and eliminates the lag users have been experiencing. --- sys/winnt/nttty.c | 269 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 216 insertions(+), 53 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index f0532b083..bf00cb94d 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -151,6 +151,180 @@ SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; +/* CP437 to Unicode mapping according to the Unicode Consortium */ +static const WCHAR cp437[] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 +}; + +/* + * cpConsole provides the mapping of characters in the console code page to UNICODE. + * It maps a character to at most two WCHARs storing the number of WCHARs in count. + * + * NOTE: cpConsole is only valid if has_unicode is TRUE. + */ + +typedef struct { + WCHAR characters[2]; + int count; +} CodePageMapping; + +static CodePageMapping cpConsole[256]; + +static void initialize_cp_console() +{ + if (has_unicode) { + UINT codePage = GetConsoleOutputCP(); + + for (int i = 0; i < 256; i++) { + char c = (char)i; + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, &cpConsole[i].characters[0], 2); + } + } +} + +/* + * Console Buffer Flipping Support + * + * To minimize the number of calls into the WriteConsoleOutputXXX methods, we implement a notion + * of a console back buffer which keeps the next frame of console output as it is being composed. + * When ready to show the new frame, we compare this next frame to what is currently being output + * and only call WriteConsoleOutputXXX for those console values that need to change. + */ + +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_CHARACTER (' ') + +#define CONSOLE_BUFFER_WIDTH 80 +#define CONSOLE_BUFFER_HEIGHT 25 +#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) + +typedef struct { + WCHAR characters[2]; + int count; + WORD attribute; +} cell_t; + +typedef struct { + cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; +} console_buffer_t; + +console_buffer_t back_buffer; +console_buffer_t front_buffer; +cell_t clear_cell; +cell_t undefined_cell; + +static boolean buffer_flipping_initialized = FALSE; + +static void initialize_buffer_flipping(); + +static void back_buffer_flip(); + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, int x, int y); +static void back_buffer_clear_to_end_of_line(int x, int y); +static void back_buffer_write(cell_t * cell, int x, int y); + + +static void initialize_buffer_flipping() +{ + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; + clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; + clear_cell.characters[1] = 0; + clear_cell.count = 1; + + undefined_cell = clear_cell; + undefined_cell.count = 0; + + buffer_fill_to_end(&front_buffer, &undefined_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + + buffer_flipping_initialized = TRUE; +} + +static void back_buffer_flip() +{ + cell_t * back_cell = &back_buffer.cells[0][0]; + cell_t * front_cell = &front_buffer.cells[0][0]; + COORD pos; + + if (!buffer_flipping_initialized) + return; + + for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { + for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + if (back_cell->attribute != front_cell->attribute) { + WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); + front_cell->attribute = back_cell->attribute; + } + if (back_cell->count != front_cell->count || + back_cell->characters[0] != front_cell->characters[0] || + back_cell->characters[1] != front_cell->characters[1]) { + if (has_unicode) { + WriteConsoleOutputCharacterW(hConOut, back_cell->characters, back_cell->count, pos, &ccount); + } else { + char ch = (char)back_cell->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, &ccount); + } + *front_cell = *back_cell; + } + } + } +} + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) +{ + cell_t * dst = &buffer->cells[y][x]; + cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + while (dst != sentinel) + *dst++ = clear_cell; +} + +static void back_buffer_write(cell_t * cell, int x, int y) +{ + back_buffer.cells[y][x] = *cell; +} + +static void back_buffer_clear_to_end_of_line(int x, int y) +{ + cell_t * cell; + cell_t *sentinel; + + cell = &back_buffer.cells[y][x]; + sentinel = &back_buffer.cells[y+1][0]; + while (cell != sentinel) + *cell++ = clear_cell; +} + /* * Called after returning from ! or ^Z */ @@ -197,7 +371,7 @@ setftty() adjust_palette(); #endif start_screen(); - has_unicode = ((GetVersion() & 0x80000000) == 0); + initialize_buffer_flipping(); } void @@ -232,6 +406,10 @@ tty_end_screen() clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -279,6 +457,10 @@ int mode; DWORD cmode; long mask; + has_unicode = ((GetVersion() & 0x80000000) == 0); + + initialize_cp_console(); + GUILaunched = 0; try : @@ -440,6 +622,8 @@ really_move_cursor() console.cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, console.cursor); + + back_buffer_flip(); } void @@ -498,6 +682,7 @@ xputc_core(ch) char ch; { boolean inverse = FALSE; + cell_t cell; switch (ch) { case '\n': console.cursor.Y++; @@ -515,17 +700,19 @@ char ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? - BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); + BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + + cell.attribute = console.attr; if (has_unicode) { - /* Avoid bug in ANSI API on WinNT */ - WCHAR c2[2]; - int rc; - rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2); - WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount); + cell.characters[0] = cpConsole[ch].characters[0]; + cell.characters[1] = cpConsole[ch].characters[1]; + cell.count = cpConsole[ch].count; } else { - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + cell.characters[1] = 0; + cell.count = 1; } + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); console.cursor.X++; } } @@ -535,46 +722,11 @@ char ch; * for win32. It is used for glyphs only, not text. */ -/* CP437 to Unicode mapping according to the Unicode Consortium */ -static const WCHAR cp437[] = { - 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, - 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, - 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, - 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, - 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 -}; - void g_putch(in_ch) int in_ch; { + cell_t cell; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -587,23 +739,24 @@ int in_ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); - + cell.attribute = console.attr; + cell.characters[1] = 0; + cell.count = 1; if (has_unicode) - WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount); + cell.characters[0] = cp437[ch]; else - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); } void cl_end() { - int cx; console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; - cx = CO - console.cursor.X; - FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount); - FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount); + + back_buffer_clear_to_end_of_line(console.cursor.X, console.cursor.Y); + tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } @@ -611,6 +764,10 @@ void raw_clear_screen() { if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -621,6 +778,7 @@ raw_clear_screen() csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); + } } @@ -651,11 +809,16 @@ cl_eos() { int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; + FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); From ea2f2d1aac6b91e9ff8dc88d42119acffe9d3329 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:40:13 -0700 Subject: [PATCH 04/42] Quick fix to buffer height. Will need to determine why we needed a buffer height of 26. --- sys/winnt/nttty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index bf00cb94d..d6bd4c582 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -226,7 +226,7 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_CHARACTER (' ') #define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 25 +#define CONSOLE_BUFFER_HEIGHT 26 #define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) typedef struct { From 8db7237cfcb741e6d38fc977768ac4e904ac2daf Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 02:47:17 -0700 Subject: [PATCH 05/42] Console buffer support for variable size console windows. --- sys/winnt/nttty.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d6bd4c582..e19244703 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -225,10 +225,6 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') -#define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 26 -#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) - typedef struct { WCHAR characters[2]; int count; @@ -236,9 +232,12 @@ typedef struct { } cell_t; typedef struct { - cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; + cell_t * cells; } console_buffer_t; +static int buffer_width; +static int buffer_height; + console_buffer_t back_buffer; console_buffer_t front_buffer; cell_t clear_cell; @@ -247,6 +246,7 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; static void initialize_buffer_flipping(); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); @@ -257,6 +257,14 @@ static void back_buffer_write(cell_t * cell, int x, int y); static void initialize_buffer_flipping() { + buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; + buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + + if (buffer_width > 80) buffer_width = 80; + + back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; clear_cell.characters[1] = 0; @@ -271,17 +279,22 @@ static void initialize_buffer_flipping() buffer_flipping_initialized = TRUE; } +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + static void back_buffer_flip() { - cell_t * back_cell = &back_buffer.cells[0][0]; - cell_t * front_cell = &front_buffer.cells[0][0]; + cell_t * back_cell = back_buffer.cells; + cell_t * front_cell = front_buffer.cells; COORD pos; if (!buffer_flipping_initialized) return; - for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { - for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { if (back_cell->attribute != front_cell->attribute) { WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); front_cell->attribute = back_cell->attribute; @@ -303,15 +316,16 @@ static void back_buffer_flip() static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) { - cell_t * dst = &buffer->cells[y][x]; - cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; } static void back_buffer_write(cell_t * cell, int x, int y) { - back_buffer.cells[y][x] = *cell; + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -319,8 +333,8 @@ static void back_buffer_clear_to_end_of_line(int x, int y) cell_t * cell; cell_t *sentinel; - cell = &back_buffer.cells[y][x]; - sentinel = &back_buffer.cells[y+1][0]; + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; } From 64cec86abb765d777ddaf738bbdfaf9edb2b587e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 6 May 2018 06:04:33 -0400 Subject: [PATCH 06/42] more performance fixes for the port code portion --- sys/winnt/nttty.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d6bd4c582..e19244703 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -225,10 +225,6 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') -#define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 26 -#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) - typedef struct { WCHAR characters[2]; int count; @@ -236,9 +232,12 @@ typedef struct { } cell_t; typedef struct { - cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; + cell_t * cells; } console_buffer_t; +static int buffer_width; +static int buffer_height; + console_buffer_t back_buffer; console_buffer_t front_buffer; cell_t clear_cell; @@ -247,6 +246,7 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; static void initialize_buffer_flipping(); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); @@ -257,6 +257,14 @@ static void back_buffer_write(cell_t * cell, int x, int y); static void initialize_buffer_flipping() { + buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; + buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + + if (buffer_width > 80) buffer_width = 80; + + back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; clear_cell.characters[1] = 0; @@ -271,17 +279,22 @@ static void initialize_buffer_flipping() buffer_flipping_initialized = TRUE; } +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + static void back_buffer_flip() { - cell_t * back_cell = &back_buffer.cells[0][0]; - cell_t * front_cell = &front_buffer.cells[0][0]; + cell_t * back_cell = back_buffer.cells; + cell_t * front_cell = front_buffer.cells; COORD pos; if (!buffer_flipping_initialized) return; - for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { - for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { if (back_cell->attribute != front_cell->attribute) { WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); front_cell->attribute = back_cell->attribute; @@ -303,15 +316,16 @@ static void back_buffer_flip() static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) { - cell_t * dst = &buffer->cells[y][x]; - cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; } static void back_buffer_write(cell_t * cell, int x, int y) { - back_buffer.cells[y][x] = *cell; + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -319,8 +333,8 @@ static void back_buffer_clear_to_end_of_line(int x, int y) cell_t * cell; cell_t *sentinel; - cell = &back_buffer.cells[y][x]; - sentinel = &back_buffer.cells[y+1][0]; + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; } From b7f351fdbbcac1812710c426a03892c1f090bb89 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 13:22:36 -0700 Subject: [PATCH 07/42] Updated console back buffer support to correctly size the buffers as appropriate. --- sys/winnt/nttty.c | 188 +++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 67 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index e19244703..1f95e4b97 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -188,8 +188,9 @@ static const WCHAR cp437[] = { }; /* - * cpConsole provides the mapping of characters in the console code page to UNICODE. - * It maps a character to at most two WCHARs storing the number of WCHARs in count. + * cpConsole provides the mapping of characters in the console code page to + * UNICODE. It maps a character to at most two WCHARs storing the number of + * WCHARs in count. * * NOTE: cpConsole is only valid if has_unicode is TRUE. */ @@ -208,7 +209,8 @@ static void initialize_cp_console() for (int i = 0; i < 256; i++) { char c = (char)i; - cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, &cpConsole[i].characters[0], 2); + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, + &cpConsole[i].characters[0], 2); } } } @@ -216,13 +218,17 @@ static void initialize_cp_console() /* * Console Buffer Flipping Support * - * To minimize the number of calls into the WriteConsoleOutputXXX methods, we implement a notion - * of a console back buffer which keeps the next frame of console output as it is being composed. - * When ready to show the new frame, we compare this next frame to what is currently being output - * and only call WriteConsoleOutputXXX for those console values that need to change. + * To minimize the number of calls into the WriteConsoleOutputXXX methods, + * we implement a notion of a console back buffer which keeps the next frame + * of console output as it is being composed. When ready to show the new + * frame, we compare this next frame to what is currently being output and + * only call WriteConsoleOutputXXX for those console values that need to + * change. + * */ -#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ + | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') typedef struct { @@ -245,25 +251,28 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; -static void initialize_buffer_flipping(); +static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, int x, int y); +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, + int x, int y); static void back_buffer_clear_to_end_of_line(int x, int y); static void back_buffer_write(cell_t * cell, int x, int y); - -static void initialize_buffer_flipping() +static void initialize_buffer_flipping(int width, int height) { - buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; - buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + if (buffer_flipping_initialized) { + check_buffer_size(width, height); + return; + } - if (buffer_width > 80) buffer_width = 80; + buffer_width = 0; + buffer_height = 0; - back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); - front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + back_buffer.cells = NULL; + front_buffer.cells = NULL; clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; @@ -273,12 +282,43 @@ static void initialize_buffer_flipping() undefined_cell = clear_cell; undefined_cell.count = 0; - buffer_fill_to_end(&front_buffer, &undefined_cell, 0, 0); - buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + check_buffer_size(width, height); buffer_flipping_initialized = TRUE; } +static void resize_buffer(console_buffer_t * buffer, cell_t * fill, + int width, int height) +{ + cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); + cell_t * dst = cells; + cell_t * sentinel = dst + (width * height); + + while (dst != sentinel) + *dst++ = *fill; + + int height_to_copy = (buffer_height > height ? height : buffer_height); + int bytes_to_copy = (buffer_width > width ? width : buffer_width) + * sizeof(cell_t); + + for (int y = 0; y < height_to_copy; y++) + memcpy(cells + (width * y), buffer->cells + (buffer_width * y), + bytes_to_copy); + + free(buffer->cells); + buffer->cells = cells; +} + +static void check_buffer_size(int width, int height) +{ + if (width != buffer_width || height != buffer_height) { + resize_buffer(&back_buffer, &clear_cell, width, height); + resize_buffer(&front_buffer, &undefined_cell, width, height); + buffer_width = width; + buffer_height = height; + } +} + static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) { return buffer->cells + (buffer_width * y) + x; @@ -286,35 +326,41 @@ static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) static void back_buffer_flip() { - cell_t * back_cell = back_buffer.cells; - cell_t * front_cell = front_buffer.cells; - COORD pos; - if (!buffer_flipping_initialized) return; + cell_t * back = back_buffer.cells; + cell_t * front = front_buffer.cells; + COORD pos; + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { - for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { - if (back_cell->attribute != front_cell->attribute) { - WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); - front_cell->attribute = back_cell->attribute; + for (pos.X = 0; pos.X < buffer_width; pos.X++) { + if (back->attribute != front->attribute) { + WriteConsoleOutputAttribute(hConOut, &back->attribute, + 1, pos, &acount); + front->attribute = back->attribute; } - if (back_cell->count != front_cell->count || - back_cell->characters[0] != front_cell->characters[0] || - back_cell->characters[1] != front_cell->characters[1]) { + if (back->count != front->count || + back->characters[0] != front->characters[0] || + back->characters[1] != front->characters[1]) { if (has_unicode) { - WriteConsoleOutputCharacterW(hConOut, back_cell->characters, back_cell->count, pos, &ccount); + WriteConsoleOutputCharacterW(hConOut, back->characters, + back->count, pos, &ccount); } else { - char ch = (char)back_cell->characters[0]; - WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, &ccount); + char ch = (char)back->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, + &ccount); } - *front_cell = *back_cell; + *front = *back; } + back++; + front++; } } } -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, + int x, int y) { cell_t * dst = buffer_get_cell(buffer, x, y); cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); @@ -385,7 +431,6 @@ setftty() adjust_palette(); #endif start_screen(); - initialize_buffer_flipping(); } void @@ -462,7 +507,16 @@ DWORD ctrltype; } } -/* called by init_tty in wintty.c for WIN32 port only */ +/* + * ntty_open() is called in several places. It is called by win_tty_init + * passing in a mode of zero. It is then later called again by pcmain passing + * in a mode of one. Finally, it can also be called by process_options also + * with a mode of one. + * + * barthouse - The fact this is getting called multiple times needs to be + * reviewed and perhaps cleaned up. + * + */ void nttty_open(mode) int mode; @@ -503,6 +557,9 @@ int mode; mode = 0; goto try; } else { + /* barthouse - Need to understand how this can happen and + * whether we should bail instead of returning. + */ return; } @@ -510,6 +567,24 @@ int mode; hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConOut, &csbi); + + int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + int width = min(csbi.srWindow.Right - csbi.srWindow.Left + 1, 80); + + /* If the window is not big enough to meet our minimum requirements, + * grow the console's buffer to be large enough. The user will have + * to manually extend the size of the window. + */ + + width = max(80, width); + height = max(25, height); + + COORD size = { max(80, width), max(25, height) }; + SetConsoleScreenBufferSize(hConOut, size); + + initialize_buffer_flipping(width, height); + load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() @@ -534,7 +609,10 @@ int mode; /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } - get_scr_size(); + + LI = height; + CO = width; + console.cursor.X = console.cursor.Y = 0; really_move_cursor(); } @@ -559,32 +637,6 @@ nttty_kbhit() return pNHkbhit(hConIn, &ir); } -void -get_scr_size() -{ - int lines, cols; - - GetConsoleScreenBufferInfo(hConOut, &csbi); - - lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); - cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1); - - LI = lines; - CO = min(cols, 80); - - if ((LI < 25) || (CO < 80)) { - COORD newcoord; - - LI = 25; - CO = 80; - - newcoord.Y = LI; - newcoord.X = CO; - - SetConsoleScreenBufferSize(hConOut, newcoord); - } -} - int tgetch() { @@ -824,8 +876,10 @@ cl_eos() int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { - buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); - buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); DWORD ccnt; COORD newcoord; @@ -1240,10 +1294,10 @@ VA_DECL(const char *, fmt) else { if(!init_ttycolor_completed) init_ttycolor(); - xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); + really_move_cursor(); } VA_END(); return; From f2e9b8a60ab182cb68564d82cf2dd642bf1daa9f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 6 May 2018 17:52:29 -0400 Subject: [PATCH 08/42] merge glitch cleanup --- sys/winnt/nttty.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 0567d4776..128c4de6c 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nttty.c $NHDT-Date: 1524931557 2018/04/28 16:05:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.71 $ */ +/* NetHack 3.6 nttty.c $NHDT-Date: 1525643540 2018/05/06 21:52:20 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,7 @@ * Switch to low level console output routines M. Allison 2003/10/01 * Restrict cursor movement until input pending M. Lehotay 2003/10/02 * Call Unicode version of output API on NT R. Chason 2005/10/28 + * Use of back buffer to improve performance B. House 2018/05/06 * */ @@ -289,9 +290,6 @@ static void initialize_buffer_flipping(int width, int height) static void resize_buffer(console_buffer_t * buffer, cell_t * fill, int width, int height) - return buffer->cells + (buffer_width * y) + x; -} - { cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); cell_t * dst = cells; From 4b922f3e8b77b731e6735bca2fedbb8caa3fc2a8 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:13:30 -0700 Subject: [PATCH 09/42] Implemented a fix to the lag problems that are occuring with the Win32 console port. The fix implements a console back buffer which significantly reduces the number of calls made to WriteConsoleOutputXXX and eliminates the lag users have been experiencing. --- sys/winnt/nttty.c | 401 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 319 insertions(+), 82 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index f0532b083..f4c3a3bf8 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -151,6 +151,240 @@ SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; +/* CP437 to Unicode mapping according to the Unicode Consortium */ +static const WCHAR cp437[] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 +}; + +/* + * cpConsole provides the mapping of characters in the console code page to + * UNICODE. It maps a character to at most two WCHARs storing the number of + * WCHARs in count. + * + * NOTE: cpConsole is only valid if has_unicode is TRUE. + */ + +typedef struct { + WCHAR characters[2]; + int count; +} CodePageMapping; + +static CodePageMapping cpConsole[256]; + +static void initialize_cp_console() +{ + if (has_unicode) { + UINT codePage = GetConsoleOutputCP(); + + for (int i = 0; i < 256; i++) { + char c = (char)i; + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, + &cpConsole[i].characters[0], 2); + } + } +} + +/* + * Console Buffer Flipping Support + * + * To minimize the number of calls into the WriteConsoleOutputXXX methods, + * we implement a notion of a console back buffer which keeps the next frame + * of console output as it is being composed. When ready to show the new + * frame, we compare this next frame to what is currently being output and + * only call WriteConsoleOutputXXX for those console values that need to + * change. + * + */ + +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ + | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_CHARACTER (' ') + +typedef struct { + WCHAR characters[2]; + int count; + WORD attribute; +} cell_t; + +typedef struct { + cell_t * cells; +} console_buffer_t; + +static int buffer_width; +static int buffer_height; + +console_buffer_t back_buffer; +console_buffer_t front_buffer; +cell_t clear_cell; +cell_t undefined_cell; + +static boolean buffer_flipping_initialized = FALSE; + +static void check_buffer_size(int width, int height); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); + +static void back_buffer_flip(); + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, + int x, int y); +static void back_buffer_clear_to_end_of_line(int x, int y); +static void back_buffer_write(cell_t * cell, int x, int y); + +static void initialize_buffer_flipping(int width, int height) +{ + if (buffer_flipping_initialized) { + check_buffer_size(width, height); + return; + } + + buffer_width = 0; + buffer_height = 0; + + back_buffer.cells = NULL; + front_buffer.cells = NULL; + + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; + clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; + clear_cell.characters[1] = 0; + clear_cell.count = 1; + + undefined_cell = clear_cell; + undefined_cell.count = 0; + + check_buffer_size(width, height); + + buffer_flipping_initialized = TRUE; +} + +static void resize_buffer(console_buffer_t * buffer, cell_t * fill, + int width, int height) +{ + cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); + cell_t * dst = cells; + cell_t * sentinel = dst + (width * height); + + while (dst != sentinel) + *dst++ = *fill; + + int height_to_copy = (buffer_height > height ? height : buffer_height); + int bytes_to_copy = (buffer_width > width ? width : buffer_width) + * sizeof(cell_t); + + for (int y = 0; y < height_to_copy; y++) + memcpy(cells + (width * y), buffer->cells + (buffer_width * y), + bytes_to_copy); + + free(buffer->cells); + buffer->cells = cells; +} + +static void check_buffer_size(int width, int height) +{ + if (width != buffer_width || height != buffer_height) { + resize_buffer(&back_buffer, &clear_cell, width, height); + resize_buffer(&front_buffer, &undefined_cell, width, height); + buffer_width = width; + buffer_height = height; + } +} + +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + +static void back_buffer_flip() +{ + if (!buffer_flipping_initialized) + return; + + cell_t * back = back_buffer.cells; + cell_t * front = front_buffer.cells; + COORD pos; + + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++) { + if (back->attribute != front->attribute) { + WriteConsoleOutputAttribute(hConOut, &back->attribute, + 1, pos, &acount); + front->attribute = back->attribute; + } + if (back->count != front->count || + back->characters[0] != front->characters[0] || + back->characters[1] != front->characters[1]) { + if (has_unicode) { + WriteConsoleOutputCharacterW(hConOut, back->characters, + back->count, pos, &ccount); + } else { + char ch = (char)back->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, + &ccount); + } + *front = *back; + } + back++; + front++; + } + } +} + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, + int x, int y) +{ + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); + while (dst != sentinel) + *dst++ = clear_cell; +} + +static void back_buffer_write(cell_t * cell, int x, int y) +{ + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; +} + +static void back_buffer_clear_to_end_of_line(int x, int y) +{ + cell_t * cell; + cell_t *sentinel; + + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); + while (cell != sentinel) + *cell++ = clear_cell; +} + /* * Called after returning from ! or ^Z */ @@ -197,7 +431,6 @@ setftty() adjust_palette(); #endif start_screen(); - has_unicode = ((GetVersion() & 0x80000000) == 0); } void @@ -232,6 +465,10 @@ tty_end_screen() clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -270,7 +507,16 @@ DWORD ctrltype; } } -/* called by init_tty in wintty.c for WIN32 port only */ +/* + * ntty_open() is called in several places. It is called by win_tty_init + * passing in a mode of zero. It is then later called again by pcmain passing + * in a mode of one. Finally, it can also be called by process_options also + * with a mode of one. + * + * barthouse - The fact this is getting called multiple times needs to be + * reviewed and perhaps cleaned up. + * + */ void nttty_open(mode) int mode; @@ -279,6 +525,10 @@ int mode; DWORD cmode; long mask; + has_unicode = ((GetVersion() & 0x80000000) == 0); + + initialize_cp_console(); + GUILaunched = 0; try : @@ -307,6 +557,9 @@ int mode; mode = 0; goto try; } else { + /* barthouse - Need to understand how this can happen and + * whether we should bail instead of returning. + */ return; } @@ -314,6 +567,30 @@ int mode; hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConOut, &csbi); + + int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + /* NOTE: We currently force to a width of 80 due to unresolved issues + * within the TTY code. These issues will need to resolved before + * we could allow widths > 80. We will always need a width of + * atleast 80. + */ + + int width = 80; + + /* If the window is not big enough to meet our minimum height needs, + * grow the console's buffer to be large enough. The user will have + * to manually extend the size of the window. + */ + + height = max(25, height); + + COORD size = { width, height }; + SetConsoleScreenBufferSize(hConOut, size); + + initialize_buffer_flipping(width, height); + load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() @@ -338,7 +615,10 @@ int mode; /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } - get_scr_size(); + + LI = height; + CO = width; + console.cursor.X = console.cursor.Y = 0; really_move_cursor(); } @@ -363,32 +643,6 @@ nttty_kbhit() return pNHkbhit(hConIn, &ir); } -void -get_scr_size() -{ - int lines, cols; - - GetConsoleScreenBufferInfo(hConOut, &csbi); - - lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); - cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1); - - LI = lines; - CO = min(cols, 80); - - if ((LI < 25) || (CO < 80)) { - COORD newcoord; - - LI = 25; - CO = 80; - - newcoord.Y = LI; - newcoord.X = CO; - - SetConsoleScreenBufferSize(hConOut, newcoord); - } -} - int tgetch() { @@ -440,6 +694,8 @@ really_move_cursor() console.cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, console.cursor); + + back_buffer_flip(); } void @@ -498,6 +754,7 @@ xputc_core(ch) char ch; { boolean inverse = FALSE; + cell_t cell; switch (ch) { case '\n': console.cursor.Y++; @@ -515,17 +772,19 @@ char ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? - BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); + BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + + cell.attribute = console.attr; if (has_unicode) { - /* Avoid bug in ANSI API on WinNT */ - WCHAR c2[2]; - int rc; - rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2); - WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount); + cell.characters[0] = cpConsole[ch].characters[0]; + cell.characters[1] = cpConsole[ch].characters[1]; + cell.count = cpConsole[ch].count; } else { - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + cell.characters[1] = 0; + cell.count = 1; } + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); console.cursor.X++; } } @@ -535,46 +794,11 @@ char ch; * for win32. It is used for glyphs only, not text. */ -/* CP437 to Unicode mapping according to the Unicode Consortium */ -static const WCHAR cp437[] = { - 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, - 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, - 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, - 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, - 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 -}; - void g_putch(in_ch) int in_ch; { + cell_t cell; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -587,23 +811,24 @@ int in_ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); - + cell.attribute = console.attr; + cell.characters[1] = 0; + cell.count = 1; if (has_unicode) - WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount); + cell.characters[0] = cp437[ch]; else - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); } void cl_end() { - int cx; console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; - cx = CO - console.cursor.X; - FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount); - FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount); + + back_buffer_clear_to_end_of_line(console.cursor.X, console.cursor.Y); + tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } @@ -611,6 +836,10 @@ void raw_clear_screen() { if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -621,6 +850,7 @@ raw_clear_screen() csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); + } } @@ -651,11 +881,18 @@ cl_eos() { int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; + FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); @@ -1063,10 +1300,10 @@ VA_DECL(const char *, fmt) else { if(!init_ttycolor_completed) init_ttycolor(); - xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); + really_move_cursor(); } VA_END(); return; From d2a7c8afa1c992ecf9782a1b54b6f215bcad680f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 08:41:54 -0400 Subject: [PATCH 10/42] some status data corrections --- src/botl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/botl.c b/src/botl.c index 5b573d856..68a38b62b 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1525563781 2018/05/05 23:43:01 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.90 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1525696908 2018/05/07 12:41:48 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.91 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -483,14 +483,14 @@ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { INIT_BLSTAT("charisma", " Ch:%s", ANY_INT, 10, BL_CH), INIT_BLSTAT("alignment", " %s", ANY_STR, 40, BL_ALIGN), INIT_BLSTAT("score", " S:%s", ANY_LONG, 20, BL_SCORE), - INIT_BLSTAT("carrying-capacity", " %s", ANY_LONG, 20, BL_CAP), + INIT_BLSTAT("carrying-capacity", " %s", ANY_INT, 20, BL_CAP), INIT_BLSTAT("gold", " %s", ANY_LONG, 30, BL_GOLD), INIT_BLSTATP("power", " Pw:%s", ANY_INT, 10, BL_ENEMAX, BL_ENE), INIT_BLSTAT("power-max", "(%s)", ANY_INT, 10, BL_ENEMAX), - INIT_BLSTAT("experience-level", " Xp:%s", ANY_LONG, 10, BL_XP), + INIT_BLSTAT("experience-level", " Xp:%s", ANY_INT, 10, BL_XP), INIT_BLSTAT("armor-class", " AC:%s", ANY_INT, 10, BL_AC), INIT_BLSTAT("HD", " HD:%s", ANY_INT, 10, BL_HD), - INIT_BLSTAT("time", " T:%s", ANY_INT, 20, BL_TIME), + INIT_BLSTAT("time", " T:%s", ANY_LONG, 20, BL_TIME), INIT_BLSTAT("hunger", " %s", ANY_UINT, 40, BL_HUNGER), INIT_BLSTATP("hitpoints", " HP:%s", ANY_INT, 10, BL_HPMAX, BL_HP), INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX), @@ -630,7 +630,7 @@ bot_via_windowport() /* Experience */ blstats[idx][BL_XP].a.a_int = u.ulevel; - blstats[idx][BL_EXP].a.a_int = u.uexp; + blstats[idx][BL_EXP].a.a_long = u.uexp; /* Time (moves) */ blstats[idx][BL_TIME].a.a_long = moves; From b524c26da5aad614a47badafffe5d752d8e68182 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 18:52:50 -0400 Subject: [PATCH 11/42] intermediate update to wintty.c as work continues --- win/tty/wintty.c | 305 +++++++++++++++++++++++++---------------------- 1 file changed, 165 insertions(+), 140 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d0f364574..813351920 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,21 +176,7 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); - -#ifdef STATUS_HILITES -static long tty_condition_bits; -static struct tty_status_fields { - int color; - int attr; - coord loc; - boolean valid; -} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; -static int st_fld; -int hpbar_percent, hpbar_color; - -static int FDECL(condcolor, (long, unsigned long *)); -static int FDECL(condattr, (long, unsigned long *)); -#endif /* STATUS_HILITES */ +STATIC_DCL void FDECL(status_content, (winid, struct WinDesc *, const char *)); /* * A string containing all the default commands -- to add to a list @@ -2504,8 +2490,7 @@ const char *str; { register struct WinDesc *cw = 0; register char *ob; - register const char *nb; - register long i, j, n0; + register long i, n0; boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- @@ -2536,55 +2521,7 @@ const char *str; break; case NHW_STATUS: - ob = &cw->data[cw->cury][j = cw->curx]; - if (context.botlx) - *ob = 0; - if (!cw->cury && (int) strlen(str) >= CO) { - /* the characters before "St:" are unnecessary */ - nb = index(str, ':'); - if (nb && nb > str + 2) - str = nb - 2; - } - nb = str; -#ifdef STATUS_HILITES - if (prev_tty_status[st_fld].valid - && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x - && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y - && tty_status[st_fld].color == prev_tty_status[st_fld].color - && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) -#endif - attr_match = TRUE; - for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { - if (!*nb) { -#ifndef STATUS_HILITES - if (*ob || context.botlx) { -#else - if (context.botlx) { -#endif - /* last char printed may be in middle of line */ - tty_curs(WIN_STATUS, i, cw->cury); - cl_end(); - } - break; - } - if (*ob != *nb || !attr_match) { -#ifdef STATUS_HILITES - tty_curs(WIN_STATUS, - tty_status[st_fld].loc.x, - tty_status[st_fld].loc.y); -#endif - tty_putsym(WIN_STATUS, i, cw->cury, *nb); - } - if (*ob) - ob++; - } - - (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); - cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ -#ifndef STATUS_HILITES - cw->cury = (cw->cury + 1) % 2; - cw->curx = 0; -#endif + status_content(window, cw, str); break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); @@ -3444,6 +3381,13 @@ char *posbar; } #endif /* POSITIONBAR */ + +/* + * +------------------+ + * | STATUS CODE | + * +------------------+ + */ + /* * The following data structures come from the genl_ routines in * src/windows.c and as such are considered to be on the window-port @@ -3455,6 +3399,20 @@ extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; +#ifdef STATUS_HILITES +static int FDECL(condcolor, (long, unsigned long *)); +static int FDECL(condattr, (long, unsigned long *)); +static long tty_condition_bits; +static struct tty_status_fields { + int color; + int attr; + coord loc; + boolean valid; +} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; +static int st_fld; +int hpbar_percent, hpbar_color; +#endif + void tty_status_init() { @@ -3477,6 +3435,143 @@ tty_status_init() genl_status_init(); } +void +status_content(window, cw, str) +winid window; +struct WinDesc *cw; +const char *str; +{ + char *ob; + long i, j, n0; + const char *nb; + boolean attr_match = FALSE; + + ob = &cw->data[cw->cury][j = cw->curx]; + if (context.botlx) + *ob = 0; + if (!cw->cury && (int) strlen(str) >= CO) { + /* the characters before "St:" are unnecessary */ + nb = index(str, ':'); + if (nb && nb > str + 2) + str = nb - 2; + } + nb = str; +#ifdef STATUS_HILITES + if (prev_tty_status[st_fld].valid + && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x + && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y + && tty_status[st_fld].color == prev_tty_status[st_fld].color + && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) +#endif + attr_match = TRUE; + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { + if (!*nb) { +#ifndef STATUS_HILITES + if (*ob || context.botlx) { +#else + if (context.botlx) { +#endif + /* last char printed may be in middle of line */ + tty_curs(WIN_STATUS, i, cw->cury); + cl_end(); + } + break; + } + if (*ob != *nb || !attr_match) { +#ifdef STATUS_HILITES + tty_curs(WIN_STATUS, + tty_status[st_fld].loc.x, + tty_status[st_fld].loc.y); +#endif + tty_putsym(WIN_STATUS, i, cw->cury, *nb); + } + if (*ob) + ob++; + } + + (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); + cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ +#ifndef STATUS_HILITES + cw->cury = (cw->cury + 1) % 2; + cw->curx = 0; +#endif + return; +} + +#ifdef STATUS_HILITES +/* new approach through status_update() only */ +#define Begin_Attr(m) \ + if (m) { \ + if ((m) & HL_BOLD) \ + term_start_attr(ATR_BOLD); \ + if ((m) & HL_INVERSE) \ + term_start_attr(ATR_INVERSE); \ + if ((m) & HL_ULINE) \ + term_start_attr(ATR_ULINE); \ + if ((m) & HL_BLINK) \ + term_start_attr(ATR_BLINK); \ + if ((m) & HL_DIM) \ + term_start_attr(ATR_DIM); \ + } + +#define End_Attr(m) \ + if (m) { \ + if ((m) & HL_DIM) \ + term_end_attr(ATR_DIM); \ + if ((m) & HL_BLINK) \ + term_end_attr(ATR_BLINK); \ + if ((m) & HL_ULINE) \ + term_end_attr(ATR_ULINE); \ + if ((m) & HL_INVERSE) \ + term_end_attr(ATR_INVERSE); \ + if ((m) & HL_BOLD) \ + term_end_attr(ATR_BOLD); \ + } + +#ifdef TEXTCOLOR +#define MaybeDisplayCond(bm,txt) \ + if (tty_condition_bits & (bm)) { \ + tty_putstr(WIN_STATUS, 0, " "); \ + if (iflags.hilite_delta) { \ + attrmask = condattr(bm, colormasks); \ + Begin_Attr(attrmask); \ + if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ + term_start_color(coloridx); \ + } \ + tty_putstr(WIN_STATUS, 0, txt); \ + if (iflags.hilite_delta) { \ + if (coloridx != NO_COLOR) \ + term_end_color(); \ + End_Attr(attrmask); \ + } \ + } +#else +#define MaybeDisplayCond(bm,txt) \ + if (tty_condition_bits & (bm)) { \ + tty_putstr(WIN_STATUS, 0, " "); \ + if (iflags.hilite_delta) { \ + attrmask = condattr(bm, colormasks); \ + Begin_Attr(attrmask); \ + } \ + tty_putstr(WIN_STATUS, 0, txt); \ + if (iflags.hilite_delta) { \ + End_Attr(attrmask); \ + } \ + } +#endif + +#define Status_Putstr(s) \ + tty_status[st_fld].loc.x = (xchar) cw->curx; \ + tty_status[st_fld].loc.y = (xchar) cw->cury; \ + tty_status[st_fld].valid = TRUE; \ + tty_putstr(WIN_STATUS, 0, s); + +/* + * tty_status_init() + * -- initialize the tty-specific data structures. + * -- call genl_status_init() to initialize the general data. + */ + /* * *_status_update() * -- update the value of a status field. @@ -3530,76 +3625,6 @@ tty_status_init() * See doc/window.doc for more details. */ - -/* new approach through status_update() only */ -#define Begin_Attr(m) \ - if (m) { \ - if ((m) & HL_BOLD) \ - term_start_attr(ATR_BOLD); \ - if ((m) & HL_INVERSE) \ - term_start_attr(ATR_INVERSE); \ - if ((m) & HL_ULINE) \ - term_start_attr(ATR_ULINE); \ - if ((m) & HL_BLINK) \ - term_start_attr(ATR_BLINK); \ - if ((m) & HL_DIM) \ - term_start_attr(ATR_DIM); \ - } - -#define End_Attr(m) \ - if (m) { \ - if ((m) & HL_DIM) \ - term_end_attr(ATR_DIM); \ - if ((m) & HL_BLINK) \ - term_end_attr(ATR_BLINK); \ - if ((m) & HL_ULINE) \ - term_end_attr(ATR_ULINE); \ - if ((m) & HL_INVERSE) \ - term_end_attr(ATR_INVERSE); \ - if ((m) & HL_BOLD) \ - term_end_attr(ATR_BOLD); \ - } - -#ifdef STATUS_HILITES - -#ifdef TEXTCOLOR -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ - term_start_color(coloridx); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - if (coloridx != NO_COLOR) \ - term_end_color(); \ - End_Attr(attrmask); \ - } \ - } -#else -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - End_Attr(attrmask); \ - } \ - } -#endif -#define status_putstr(s) \ - tty_status[st_fld].loc.x = (xchar) cw->curx; \ - tty_status[st_fld].loc.y = (xchar) cw->cury; \ - tty_status[st_fld].valid = TRUE; \ - tty_putstr(WIN_STATUS, 0, s); - - void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) int fldidx, chg UNUSED, percent UNUSED, color; @@ -3678,7 +3703,7 @@ unsigned long *colormasks; text = status_vals[fldidx1]; if (iflags.hilite_delta) { if (*text == ' ') { - status_putstr(" "); + Status_Putstr(" "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3689,7 +3714,7 @@ unsigned long *colormasks; #endif } - status_putstr(text); + Status_Putstr(text); if (iflags.hilite_delta) { #ifdef TEXTCOLOR @@ -3722,7 +3747,7 @@ unsigned long *colormasks; } } if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - status_putstr("["); + Status_Putstr("["); #ifdef TEXTCOLOR coloridx = hpbar_color & 0x00FF; /* attridx = (hpbar_color & 0xFF00) >> 8; */ @@ -3778,7 +3803,7 @@ unsigned long *colormasks; /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); } else { - status_putstr(text); + Status_Putstr(text); } if (iflags.hilite_delta) { From e90b20a3a9bd5dedac96722b370a70da9c1c0d89 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 20:20:36 -0400 Subject: [PATCH 12/42] optimization of output was ruining display effects --- sys/winnt/nttty.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 2ed5d7c14..9d1114498 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -252,6 +252,8 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; +boolean do_immediate_flips = FALSE; + static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); @@ -367,12 +369,18 @@ static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; + + if (do_immediate_flips && buffer == &back_buffer) + back_buffer_flip(); } static void back_buffer_write(cell_t * cell, int x, int y) { cell_t * dst = buffer_get_cell(&back_buffer, x, y); *dst = *cell; + + if (do_immediate_flips) + back_buffer_flip(); } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -384,6 +392,9 @@ static void back_buffer_clear_to_end_of_line(int x, int y) sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; + + if (do_immediate_flips) + back_buffer_flip(); } /* @@ -922,6 +933,7 @@ tty_delay_output() int k; goal = 50 + clock(); + back_buffer_flip(); while (goal > clock()) { k = junk; /* Do nothing */ } From 9bca6ecb8e1bf0f22b3765b3583a79c000223fe7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 13:12:11 -0400 Subject: [PATCH 13/42] tty status updates some status code cleanup It should be ready to merge tty-status changes into NetHack-3.6.0. --- win/tty/wintty.c | 619 ++++++++++++++++++++++++++--------------------- 1 file changed, 339 insertions(+), 280 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 813351920..ac3fe384f 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1525563766 2018/05/05 23:42:46 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.144 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1525885919 2018/05/09 17:11:59 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -176,7 +176,9 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); -STATIC_DCL void FDECL(status_content, (winid, struct WinDesc *, const char *)); +STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); +STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); +STATIC_DCL void NDECL(render_status); /* * A string containing all the default commands -- to add to a list @@ -2504,7 +2506,11 @@ const char *str; if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; +#ifndef STATUS_HILITES if (cw->type != NHW_MESSAGE) +#else + if (cw->type != NHW_MESSAGE && cw->type != NHW_STATUS) +#endif str = compress_str(str); ttyDisplay->lastwin = window; @@ -2521,7 +2527,7 @@ const char *str; break; case NHW_STATUS: - status_content(window, cw, str); + status_putstr(window, cw, str); break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); @@ -3393,7 +3399,6 @@ char *posbar; * src/windows.c and as such are considered to be on the window-port * "side" of things, rather than the NetHack-core "side" of things. */ - extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; @@ -3403,16 +3408,51 @@ extern winid WIN_STATUS; static int FDECL(condcolor, (long, unsigned long *)); static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; +static unsigned long *tty_colormasks; static struct tty_status_fields { int color; int attr; - coord loc; + int x, y; + size_t lth; boolean valid; -} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; + boolean redraw; +} tty_status[2][MAXBLSTATS]; static int st_fld; int hpbar_percent, hpbar_color; +struct condition_t { + long mask; + char *text[3]; /* 3 potential display values, progressively smaller */ +} conditions[] = { + /* The sequence order of these matters */ + { BL_MASK_STONE, {"Stone", "Ston", "Sto"}}, + { BL_MASK_SLIME, {"Slime", "Slim", "Slm"}}, + { BL_MASK_STRNGL, {"Strngl", "Stngl", "Str"}}, + { BL_MASK_FOODPOIS, {"FoodPois", "Fpois", "Poi"}}, + { BL_MASK_TERMILL, {"TermIll" , "Ill", "Ill"}}, + { BL_MASK_BLIND, {"Blind", "Blnd", "Bl"}}, + { BL_MASK_DEAF, {"Deaf", "Def", "Df"}}, + { BL_MASK_STUN, {"Stun", "Stun", "St"}}, + { BL_MASK_CONF, {"Conf", "Cnf", "Cn"}}, + { BL_MASK_HALLU, {"Hallu", "Hal", "Ha"}}, + { BL_MASK_LEV, {"Lev", "Lev", "Lv"}}, + { BL_MASK_FLY, {"Fly", "Fly", "Fl"}}, + { BL_MASK_RIDE, {"Ride", "Rid", "Ri"}}, +}; +enum statusfields fieldorder[2][15] = { + { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, + BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, + BL_FLUSH }, + { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, + BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, + BL_CAP, BL_CONDITION, BL_FLUSH } +}; #endif +/* + * tty_status_init() + * -- initialize the tty-specific data structures. + * -- call genl_status_init() to initialize the general data. + */ void tty_status_init() { @@ -3420,12 +3460,13 @@ tty_status_init() int i; for (i = 0; i < MAXBLSTATS; ++i) { - tty_status[i].color = NO_COLOR; /* no color */ - tty_status[i].attr = ATR_NONE; - tty_status[i].loc.x = 0; - tty_status[i].loc.y = 0; - tty_status[i].valid = FALSE; - prev_tty_status[i] = tty_status[i]; + tty_status[NOW][i].color = NO_COLOR; /* no color */ + tty_status[NOW][i].attr = ATR_NONE; + tty_status[NOW][i].x = 0; + tty_status[NOW][i].y = 0; + tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].redraw = FALSE; + tty_status[BEFORE][i] = tty_status[NOW][i]; } tty_condition_bits = 0L; hpbar_percent = 0, hpbar_color = NO_COLOR; @@ -3435,8 +3476,21 @@ tty_status_init() genl_status_init(); } -void -status_content(window, cw, str) +/* + * status_putstr() is not intended to be called directly + * by anything other than tty_putstr(). tty_putstr() + * does the prereq validations, and initializations of + * window and cw. + * + * Moving the status handling code here from tty_putstr() + * allows access to status data structures defined just + * above, rather than up top, with the additional bonus + * of having most status-related code bits fairly close + * together. + * + */ +static void +status_putstr(window, cw, str) winid window; struct WinDesc *cw; const char *str; @@ -3444,7 +3498,6 @@ const char *str; char *ob; long i, j, n0; const char *nb; - boolean attr_match = FALSE; ob = &cw->data[cw->cury][j = cw->curx]; if (context.botlx) @@ -3456,14 +3509,6 @@ const char *str; str = nb - 2; } nb = str; -#ifdef STATUS_HILITES - if (prev_tty_status[st_fld].valid - && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x - && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y - && tty_status[st_fld].color == prev_tty_status[st_fld].color - && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) -#endif - attr_match = TRUE; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES @@ -3477,14 +3522,20 @@ const char *str; } break; } - if (*ob != *nb || !attr_match) { -#ifdef STATUS_HILITES - tty_curs(WIN_STATUS, - tty_status[st_fld].loc.x, - tty_status[st_fld].loc.y); +#ifndef STATUS_HILITES + if (*ob != *nb) { +#else + if (*ob != *nb || tty_status[NOW][st_fld].redraw) { #endif tty_putsym(WIN_STATUS, i, cw->cury, *nb); } +#ifdef STATUS_HILITES + else { + /* tty_curs(window, x, y); */ + ttyDisplay->curx++; + cw->curx++; + } +#endif if (*ob) ob++; } @@ -3499,78 +3550,6 @@ const char *str; } #ifdef STATUS_HILITES -/* new approach through status_update() only */ -#define Begin_Attr(m) \ - if (m) { \ - if ((m) & HL_BOLD) \ - term_start_attr(ATR_BOLD); \ - if ((m) & HL_INVERSE) \ - term_start_attr(ATR_INVERSE); \ - if ((m) & HL_ULINE) \ - term_start_attr(ATR_ULINE); \ - if ((m) & HL_BLINK) \ - term_start_attr(ATR_BLINK); \ - if ((m) & HL_DIM) \ - term_start_attr(ATR_DIM); \ - } - -#define End_Attr(m) \ - if (m) { \ - if ((m) & HL_DIM) \ - term_end_attr(ATR_DIM); \ - if ((m) & HL_BLINK) \ - term_end_attr(ATR_BLINK); \ - if ((m) & HL_ULINE) \ - term_end_attr(ATR_ULINE); \ - if ((m) & HL_INVERSE) \ - term_end_attr(ATR_INVERSE); \ - if ((m) & HL_BOLD) \ - term_end_attr(ATR_BOLD); \ - } - -#ifdef TEXTCOLOR -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ - term_start_color(coloridx); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - if (coloridx != NO_COLOR) \ - term_end_color(); \ - End_Attr(attrmask); \ - } \ - } -#else -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - End_Attr(attrmask); \ - } \ - } -#endif - -#define Status_Putstr(s) \ - tty_status[st_fld].loc.x = (xchar) cw->curx; \ - tty_status[st_fld].loc.y = (xchar) cw->cury; \ - tty_status[st_fld].valid = TRUE; \ - tty_putstr(WIN_STATUS, 0, s); - -/* - * tty_status_init() - * -- initialize the tty-specific data structures. - * -- call genl_status_init() to initialize the general data. - */ /* * *_status_update() @@ -3627,63 +3606,152 @@ const char *str; void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) -int fldidx, chg UNUSED, percent UNUSED, color; +int fldidx, chg UNUSED, percent, color; genericptr_t ptr; unsigned long *colormasks; { long *condptr = (long *) ptr; - int i, attrmask = 0; -#ifdef TEXTCOLOR - int coloridx = NO_COLOR; -#endif - struct WinDesc *cw = 0; - char *text = (char *) ptr; - static boolean oncearound = FALSE; /* prevent premature partial display */ - enum statusfields fieldorder[2][15] = { - { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, - BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, - BL_FLUSH }, - { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, - BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, - BL_CAP, BL_CONDITION, BL_FLUSH } - }; - int attridx = 0; - st_fld = fldidx; + boolean do_color = FALSE; + boolean force_update = FALSE; - if (fldidx != BL_FLUSH) { - if (!status_activefields[fldidx]) - return; - switch (fldidx) { - case BL_CONDITION: - tty_condition_bits = *condptr; - oncearound = TRUE; +#ifdef TEXTCOLOR + do_color = TRUE; +#endif + + if (fldidx != BL_FLUSH && !status_activefields[fldidx]) + return; + + switch (fldidx) { + case BL_FLUSH: + force_update = TRUE; break; - default: + case BL_CONDITION: + tty_condition_bits = *condptr; + tty_colormasks = colormasks; + tty_status[NOW][fldidx].valid = TRUE; + break; + default: Sprintf(status_vals[fldidx], status_fieldfmt[fldidx] ? - status_fieldfmt[fldidx] : "%s", - text); -#ifdef TEXTCOLOR - tty_status[fldidx].color = (color & 0x00FF); -#else - tty_status[fldidx].color = NO_COLOR; -#endif - tty_status[fldidx].attr = (color & 0xFF00) >> 8; - - if (iflags.wc2_hitpointbar && fldidx == BL_HP) { - hpbar_percent = percent; -#ifdef TEXTCOLOR - hpbar_color = color; -#else - hpbar_color = NO_COLOR; -#endif - } - break; - } + status_fieldfmt[fldidx] : "%s", text); + tty_status[NOW][fldidx].color = do_color ? (color & 0x00FF) + : NO_COLOR; + tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; + tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); + tty_status[NOW][fldidx].valid = TRUE; + break; } - if (!oncearound) return; + /* Special additional processing for hitpointbar */ + if (iflags.wc2_hitpointbar && fldidx == BL_HP) { + hpbar_percent = percent; + hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; + } + + /* special case fixups */ + if (iflags.wc2_hitpointbar && fldidx == BL_TITLE) + tty_status[NOW][fldidx].lth += 2; /* [ and ] */ + if (fldidx == BL_GOLD) + tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ + + if (check_fields(force_update)) + render_status(); + return; +} + +/* + * This is the routine where we figure out where each field + * should be placed, and flag whether the on-screen details + * must be updated because they need to change. + * This is now done at an individual field case-by-case level. + */ +boolean +check_fields(forcefields) +boolean forcefields; +{ + int i, row, col; + boolean valid = TRUE, update_right; + + for (row = 0; row < 2; ++row) { + col = 1; + update_right = FALSE; + for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { + int idx = fieldorder[row][i]; + + if (!status_activefields[idx]) + continue; + + if (!tty_status[NOW][idx].valid) + valid = FALSE; + + tty_status[NOW][idx].y = row; + tty_status[NOW][idx].x = col; + if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) + update_right = TRUE; + /* + * status_putstr(), called from tty_putstr() checks + * whether individual tty cell text content matches what + * was already there and optimizes by leaving it be. + * Checking the text iself was sufficient back when the + * status lines were monochrome and of a single + * attribute style. + * + * With STATUS_HILITES, it is possible that the color + * needs to change even if the text is the same, so + * we flag that here by setting .redraw. + * Then, status_putstr() will see that flag setting + * and ensure that the tty cell content is updated. + */ + if (forcefields || update_right + || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color + || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) + tty_status[NOW][idx].redraw = TRUE; + col += tty_status[NOW][idx].lth; + } + } + return valid; +} + +#define Begin_Attr(m) \ + if (m) { \ + if ((m) & HL_BOLD) \ + term_start_attr(ATR_BOLD); \ + if ((m) & HL_INVERSE) \ + term_start_attr(ATR_INVERSE); \ + if ((m) & HL_ULINE) \ + term_start_attr(ATR_ULINE); \ + if ((m) & HL_BLINK) \ + term_start_attr(ATR_BLINK); \ + if ((m) & HL_DIM) \ + term_start_attr(ATR_DIM); \ + } + +#define End_Attr(m) \ + if (m) { \ + if ((m) & HL_DIM) \ + term_end_attr(ATR_DIM); \ + if ((m) & HL_BLINK) \ + term_end_attr(ATR_BLINK); \ + if ((m) & HL_ULINE) \ + term_end_attr(ATR_ULINE); \ + if ((m) & HL_INVERSE) \ + term_end_attr(ATR_INVERSE); \ + if ((m) & HL_BOLD) \ + term_end_attr(ATR_BOLD); \ + } + +void +render_status(VOID_ARGS) +{ + long mask = 0L; + int i, c, row, shrinklvl = 0, attrmask = 0; + struct WinDesc *cw = 0; + boolean do_color = FALSE; + +#ifdef TEXTCOLOR + do_color = TRUE; +#endif if (WIN_STATUS == WIN_ERR || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { @@ -3691,147 +3759,138 @@ unsigned long *colormasks; return; } - curs(WIN_STATUS, 1, 0); - for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { - int fldidx1 = fieldorder[0][i]; - if (status_activefields[fldidx1]) { - if (fldidx1 != BL_TITLE || !iflags.wc2_hitpointbar) { -#ifdef TEXTCOLOR - coloridx = tty_status[fldidx1].color; -#endif - attridx = tty_status[fldidx1].attr; - text = status_vals[fldidx1]; - if (iflags.hilite_delta) { - if (*text == ' ') { - Status_Putstr(" "); - text++; + for (row = 0; row < 2; ++row) { + curs(WIN_STATUS, 1, row); + for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { + int fldidx = fieldorder[row][i]; + + if (status_activefields[fldidx]) { + int coloridx = tty_status[NOW][fldidx].color; + int attridx = tty_status[NOW][fldidx].attr; + int x = tty_status[NOW][fldidx].x; + int y = row; + char *text = status_vals[fldidx]; + boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); + + st_fld = fldidx; /* for status_putstr() */ + tty_curs(WIN_STATUS, x, y); + if (st_fld == BL_CONDITION) { + /* + * +-----------------+ + * | Condition Codes | + * +-----------------+ + */ + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) { + tty_putstr(WIN_STATUS, 0, " "); + if (iflags.hilite_delta) { + attrmask = condattr(mask, tty_colormasks); + Begin_Attr(attrmask); + if (do_color) { + coloridx = condcolor(mask, tty_colormasks); + if (coloridx != NO_COLOR) + term_start_color(coloridx); + } + } + tty_putstr(WIN_STATUS, 0, + conditions[c].text[shrinklvl]); + if (iflags.hilite_delta) { + if (do_color && coloridx != NO_COLOR) + term_end_color(); + End_Attr(attrmask); + } + } } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_start_color(coloridx); -#endif - } - - Status_Putstr(text); - - if (iflags.hilite_delta) { -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - End_Attr(attridx); - } - } else { - /* hitpointbar using hp percent calculation */ - int bar_pos, bar_len; - char *bar2 = (char *)0; - char bar[MAXCO], savedch; - boolean twoparts = FALSE; - - text = status_vals[fldidx1]; - bar_len = strlen(text); - if (bar_len < MAXCO-1) { - Strcpy(bar, text); - bar_pos = (bar_len * hpbar_percent) / 100; - if (bar_pos < 1 && hpbar_percent > 0) - bar_pos = 1; - if (bar_pos >= bar_len && hpbar_percent < 100) - bar_pos = bar_len - 1; - if (bar_pos > 0 && bar_pos < bar_len) { - twoparts = TRUE; - bar2 = &bar[bar_pos]; - savedch = *bar2; - *bar2 = '\0'; - } - } - if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - Status_Putstr("["); -#ifdef TEXTCOLOR - coloridx = hpbar_color & 0x00FF; - /* attridx = (hpbar_color & 0xFF00) >> 8; */ - if (coloridx != NO_COLOR) - term_start_color(coloridx); -#endif - term_start_attr(ATR_INVERSE); - tty_putstr(WIN_STATUS, 0, bar); - term_end_attr(ATR_INVERSE); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - if (twoparts) { - *bar2 = savedch; - tty_putstr(WIN_STATUS, 0, bar2); - } - tty_putstr(WIN_STATUS, 0, "]"); - } else - tty_putstr(WIN_STATUS, 0, text); - } - } - } - cl_end(); - curs(WIN_STATUS, 1, 1); - for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) { - int fldidx2 = fieldorder[1][i]; - - if (status_activefields[fldidx2]) { - if (fldidx2 != BL_CONDITION) { -#ifdef TEXTCOLOR - coloridx = tty_status[fldidx2].color; -#endif - attridx = tty_status[fldidx2].attr; - text = status_vals[fldidx2]; - if (iflags.hilite_delta) { - if (*text == ' ') { - tty_putstr(WIN_STATUS, 0, " "); - text++; - } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_start_color(coloridx); -#endif - } - - if (fldidx2 == BL_GOLD) { - tty_status[st_fld].loc.x = (xchar) cw->curx; - tty_status[st_fld].loc.y = (xchar) cw->cury; - tty_status[st_fld].valid = TRUE; \ + } else if (st_fld == BL_GOLD) { + /* + * +-----------+ + * | Gold | + * +-----------+ + */ /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); - } else { - Status_Putstr(text); - } + } else if (hitpointbar) { + /* + * +-------------------------+ + * | Title with Hitpoint Bar | + * +-------------------------+ + */ + /* hitpointbar using hp percent calculation */ + int bar_pos, bar_len; + char *bar2 = (char *)0; + char bar[MAXCO], savedch; + boolean twoparts = FALSE; - if (iflags.hilite_delta) { -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - End_Attr(attridx); + bar_len = strlen(text); + if (bar_len < MAXCO-1) { + Strcpy(bar, text); + bar_pos = (bar_len * hpbar_percent) / 100; + if (bar_pos < 1 && hpbar_percent > 0) + bar_pos = 1; + if (bar_pos >= bar_len && hpbar_percent < 100) + bar_pos = bar_len - 1; + if (bar_pos > 0 && bar_pos < bar_len) { + twoparts = TRUE; + bar2 = &bar[bar_pos]; + savedch = *bar2; + *bar2 = '\0'; + } + } + if (iflags.hilite_delta && iflags.wc2_hitpointbar) { + tty_putstr(WIN_STATUS, 0, "["); + if (do_color && hpbar_color != NO_COLOR) + term_start_color(hpbar_color); + term_start_attr(ATR_INVERSE); + tty_putstr(WIN_STATUS, 0, bar); + term_end_attr(ATR_INVERSE); + if (do_color && hpbar_color != NO_COLOR) + term_end_color(); + if (twoparts) { + *bar2 = savedch; + tty_putstr(WIN_STATUS, 0, bar2); + } + tty_putstr(WIN_STATUS, 0, "]"); + } else { + tty_putstr(WIN_STATUS, 0, text); + } + } else { + /* + * +-----------------------------+ + * | Everything else that is not | + * | in a special case above | + * +-----------------------------+ + */ + if (iflags.hilite_delta) { + if (*text == ' ') { + tty_putstr(WIN_STATUS, 0, " "); + text++; + } + /* multiple attributes can be in effect concurrently */ + Begin_Attr(attridx); + if (do_color && coloridx != NO_COLOR + && coloridx != CLR_MAX) + term_start_color(coloridx); + } + tty_putstr(WIN_STATUS, 0, text); + if (iflags.hilite_delta) { + if (do_color && coloridx != NO_COLOR) + term_end_color(); + End_Attr(attridx); + } } - } else { - MaybeDisplayCond(BL_MASK_STONE, "Stone"); - MaybeDisplayCond(BL_MASK_SLIME, "Slime"); - MaybeDisplayCond(BL_MASK_STRNGL, "Strngl"); - MaybeDisplayCond(BL_MASK_FOODPOIS, "FoodPois"); - MaybeDisplayCond(BL_MASK_TERMILL, "TermIll"); - MaybeDisplayCond(BL_MASK_BLIND, "Blind"); - MaybeDisplayCond(BL_MASK_DEAF, "Deaf"); - MaybeDisplayCond(BL_MASK_STUN, "Stun"); - MaybeDisplayCond(BL_MASK_CONF, "Conf"); - MaybeDisplayCond(BL_MASK_HALLU, "Hallu"); - MaybeDisplayCond(BL_MASK_LEV, "Lev"); - MaybeDisplayCond(BL_MASK_FLY, "Fly"); - MaybeDisplayCond(BL_MASK_RIDE, "Ride"); + /* reset .redraw */ + tty_status[NOW][st_fld].redraw = FALSE; + /* + * Make a copy of the entire tty_status struct for comparison + * of current and previous. + */ + tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ } - } - prev_tty_status[st_fld] = tty_status[st_fld]; /* copy struct */ + } + tty_curs(WIN_STATUS, cw->curx+1, cw->cury); + cl_end(); } - cl_end(); return; } From 778c8a56ab8c6dd15bfbdf747b5092f8b8ca3d7e Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 13:25:46 -0400 Subject: [PATCH 14/42] remove a commented out code line --- win/tty/wintty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ac3fe384f..d58b211e3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3531,7 +3531,6 @@ const char *str; } #ifdef STATUS_HILITES else { - /* tty_curs(window, x, y); */ ttyDisplay->curx++; cw->curx++; } From 4dd535cbd2bf9d05ab5a9245b85e6a954c6bf8f2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 18:47:19 -0400 Subject: [PATCH 15/42] cross platform testing --- win/tty/wintty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d58b211e3..96ec3b5f9 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3531,6 +3531,7 @@ const char *str; } #ifdef STATUS_HILITES else { + tty_curs(WIN_STATUS, i, cw->cury); ttyDisplay->curx++; cw->curx++; } From 702154529fb69af17972d0292d305acaf3a54eca Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 10:05:29 -0400 Subject: [PATCH 16/42] provide some debug developer controls - part 1 --- include/extern.h | 2 +- include/flag.h | 11 ++++++ src/allmain.c | 89 +++++++++++++++++++++++++++++++++++++++++---- sys/share/pcmain.c | 7 +++- sys/unix/unixmain.c | 7 +++- sys/winnt/nttty.c | 8 ++-- 6 files changed, 108 insertions(+), 16 deletions(-) diff --git a/include/extern.h b/include/extern.h index b6f482515..4535f8769 100644 --- a/include/extern.h +++ b/include/extern.h @@ -26,7 +26,7 @@ E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); E time_t NDECL(get_realtime); -E boolean FDECL(argcheck, (int, char **, enum earlyarg)); +E int FDECL(argcheck, (int, char **, enum earlyarg)); /* ### apply.c ### */ diff --git a/include/flag.h b/include/flag.h index 5dd13b2ec..277b42cfe 100644 --- a/include/flag.h +++ b/include/flag.h @@ -221,6 +221,16 @@ enum getloc_filters { NUM_GFILTER }; +struct debug_flags { + boolean test; +#ifdef TTY_GRAPHICS + boolean ttystatus; +#endif +#ifdef WIN32 + boolean immediateflips; +#endif +}; + struct instance_flags { /* stuff that really isn't option or platform related. They are * set and cleared during the game to control the internal @@ -423,6 +433,7 @@ struct instance_flags { short mines_prize_type; /* luckstone */ short soko_prize_type1; /* bag of holding or */ short soko_prize_type2; /* amulet of reflection */ + struct debug_flags debug; }; /* diff --git a/src/allmain.c b/src/allmain.c index 6942aa232..569c6e456 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -6,6 +6,7 @@ /* various code that was replicated in *main.c */ #include "hack.h" +#include #ifndef NO_SIGNAL #include @@ -16,6 +17,7 @@ STATIC_DCL void NDECL(do_positionbar); #endif STATIC_DCL void FDECL(regen_hp, (int)); STATIC_DCL void FDECL(interrupt_multi, (const char *)); +STATIC_DCL void FDECL(debug_fields, (const char *)); void moveloop(resuming) @@ -752,11 +754,18 @@ const char *msg; */ static struct early_opt earlyopts[] = { - {ARG_DEBUG, "debug", 5, FALSE}, + {ARG_DEBUG, "debug", 5, TRUE}, {ARG_VERSION, "version", 4, TRUE}, }; -boolean +/* + * Returns: + * 0 = no match + * 1 = found and skip past this argument + * 2 = found and trigger immediate exit + */ + +int argcheck(argc, argv, e_arg) int argc; char *argv[]; @@ -774,7 +783,7 @@ enum earlyarg e_arg; if ((idx >= SIZE(earlyopts)) || (argc <= 1)) return FALSE; - for (i = 1; i < argc; ++i) { + for (i = 0; i < argc; ++i) { if (argv[i][0] != '-') continue; if (argv[i][1] == '-') { @@ -789,15 +798,20 @@ enum earlyarg e_arg; } if (match) { + const char *extended_opt = index(userea,':'); + + if (!extended_opt) + extended_opt = index(userea, '='); switch(e_arg) { case ARG_DEBUG: + if (extended_opt) { + extended_opt++; + debug_fields(extended_opt); + } + return 1; break; case ARG_VERSION: { boolean insert_into_pastebuf = FALSE; - const char *extended_opt = index(userea,':'); - - if (!extended_opt) - extended_opt = index(userea, '='); if (extended_opt) { extended_opt++; @@ -812,7 +826,7 @@ enum earlyarg e_arg; } } early_version_info(insert_into_pastebuf); - return TRUE; + return 2; break; } default: @@ -822,4 +836,63 @@ enum earlyarg e_arg; return FALSE; } +/* + * These are internal controls to aid developers with + * testing and debugging particular aspects of the code. + * They are not player options and the only place they + * are documented is right here. No gameplay is altered. + * + * test - test whether this parser is working + * ttystatus - TTY: + * immediateflips - WIN32: turn off display performance + * optimization so that display output + * can be debugged without buffering. + */ +void +debug_fields(opts) +const char *opts; +{ + char *op; + boolean negated = FALSE; + boolean retval = TRUE; + + while ((op = index(opts, ',')) != 0) { + *op++ = 0; + /* recurse */ + debug_fields(op); + } + if (strlen(opts) > BUFSZ / 2) + return; + + + /* strip leading and trailing white space */ + while (isspace((uchar) *opts)) + opts++; + op = eos((char *) opts); + while (--op >= opts && isspace((uchar) *op)) + *op = '\0'; + + if (!*opts) { + /* empty */ + return; + } + while ((*opts == '!') || !strncmpi(opts, "no", 2)) { + if (*opts == '!') + opts++; + else + opts += 2; + negated = !negated; + } + if (match_optname(opts, "test", 4, FALSE)) + iflags.debug.test = negated ? FALSE : TRUE; +#ifdef TTY_GRAPHICS + if (match_optname(opts, "ttystatus", 9, FALSE)) + iflags.debug.ttystatus = negated ? FALSE : TRUE; +#endif +#ifdef WIN32 + if (match_optname(opts, "immediateflips", 14, FALSE)) + iflags.debug.immediateflips = negated ? FALSE : TRUE; +#endif + return; +} /*allmain.c*/ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index eea29f8de..6bb6cfc29 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -331,9 +331,14 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, HACKDIR); #endif if (argc > 1) { - if (argcheck(argc, argv, ARG_VERSION)) + if (argcheck(argc, argv, ARG_VERSION) == 2) nethack_exit(EXIT_SUCCESS); + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index c856e758b..3c91b3e55 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -111,9 +111,14 @@ char *argv[]; dir = nh_getenv("HACKDIR"); if (argc > 1) { - if (argcheck(argc, argv, ARG_VERSION)) + if (argcheck(argc, argv, ARG_VERSION) == 2) exit(EXIT_SUCCESS); + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 9d1114498..4fbc11c63 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -252,8 +252,6 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; -boolean do_immediate_flips = FALSE; - static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); @@ -370,7 +368,7 @@ static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, while (dst != sentinel) *dst++ = clear_cell; - if (do_immediate_flips && buffer == &back_buffer) + if (iflags.debug.immediateflips && buffer == &back_buffer) back_buffer_flip(); } @@ -379,7 +377,7 @@ static void back_buffer_write(cell_t * cell, int x, int y) cell_t * dst = buffer_get_cell(&back_buffer, x, y); *dst = *cell; - if (do_immediate_flips) + if (iflags.debug.immediateflips) back_buffer_flip(); } @@ -393,7 +391,7 @@ static void back_buffer_clear_to_end_of_line(int x, int y) while (cell != sentinel) *cell++ = clear_cell; - if (do_immediate_flips) + if (iflags.debug.immediateflips) back_buffer_flip(); } From 8c2dc7bb1cf4fef8e7001c5cc2371a053c242b20 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 18:48:02 -0400 Subject: [PATCH 17/42] add some logging to debug --- win/tty/wintty.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 96ec3b5f9..55f66ded3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -179,6 +179,9 @@ STATIC_DCL boolean NDECL(reset_role_filtering); STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); +STATIC_DCL void FDECL(dump_tty_status, (const char *, int)); +STATIC_DCL void FDECL(dump_display_status, (const char *, int, + struct WinDesc *, const char *)); /* * A string containing all the default commands -- to add to a list @@ -3403,6 +3406,31 @@ extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; +const char *fieldnames[] = { + "title", + "strength", + "dexterity", + "constitution", + "intelligence", + "wisdom", + "charisma", + "alignment", + "score", + "carrying-capacity", + "gold", + "power", + "power-max", + "experience-level", + "armor-class", + "HD", + "time", + "hunger", + "hitpoints", + "hitpoints-max", + "dungeon-level", + "experience", + "condition", +}; #ifdef STATUS_HILITES static int FDECL(condcolor, (long, unsigned long *)); @@ -3509,6 +3537,9 @@ const char *str; str = nb - 2; } nb = str; + if (iflags.debug.ttystatus) + dump_display_status("status_putstr (before)", st_fld, cw, str); + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES @@ -3539,6 +3570,8 @@ const char *str; if (*ob) ob++; } + if (iflags.debug.ttystatus) + dump_display_status("status_putsr (after)", st_fld, cw, str); (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ @@ -3654,7 +3687,11 @@ unsigned long *colormasks; tty_status[NOW][fldidx].lth += 2; /* [ and ] */ if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - + + /* debugging log */ + if (iflags.debug.ttystatus) + dump_tty_status("tty_status_update", fldidx); + if (check_fields(force_update)) render_status(); return; @@ -3703,10 +3740,22 @@ boolean forcefields; * Then, status_putstr() will see that flag setting * and ensure that the tty cell content is updated. */ + if (valid && iflags.debug.ttystatus) { + char buf[BUFSZ]; + + Sprintf(buf, "check_fields: forcefields=%s, name=%s\n" + "\t\t\"%s\"", + forcefields ? "TRUE" : "FALSE", + fieldnames[idx], + status_vals[idx]); + testinglog("ttystatus", buf, ""); + } + if (forcefields || update_right || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; + if (iflags.debug.ttystatus) dump_tty_status("", idx); col += tty_status[NOW][idx].lth; } } @@ -3774,6 +3823,8 @@ render_status(VOID_ARGS) st_fld = fldidx; /* for status_putstr() */ tty_curs(WIN_STATUS, x, y); + if (iflags.debug.ttystatus) + dump_tty_status("render_status (before)", st_fld); if (st_fld == BL_CONDITION) { /* * +-----------------+ @@ -3881,6 +3932,8 @@ render_status(VOID_ARGS) } /* reset .redraw */ tty_status[NOW][st_fld].redraw = FALSE; + if (iflags.debug.ttystatus) + dump_tty_status("render_status (after)", st_fld); /* * Make a copy of the entire tty_status struct for comparison * of current and previous. @@ -3946,6 +3999,66 @@ unsigned long *bmarray; } return attr; } + +void +dump_display_status(descr, idx, cw, str) +const char *descr; +int idx; +struct WinDesc *cw; +const char *str; +{ + boolean buf[BUFSZ]; + const char *d2 = descr ? descr : "dump_Display_status"; + + Sprintf(buf, + "\t\t\"%s\"\n" + "\t\t%s = %d [%s], %s = %d, %s = %s\n" + "\t\t" + "%-17s = (%d,%d)\n" + "\t\t" + "%-17s = (%d,%d)\n" + "\t\t" + "%-17s = (%d,%d)\n", + str, + "idx", idx, fieldnames[idx], + "lth", tty_status[NOW][idx].lth, + "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE", + "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, + "ttyDisplay->x,->y", ttyDisplay->curx, ttyDisplay->cury, + "cw->curx,->cury", cw->curx, cw->cury); + testinglog("ttystatus", d2, buf); + return; +} + +void +dump_tty_status(descr, idx) +const char *descr; +int idx; +{ + boolean buf[BUFSZ]; + const char *d2 = descr ? descr : "dump_status"; + + Sprintf(buf, + "\t\t%-6s = %s\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %X\n" + "\t\t%-6s = %d,%d\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %s\n" + "\t\t%-6s = %s\n", + "name", fieldnames[idx], + "idx", idx, + "color", tty_status[NOW][idx].color, + "attr", tty_status[NOW][idx].attr, + "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, + "lth", tty_status[NOW][idx].lth, + "valid", tty_status[NOW][idx].valid ? "TRUE" : "FALSE", + "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE"); + testinglog("ttystatus", d2, buf); + return; +} + #endif /* STATUS_HILITES */ #endif /* TTY_GRAPHICS */ From 04c85aa59d23357cc9188def53fd8c5e0118c816 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 18:54:58 -0400 Subject: [PATCH 18/42] update files.c with testinglog --- src/files.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/files.c b/src/files.c index 8a490d09e..cd5277acb 100644 --- a/src/files.c +++ b/src/files.c @@ -3542,7 +3542,7 @@ const char *dir UNUSED_if_not_OS2_CODEVIEW; /* ---------- END SCOREBOARD CREATION ----------- */ -/* ---------- BEGIN PANIC/IMPOSSIBLE LOG ----------- */ +/* ---------- BEGIN PANIC/IMPOSSIBLE/TESTING LOG ----------- */ /*ARGSUSED*/ void @@ -3579,7 +3579,31 @@ const char *reason; /* explanation */ return; } -/* ---------- END PANIC/IMPOSSIBLE LOG ----------- */ +/*ARGSUSED*/ +void +testinglog(filenm, type, reason) +const char *filenm; /* ad hoc file name */ +const char *type; +const char *reason; /* explanation */ +{ + FILE *lfile; + char fnbuf[BUFSZ]; + + if (!filenm) return; + Strcpy(fnbuf, filenm); + if (index(fnbuf, '.') == 0) + Strcat(fnbuf, ".log"); + lfile = fopen_datafile(fnbuf, "a", TROUBLEPREFIX); + if (lfile) { + time_t now = getnow(); + int uid = getuid(); + (void) fprintf(lfile, "%s\n%s\n", type, reason); + (void) fclose(lfile); + } + return; +} + +/* ---------- END PANIC/IMPOSSIBLE/TESTING LOG ----------- */ #ifdef SELF_RECOVER From dd04f5fcb551294e59853c58fbf0eb7d71d4936e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:04:57 -0400 Subject: [PATCH 19/42] more tty-status updates --- include/extern.h | 2 + src/mapglyph.c | 135 ++++++++++++------------ win/tty/wintty.c | 262 +++++++++++++---------------------------------- 3 files changed, 147 insertions(+), 252 deletions(-) diff --git a/include/extern.h b/include/extern.h index 4535f8769..8ef6e617f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -786,6 +786,7 @@ E void NDECL(read_wizkit); E int FDECL(read_sym_file, (int)); E int FDECL(parse_sym_line, (char *, int)); E void FDECL(paniclog, (const char *, const char *)); +E void FDECL(testinglog, (const char *, const char *, const char *)); E int FDECL(validate_prefix_locations, (char *)); #ifdef SELECTSAVED E char *FDECL(plname_from_file, (const char *)); @@ -1157,6 +1158,7 @@ E boolean FDECL(usmellmon, (struct permonst *)); E int FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); E char *FDECL(encglyph, (int)); +E char *FDECL(decode_mixed, (char *,const char *)); E void FDECL(genl_putmixed, (winid, int, const char *)); /* ### mcastu.c ### */ diff --git a/src/mapglyph.c b/src/mapglyph.c index 4ba4ee7e6..ca7e5ca33 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -247,6 +247,77 @@ int glyph; return encbuf; } +char * +decode_mixed(buf, str) +char *buf; +const char *str; +{ + static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; + char *put = buf; + + if (!put || !str) + return ""; + + while (*str) { + if (*str == '\\') { + int rndchk, dcount, so, gv, ch = 0, oc = 0; + unsigned os = 0; + const char *dp, *save_str; + + save_str = str++; + switch (*str) { + case 'G': /* glyph value \GXXXXNNNN*/ + rndchk = dcount = 0; + for (++str; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); + else + break; + if (rndchk == context.rndencode) { + gv = dcount = 0; + for (; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + gv = (gv * 16) + ((int) (dp - hex) / 2); + else + break; + so = mapglyph(gv, &ch, &oc, &os, 0, 0); + *put++ = showsyms[so]; + /* 'str' is ready for the next loop iteration and '*str' + should not be copied at the end of this iteration */ + continue; + } else { + /* possible forgery - leave it the way it is */ + str = save_str; + } + break; +#if 0 + case 'S': /* symbol offset */ + so = rndchk = dcount = 0; + for (++str; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); + else + break; + if (rndchk == context.rndencode) { + dcount = 0; + for (; *str && ++dcount <= 2; ++str) + if ((dp = index(hex, *str)) != 0) + so = (so * 16) + ((int) (dp - hex) / 2); + else + break; + } + *put++ = showsyms[so]; + break; +#endif + case '\\': + break; + } + } + *put++ = *str++; + } + *put = '\0'; +} + /* * This differs from putstr() because the str parameter can * contain a sequence of characters representing: @@ -265,71 +336,9 @@ winid window; int attr; const char *str; { - static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; char buf[BUFSZ]; - const char *cp = str; - char *put = buf; - - while (*cp) { - if (*cp == '\\') { - int rndchk, dcount, so, gv, ch = 0, oc = 0; - unsigned os = 0; - const char *dp, *save_cp; - - save_cp = cp++; - switch (*cp) { - case 'G': /* glyph value \GXXXXNNNN*/ - rndchk = dcount = 0; - for (++cp; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); - else - break; - if (rndchk == context.rndencode) { - gv = dcount = 0; - for (; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - gv = (gv * 16) + ((int) (dp - hex) / 2); - else - break; - so = mapglyph(gv, &ch, &oc, &os, 0, 0); - *put++ = showsyms[so]; - /* 'cp' is ready for the next loop iteration and '*cp' - should not be copied at the end of this iteration */ - continue; - } else { - /* possible forgery - leave it the way it is */ - cp = save_cp; - } - break; -#if 0 - case 'S': /* symbol offset */ - so = rndchk = dcount = 0; - for (++cp; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); - else - break; - if (rndchk == context.rndencode) { - dcount = 0; - for (; *cp && ++dcount <= 2; ++cp) - if ((dp = index(hex, *cp)) != 0) - so = (so * 16) + ((int) (dp - hex) / 2); - else - break; - } - *put++ = showsyms[so]; - break; -#endif - case '\\': - break; - } - } - *put++ = *cp++; - } - *put = '\0'; /* now send it to the normal putstr */ - putstr(window, attr, buf); + putstr(window, attr, decode_mixed(buf, str)); } /*mapglyph.c*/ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 55f66ded3..50d9c98ef 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,12 +176,9 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); -STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(dump_tty_status, (const char *, int)); -STATIC_DCL void FDECL(dump_display_status, (const char *, int, - struct WinDesc *, const char *)); +STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); /* * A string containing all the default commands -- to add to a list @@ -2529,9 +2526,6 @@ const char *str; update_topl(str); break; - case NHW_STATUS: - status_putstr(window, cw, str); - break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); @@ -3406,30 +3400,13 @@ extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; + const char *fieldnames[] = { - "title", - "strength", - "dexterity", - "constitution", - "intelligence", - "wisdom", - "charisma", - "alignment", - "score", - "carrying-capacity", - "gold", - "power", - "power-max", - "experience-level", - "armor-class", - "HD", - "time", - "hunger", - "hitpoints", - "hitpoints-max", - "dungeon-level", - "experience", - "condition", + "title", "strength", "dexterity", "constitution", "intelligence", + "wisdom", "charisma", "alignment", "score", "carrying-capacity", + "gold", "power", "power-max", "experience-level", "armor-class", + "HD", "time", "hunger", "hitpoints", "hitpoints-max", + "dungeon-level", "experience", "condition", }; #ifdef STATUS_HILITES @@ -3438,6 +3415,7 @@ static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; static unsigned long *tty_colormasks; static struct tty_status_fields { + int idx; int color; int attr; int x, y; @@ -3488,6 +3466,7 @@ tty_status_init() int i; for (i = 0; i < MAXBLSTATS; ++i) { + tty_status[NOW][i].idx = -1; tty_status[NOW][i].color = NO_COLOR; /* no color */ tty_status[NOW][i].attr = ATR_NONE; tty_status[NOW][i].x = 0; @@ -3504,84 +3483,6 @@ tty_status_init() genl_status_init(); } -/* - * status_putstr() is not intended to be called directly - * by anything other than tty_putstr(). tty_putstr() - * does the prereq validations, and initializations of - * window and cw. - * - * Moving the status handling code here from tty_putstr() - * allows access to status data structures defined just - * above, rather than up top, with the additional bonus - * of having most status-related code bits fairly close - * together. - * - */ -static void -status_putstr(window, cw, str) -winid window; -struct WinDesc *cw; -const char *str; -{ - char *ob; - long i, j, n0; - const char *nb; - - ob = &cw->data[cw->cury][j = cw->curx]; - if (context.botlx) - *ob = 0; - if (!cw->cury && (int) strlen(str) >= CO) { - /* the characters before "St:" are unnecessary */ - nb = index(str, ':'); - if (nb && nb > str + 2) - str = nb - 2; - } - nb = str; - if (iflags.debug.ttystatus) - dump_display_status("status_putstr (before)", st_fld, cw, str); - - for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { - if (!*nb) { -#ifndef STATUS_HILITES - if (*ob || context.botlx) { -#else - if (context.botlx) { -#endif - /* last char printed may be in middle of line */ - tty_curs(WIN_STATUS, i, cw->cury); - cl_end(); - } - break; - } -#ifndef STATUS_HILITES - if (*ob != *nb) { -#else - if (*ob != *nb || tty_status[NOW][st_fld].redraw) { -#endif - tty_putsym(WIN_STATUS, i, cw->cury, *nb); - } -#ifdef STATUS_HILITES - else { - tty_curs(WIN_STATUS, i, cw->cury); - ttyDisplay->curx++; - cw->curx++; - } -#endif - if (*ob) - ob++; - } - if (iflags.debug.ttystatus) - dump_display_status("status_putsr (after)", st_fld, cw, str); - - (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); - cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ -#ifndef STATUS_HILITES - cw->cury = (cw->cury + 1) % 2; - cw->curx = 0; -#endif - return; -} - #ifdef STATUS_HILITES /* @@ -3662,6 +3563,7 @@ unsigned long *colormasks; case BL_CONDITION: tty_condition_bits = *condptr; tty_colormasks = colormasks; + tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; break; default: @@ -3672,6 +3574,7 @@ unsigned long *colormasks; : NO_COLOR; tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); + tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; break; } @@ -3797,6 +3700,7 @@ render_status(VOID_ARGS) int i, c, row, shrinklvl = 0, attrmask = 0; struct WinDesc *cw = 0; boolean do_color = FALSE; + struct tty_status_fields *nullfield = (struct tty_status_fields *)0; #ifdef TEXTCOLOR do_color = TRUE; @@ -3821,10 +3725,7 @@ render_status(VOID_ARGS) char *text = status_vals[fldidx]; boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); - st_fld = fldidx; /* for status_putstr() */ - tty_curs(WIN_STATUS, x, y); - if (iflags.debug.ttystatus) - dump_tty_status("render_status (before)", st_fld); + st_fld = fldidx; if (st_fld == BL_CONDITION) { /* * +-----------------+ @@ -3832,9 +3733,9 @@ render_status(VOID_ARGS) * +-----------------+ */ for (c = 0; c < SIZE(conditions); ++c) { - mask = conditions[c].mask; + mask = conditions[c].mask; if ((tty_condition_bits & mask) == mask) { - tty_putstr(WIN_STATUS, 0, " "); + tty_putstatusfield(nullfield, " ", x++, y); if (iflags.hilite_delta) { attrmask = condattr(mask, tty_colormasks); Begin_Attr(attrmask); @@ -3844,8 +3745,9 @@ render_status(VOID_ARGS) term_start_color(coloridx); } } - tty_putstr(WIN_STATUS, 0, - conditions[c].text[shrinklvl]); + tty_putstatusfield(nullfield, + conditions[c].text[shrinklvl], x, y); + x += (int) strlen(conditions[c].text[shrinklvl]); if (iflags.hilite_delta) { if (do_color && coloridx != NO_COLOR) term_end_color(); @@ -3853,14 +3755,18 @@ render_status(VOID_ARGS) } } } + tty_curs(WIN_STATUS, x, y); + cl_end(); } else if (st_fld == BL_GOLD) { + char buf[BUFSZ]; /* * +-----------+ * | Gold | * +-----------+ */ - /* putmixed() due to GOLD glyph */ - putmixed(WIN_STATUS, 0, text); + /* decode_mixed() due to GOLD glyph */ + tty_putstatusfield(nullfield, + decode_mixed(buf, text), x, y); } else if (hitpointbar) { /* * +-------------------------+ @@ -3888,22 +3794,26 @@ render_status(VOID_ARGS) *bar2 = '\0'; } } - if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - tty_putstr(WIN_STATUS, 0, "["); + if (iflags.hilite_delta) { + tty_putstatusfield(nullfield, "[", x++, y); if (do_color && hpbar_color != NO_COLOR) term_start_color(hpbar_color); term_start_attr(ATR_INVERSE); - tty_putstr(WIN_STATUS, 0, bar); + tty_putstatusfield(nullfield, bar, x, y); + x += (int) strlen(bar); term_end_attr(ATR_INVERSE); if (do_color && hpbar_color != NO_COLOR) term_end_color(); if (twoparts) { *bar2 = savedch; - tty_putstr(WIN_STATUS, 0, bar2); + tty_putstatusfield(nullfield, bar2, x, y); + x += (int) strlen(bar2); + tty_curs(WIN_STATUS, x, y); } - tty_putstr(WIN_STATUS, 0, "]"); + tty_putstatusfield(nullfield, "]", x++, y); } else { - tty_putstr(WIN_STATUS, 0, text); + tty_putstatusfield(&tty_status[NOW][fldidx], + (char *)0, x, y); } } else { /* @@ -3914,7 +3824,7 @@ render_status(VOID_ARGS) */ if (iflags.hilite_delta) { if (*text == ' ') { - tty_putstr(WIN_STATUS, 0, " "); + tty_putstatusfield(nullfield, " ", x++, y); text++; } /* multiple attributes can be in effect concurrently */ @@ -3923,7 +3833,8 @@ render_status(VOID_ARGS) && coloridx != CLR_MAX) term_start_color(coloridx); } - tty_putstr(WIN_STATUS, 0, text); + tty_putstatusfield(&tty_status[NOW][fldidx], + text, x, y); if (iflags.hilite_delta) { if (do_color && coloridx != NO_COLOR) term_end_color(); @@ -3932,8 +3843,6 @@ render_status(VOID_ARGS) } /* reset .redraw */ tty_status[NOW][st_fld].redraw = FALSE; - if (iflags.debug.ttystatus) - dump_tty_status("render_status (after)", st_fld); /* * Make a copy of the entire tty_status struct for comparison * of current and previous. @@ -3941,12 +3850,45 @@ render_status(VOID_ARGS) tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ } } - tty_curs(WIN_STATUS, cw->curx+1, cw->cury); - cl_end(); } return; } +void +tty_putstatusfield(fld, val, x, y) +struct tty_status_fields *fld; +const char *val; +int x,y; +{ + int i, ncols, lth; + struct WinDesc *cw = 0; + const char *text = (char *)0; + + if ((cw = wins[NHW_STATUS]) == (struct WinDesc *) 0) + panic("Invalid WinDesc\n"); + + ncols = cw->cols; + if (val) { + text = val; + lth = strlen(text); + } else if (fld) { + text = status_vals[fld->idx]; + lth = fld->lth; + } + if (!text) return; + + print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); + + tty_curs(NHW_STATUS, x, y); + for (i = 0; i < lth; ++i) { + if ((i + x ) < ncols) { + (void) putchar(*text++); + ttyDisplay->curx++; + cw->curx++; + } + } +} + #ifdef TEXTCOLOR /* * Return what color this condition should @@ -4000,67 +3942,9 @@ unsigned long *bmarray; return attr; } -void -dump_display_status(descr, idx, cw, str) -const char *descr; -int idx; -struct WinDesc *cw; -const char *str; -{ - boolean buf[BUFSZ]; - const char *d2 = descr ? descr : "dump_Display_status"; - - Sprintf(buf, - "\t\t\"%s\"\n" - "\t\t%s = %d [%s], %s = %d, %s = %s\n" - "\t\t" - "%-17s = (%d,%d)\n" - "\t\t" - "%-17s = (%d,%d)\n" - "\t\t" - "%-17s = (%d,%d)\n", - str, - "idx", idx, fieldnames[idx], - "lth", tty_status[NOW][idx].lth, - "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE", - "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, - "ttyDisplay->x,->y", ttyDisplay->curx, ttyDisplay->cury, - "cw->curx,->cury", cw->curx, cw->cury); - testinglog("ttystatus", d2, buf); - return; -} - -void -dump_tty_status(descr, idx) -const char *descr; -int idx; -{ - boolean buf[BUFSZ]; - const char *d2 = descr ? descr : "dump_status"; - - Sprintf(buf, - "\t\t%-6s = %s\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %X\n" - "\t\t%-6s = %d,%d\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %s\n" - "\t\t%-6s = %s\n", - "name", fieldnames[idx], - "idx", idx, - "color", tty_status[NOW][idx].color, - "attr", tty_status[NOW][idx].attr, - "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, - "lth", tty_status[NOW][idx].lth, - "valid", tty_status[NOW][idx].valid ? "TRUE" : "FALSE", - "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE"); - testinglog("ttystatus", d2, buf); - return; -} - #endif /* STATUS_HILITES */ #endif /* TTY_GRAPHICS */ /*wintty.c*/ + From d0e508241b23938d25963553cdec6b25d075e077 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:07:54 -0400 Subject: [PATCH 20/42] missing return value --- src/mapglyph.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mapglyph.c b/src/mapglyph.c index ca7e5ca33..587d317c8 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -316,6 +316,7 @@ const char *str; *put++ = *str++; } *put = '\0'; + return buf; } /* From a3ba46d73278625522155148238ab6971f287c12 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:10:43 -0400 Subject: [PATCH 21/42] remove some debug code --- win/tty/wintty.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 50d9c98ef..ad29a4650 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3591,10 +3591,6 @@ unsigned long *colormasks; if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - /* debugging log */ - if (iflags.debug.ttystatus) - dump_tty_status("tty_status_update", fldidx); - if (check_fields(force_update)) render_status(); return; @@ -3630,35 +3626,16 @@ boolean forcefields; if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) update_right = TRUE; /* - * status_putstr(), called from tty_putstr() checks - * whether individual tty cell text content matches what - * was already there and optimizes by leaving it be. - * Checking the text iself was sufficient back when the - * status lines were monochrome and of a single - * attribute style. - * * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so * we flag that here by setting .redraw. * Then, status_putstr() will see that flag setting * and ensure that the tty cell content is updated. */ - if (valid && iflags.debug.ttystatus) { - char buf[BUFSZ]; - - Sprintf(buf, "check_fields: forcefields=%s, name=%s\n" - "\t\t\"%s\"", - forcefields ? "TRUE" : "FALSE", - fieldnames[idx], - status_vals[idx]); - testinglog("ttystatus", buf, ""); - } - if (forcefields || update_right || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; - if (iflags.debug.ttystatus) dump_tty_status("", idx); col += tty_status[NOW][idx].lth; } } From ba057ef3de1815eb3f01d076f3601d64931fbb0c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 02:18:42 -0400 Subject: [PATCH 22/42] condition shrinkage when required --- win/tty/wintty.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ad29a4650..ffc8ccadb 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -179,6 +179,7 @@ STATIC_DCL boolean NDECL(reset_role_filtering); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); +STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); /* * A string containing all the default commands -- to add to a list @@ -3676,7 +3677,7 @@ render_status(VOID_ARGS) long mask = 0L; int i, c, row, shrinklvl = 0, attrmask = 0; struct WinDesc *cw = 0; - boolean do_color = FALSE; + boolean do_color = FALSE, fit = FALSE; struct tty_status_fields *nullfield = (struct tty_status_fields *)0; #ifdef TEXTCOLOR @@ -3709,6 +3710,7 @@ render_status(VOID_ARGS) * | Condition Codes | * +-----------------+ */ + shrinklvl = set_cond_shrinklvl(x, cw->cols); for (c = 0; c < SIZE(conditions); ++c) { mask = conditions[c].mask; if ((tty_condition_bits & mask) == mask) { @@ -3866,6 +3868,33 @@ int x,y; } } +int +set_cond_shrinklvl(col, ncols) +int col, ncols; +{ + long mask = 0L; + int j, c, x, avail, shrinklvl = 0; + boolean fitting = FALSE; + + avail = ncols - col; + /* determine appropriate shrinklvl required */ + for (j = 0; j < 3 && !fitting; ++j) { + x = 0; + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) { + x++; /* for spacer */ + x += (int) strlen(conditions[c].text[shrinklvl]); + } + } + if (x < avail) + fitting = TRUE; + else if (shrinklvl < 2) + shrinklvl++; + } + return shrinklvl; +} + #ifdef TEXTCOLOR /* * Return what color this condition should From 9a87064ccae39289dd26f0b64b2020c76471d50e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 06:57:34 -0400 Subject: [PATCH 23/42] some build fixes for compile issues reported --- include/extern.h | 2 +- include/wintty.h | 12 +++++++++ src/allmain.c | 1 - src/mapglyph.c | 2 +- win/tty/wintty.c | 63 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8ef6e617f..96a5ade8b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1158,7 +1158,7 @@ E boolean FDECL(usmellmon, (struct permonst *)); E int FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); E char *FDECL(encglyph, (int)); -E char *FDECL(decode_mixed, (char *,const char *)); +E const char *FDECL(decode_mixed, (char *,const char *)); E void FDECL(genl_putmixed, (winid, int, const char *)); /* ### mcastu.c ### */ diff --git a/include/wintty.h b/include/wintty.h index 1f270128f..4ff0ddb3c 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -69,6 +69,18 @@ struct DisplayDesc { #endif /* WINDOW_STRUCTS */ +#ifdef STATUS_HILITES +struct tty_status_fields { + int idx; + int color; + int attr; + int x, y; + size_t lth; + boolean valid; + boolean redraw; +}; +#endif + #define MAXWIN 20 /* maximum number of windows, cop-out */ /* tty dependent window types */ diff --git a/src/allmain.c b/src/allmain.c index 569c6e456..2c1364d75 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -854,7 +854,6 @@ const char *opts; { char *op; boolean negated = FALSE; - boolean retval = TRUE; while ((op = index(opts, ',')) != 0) { *op++ = 0; diff --git a/src/mapglyph.c b/src/mapglyph.c index 587d317c8..04ef068e9 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -247,7 +247,7 @@ int glyph; return encbuf; } -char * +const char * decode_mixed(buf, str) char *buf; const char *str; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ffc8ccadb..821859efa 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,10 +176,13 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); +#ifdef STATUS_HILITES STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); +STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, + const char *, int, int)); STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); +#endif /* * A string containing all the default commands -- to add to a list @@ -2494,7 +2497,6 @@ const char *str; register struct WinDesc *cw = 0; register char *ob; register long i, n0; - boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- * probably a panic message @@ -2507,11 +2509,7 @@ const char *str; if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; -#ifndef STATUS_HILITES if (cw->type != NHW_MESSAGE) -#else - if (cw->type != NHW_MESSAGE && cw->type != NHW_STATUS) -#endif str = compress_str(str); ttyDisplay->lastwin = window; @@ -2526,7 +2524,39 @@ const char *str; #endif update_topl(str); break; +#ifndef STATUS_HILITES + case NHW_STATUS: + ob = &cw->data[cw->cury][j = cw->curx]; + if (context.botlx) + *ob = 0; + if (!cw->cury && (int) strlen(str) >= CO) { + /* the characters before "St:" are unnecessary */ + nb = index(str, ':'); + if (nb && nb > str + 2) + str = nb - 2; + } + nb = str; + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { + if (!*nb) { + if (*ob || context.botlx) { + /* last char printed may be in middle of line */ + tty_curs(WIN_STATUS, i, cw->cury); + cl_end(); + } + break; + } + if (*ob != *nb) + tty_putsym(WIN_STATUS, i, cw->cury, *nb); + if (*ob) + ob++; + } + (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); + cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ + cw->cury = (cw->cury + 1) % 2; + cw->curx = 0; + break; +#endif /* STATUS_HILITES */ case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); @@ -3415,20 +3445,15 @@ static int FDECL(condcolor, (long, unsigned long *)); static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; static unsigned long *tty_colormasks; -static struct tty_status_fields { - int idx; - int color; - int attr; - int x, y; - size_t lth; - boolean valid; - boolean redraw; -} tty_status[2][MAXBLSTATS]; +static struct tty_status_fields + tty_status[2][MAXBLSTATS]; /* 2: first index is for current + and previous */ static int st_fld; -int hpbar_percent, hpbar_color; -struct condition_t { +static int hpbar_percent, hpbar_color; +static struct condition_t { long mask; - char *text[3]; /* 3 potential display values, progressively smaller */ + const char *text[3]; /* 3: potential display values, progressively + * smaller */ } conditions[] = { /* The sequence order of these matters */ { BL_MASK_STONE, {"Stone", "Ston", "Sto"}}, @@ -3445,7 +3470,7 @@ struct condition_t { { BL_MASK_FLY, {"Fly", "Fly", "Fl"}}, { BL_MASK_RIDE, {"Ride", "Rid", "Ri"}}, }; -enum statusfields fieldorder[2][15] = { +static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH }, From 3598fcc92999289663d005d981678a469e2ef352 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 14:10:52 -0400 Subject: [PATCH 24/42] more status handling updates Suppress unneeded spaces from a couple of fields BL_LEVELDESC - trailing spaces. BL_CAP - it only contains a space --- include/wintty.h | 1 + win/tty/wintty.c | 152 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 133 insertions(+), 20 deletions(-) diff --git a/include/wintty.h b/include/wintty.h index 4ff0ddb3c..a4a6625a5 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -77,6 +77,7 @@ struct tty_status_fields { int x, y; size_t lth; boolean valid; + boolean dirty; boolean redraw; }; #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 821859efa..4562788db 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -182,6 +182,7 @@ STATIC_DCL void NDECL(render_status); STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); +STATIC_DCL boolean NDECL(check_windowdata); #endif /* @@ -3448,7 +3449,6 @@ static unsigned long *tty_colormasks; static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: first index is for current and previous */ -static int st_fld; static int hpbar_percent, hpbar_color; static struct condition_t { long mask; @@ -3478,7 +3478,21 @@ static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; +static boolean windowdata_init = FALSE; +/* This controls whether to skip fields that aren't + * flagged as requiring updating during the current + * render_status(). + * + * Hopefully that can be confirmed as working correctly + * for all platforms eventually and the conditional + * setting below can be removed. + */ +#if defined(UNIX) +static int do_field_opt = 0; +#else +static int do_field_opt = 1; #endif +#endif /* STATUS_HILITES */ /* * tty_status_init() @@ -3497,7 +3511,8 @@ tty_status_init() tty_status[NOW][i].attr = ATR_NONE; tty_status[NOW][i].x = 0; tty_status[NOW][i].y = 0; - tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].dirty = FALSE; tty_status[NOW][i].redraw = FALSE; tty_status[BEFORE][i] = tty_status[NOW][i]; } @@ -3587,12 +3602,14 @@ unsigned long *colormasks; force_update = TRUE; break; case BL_CONDITION: + tty_status[NOW][fldidx].idx = fldidx; tty_condition_bits = *condptr; tty_colormasks = colormasks; - tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; + tty_status[NOW][fldidx].dirty = TRUE; break; default: + tty_status[NOW][fldidx].idx = fldidx; Sprintf(status_vals[fldidx], status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", text); @@ -3600,8 +3617,9 @@ unsigned long *colormasks; : NO_COLOR; tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); - tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; + tty_status[NOW][fldidx].dirty = TRUE; + break; } @@ -3611,12 +3629,33 @@ unsigned long *colormasks; hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; } - /* special case fixups */ + /* The core botl engine sends a single blank to the window port + for carrying-capacity when its unused. Let's suppress that */ + if (tty_status[NOW][fldidx].lth == 1 && + status_vals[fldidx][0] == ' ') { + status_vals[fldidx][0] = '\0'; + tty_status[NOW][fldidx].lth = 0; + } + + /* The core botl engine sends BL_LEVELDESC with trailing blanks + included. Let's suppress one of the trailing blanks */ + if (fldidx == BL_LEVELDESC) { + char *lastchar = eos(status_vals[fldidx]); + lastchar--; + while (lastchar && *lastchar == ' ' + && lastchar >= status_vals[fldidx]) { + *lastchar-- = '\0'; + tty_status[NOW][fldidx].lth--; + } + } + + /* Some other special case fixups */ if (iflags.wc2_hitpointbar && fldidx == BL_TITLE) tty_status[NOW][fldidx].lth += 2; /* [ and ] */ if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ + if (check_fields(force_update)) render_status(); return; @@ -3632,8 +3671,11 @@ boolean check_fields(forcefields) boolean forcefields; { - int i, row, col; - boolean valid = TRUE, update_right; + int c, i, row, col; + boolean valid = TRUE, matchprev = FALSE, update_right; + + if (!windowdata_init && !check_windowdata()) + return FALSE; for (row = 0; row < 2; ++row) { col = 1; @@ -3649,16 +3691,44 @@ boolean forcefields; tty_status[NOW][idx].y = row; tty_status[NOW][idx].x = col; + + /* evaluate */ if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) update_right = TRUE; + + /* + * Check values against those already on the dislay. + * - Is the additional processing time for this worth it? + */ + matchprev = FALSE; + if (do_field_opt && tty_status[NOW][idx].dirty) { + /* compare values */ + const char *ob, *nb; /* old byte, new byte */ + + c = col - 1; + ob = &wins[WIN_STATUS]->data[row][c]; + nb = status_vals[idx]; + while (*nb && c < wins[WIN_STATUS]->cols) { + if (*nb != *ob) + break; + nb++; + ob++; + c++; + } + if (!*nb && c > col - 1) + matchprev = TRUE; + } + /* * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so * we flag that here by setting .redraw. - * Then, status_putstr() will see that flag setting + * Then, render_status() will see that flag setting * and ensure that the tty cell content is updated. - */ - if (forcefields || update_right + * After the field has been updated, render_status() + * will also clear .redraw. + */ + if (forcefields || update_right || !matchprev || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; @@ -3711,7 +3781,7 @@ render_status(VOID_ARGS) if (WIN_STATUS == WIN_ERR || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { - paniclog("status", "WIN_ERR on status window."); + paniclog("render_status", "WIN_ERR on status window."); return; } @@ -3728,8 +3798,17 @@ render_status(VOID_ARGS) char *text = status_vals[fldidx]; boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); - st_fld = fldidx; - if (st_fld == BL_CONDITION) { + if (do_field_opt && !tty_status[NOW][fldidx].redraw) + continue; + + /* + * Ignore zero length fields. check_fields() didn't count + * them in either. + */ + if (!tty_status[NOW][fldidx].lth) + continue; + + if (fldidx == BL_CONDITION) { /* * +-----------------+ * | Condition Codes | @@ -3761,7 +3840,7 @@ render_status(VOID_ARGS) } tty_curs(WIN_STATUS, x, y); cl_end(); - } else if (st_fld == BL_GOLD) { + } else if (fldidx == BL_GOLD) { char buf[BUFSZ]; /* * +-----------+ @@ -3845,26 +3924,32 @@ render_status(VOID_ARGS) End_Attr(attridx); } } - /* reset .redraw */ - tty_status[NOW][st_fld].redraw = FALSE; + /* reset .redraw and .dirty now that they've been rendered */ + tty_status[NOW][fldidx].dirty = FALSE; + tty_status[NOW][fldidx].redraw = FALSE; /* * Make a copy of the entire tty_status struct for comparison * of current and previous. */ - tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ + tty_status[BEFORE][fldidx] = tty_status[NOW][fldidx]; /* copy struct */ } } } return; } +/* + * This is what places a field on the tty display. + * If val isn't null, it will be used rather than + * fld (it takes precedence). + */ void tty_putstatusfield(fld, val, x, y) struct tty_status_fields *fld; const char *val; int x,y; { - int i, ncols, lth; + int i, n, ncols, lth; struct WinDesc *cw = 0; const char *text = (char *)0; @@ -3885,10 +3970,13 @@ int x,y; tty_curs(NHW_STATUS, x, y); for (i = 0; i < lth; ++i) { - if ((i + x ) < ncols) { - (void) putchar(*text++); + n = i + x; + if (n < ncols && *text) { + (void) putchar(*text); ttyDisplay->curx++; cw->curx++; + cw->data[y][n-1] = *text; + text++; } } } @@ -3920,6 +4008,30 @@ int col, ncols; return shrinklvl; } +/* + * Ensure the underlying status window data start out + * blank and null-terminated. + */ +boolean +check_windowdata(VOID_ARGS) +{ + if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) { + paniclog("check_windowdata", " null status window."); + return FALSE; + } else if (!windowdata_init) { + int i, n = wins[WIN_STATUS]->cols; + + for (i = 0; i < wins[WIN_STATUS]->cols; ++i) + wins[WIN_STATUS]->data[0][i] = ' '; + wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ + for (i = 0; i < wins[WIN_STATUS]->cols; ++i) + wins[WIN_STATUS]->data[1][i] = ' '; + wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ + windowdata_init = TRUE; + } + return TRUE; +} + #ifdef TEXTCOLOR /* * Return what color this condition should From 149fc5a4dd2854f3ee757d5575379f86da425eae Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 14:42:19 -0400 Subject: [PATCH 25/42] empty field suppression caught condition values unintentionally --- win/tty/wintty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 4562788db..dbfc6d863 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3631,8 +3631,8 @@ unsigned long *colormasks; /* The core botl engine sends a single blank to the window port for carrying-capacity when its unused. Let's suppress that */ - if (tty_status[NOW][fldidx].lth == 1 && - status_vals[fldidx][0] == ' ') { + if (tty_status[NOW][fldidx].lth == 1 + && status_vals[fldidx][0] == ' ') { status_vals[fldidx][0] = '\0'; tty_status[NOW][fldidx].lth = 0; } @@ -3805,7 +3805,7 @@ render_status(VOID_ARGS) * Ignore zero length fields. check_fields() didn't count * them in either. */ - if (!tty_status[NOW][fldidx].lth) + if (!tty_status[NOW][fldidx].lth && fldidx != BL_CONDITION) continue; if (fldidx == BL_CONDITION) { From 3467b9f087d84ececa2721235208ee9aa21b628d Mon Sep 17 00:00:00 2001 From: Bart House Date: Sat, 12 May 2018 13:59:06 -0700 Subject: [PATCH 26/42] Added ntassert() mechanism for Windows based port use. --- include/ntconf.h | 10 ++++++++++ sys/winnt/nttty.c | 16 ++++++++++++++++ sys/winnt/winnt.c | 15 +++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/include/ntconf.h b/include/ntconf.h index 534fa6e5d..c9d2031f8 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -246,4 +246,14 @@ extern int FDECL(set_win32_option, (const char *, const char *)); extern int FDECL(alternative_palette, (char *)); #endif +#ifdef NDEBUG +#define ntassert(expression) ((void)0) +#else +extern void FDECL(ntassert_failed, (const char * exp, const char * file, + int line)); + +#define ntassert(expression) (void)((!!(expression)) || \ + (ntassert_failed(#expression, __FILE__, __LINE__), 0)) +#endif + #endif /* NTCONF_H */ diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 4fbc11c63..035c2f885 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -322,6 +322,10 @@ static void check_buffer_size(int width, int height) static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) { + ntassert(x >= 0 && x < buffer_width); + ntassert(y >= 0 && ((y < buffer_height) || + (y == buffer_height && x == 0))); + return buffer->cells + (buffer_width * y) + x; } @@ -363,6 +367,9 @@ static void back_buffer_flip() static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) { + ntassert(x >= 0 && x < buffer_width); + ntassert(y >= 0 && y < buffer_height); + cell_t * dst = buffer_get_cell(buffer, x, y); cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) @@ -374,6 +381,9 @@ static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, static void back_buffer_write(cell_t * cell, int x, int y) { + ntassert(x >= 0 && x < buffer_width); + ntassert(y >= 0 && y < buffer_height); + cell_t * dst = buffer_get_cell(&back_buffer, x, y); *dst = *cell; @@ -383,6 +393,9 @@ static void back_buffer_write(cell_t * cell, int x, int y) static void back_buffer_clear_to_end_of_line(int x, int y) { + ntassert(x >= 0 && x < buffer_width); + ntassert(y >= 0 && y < buffer_height); + cell_t * cell; cell_t *sentinel; @@ -834,6 +847,9 @@ int in_ch; void cl_end() { + ntassert(ttyDisplay->curx >= 0 && ttyDisplay->curx < buffer_width); + ntassert(ttyDisplay->cury >= 0 && ttyDisplay->cury < buffer_height); + console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 826a02d40..023889881 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -461,6 +461,21 @@ char *buf; } #endif /* RUNTIME_PORT_ID */ +/* ntassert_failed is called when an ntassert's condition is false */ +void ntassert_failed(const char * exp, const char * file, int line) +{ + char message[128]; + _snprintf(message, sizeof(message), + "NHASSERT(%s) in '%s' at line %d\n", exp, file, line); + + if (IsDebuggerPresent()) { + OutputDebugStringA(message); + DebugBreak(); + } + + error(message); +} + #endif /* WIN32 */ /*winnt.c*/ From 1d31a4966169eca100b5a088e1492cbccec15490 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sat, 12 May 2018 15:58:44 -0700 Subject: [PATCH 27/42] Some nttty.c clean-up. --- include/extern.h | 6 + include/global.h | 6 + include/ntconf.h | 2 + sys/share/pcmain.c | 16 +- sys/winnt/nttty.c | 828 +++++++++++++++++++++------------------------ sys/winnt/winnt.c | 12 +- win/tty/wintty.c | 4 - 7 files changed, 412 insertions(+), 462 deletions(-) diff --git a/include/extern.h b/include/extern.h index 96a5ade8b..227a3f222 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1620,6 +1620,7 @@ E int NDECL(tgetch); E int FDECL(ntposkey, (int *, int *, int *)); E void FDECL(set_output_mode, (int)); E void NDECL(synch_cursor); +E void NDECL(nethack_enter_nttty); #endif /* ### o_init.c ### */ @@ -2779,6 +2780,11 @@ E void NDECL(dump_close_log); E void FDECL(dump_redirect, (BOOLEAN_P)); E void FDECL(dump_forward_putstr, (winid, int, const char*, int)); +/* ### winnt.c ### */ +#ifdef WIN32 +E void NDECL(nethack_enter_winnt); +#endif + /* ### wizard.c ### */ E void NDECL(amulet); diff --git a/include/global.h b/include/global.h index 831717c36..f92ce3cfc 100644 --- a/include/global.h +++ b/include/global.h @@ -352,4 +352,10 @@ struct savefile_info { #define PANICTRACE_GDB #endif +/* Supply nethack_enter macro if not supplied by port */ +#ifndef nethack_enter +#define nethack_enter(argc, argv) ((void) 0) +#endif + + #endif /* GLOBAL_H */ diff --git a/include/ntconf.h b/include/ntconf.h index c9d2031f8..88db55b84 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -256,4 +256,6 @@ extern void FDECL(ntassert_failed, (const char * exp, const char * file, (ntassert_failed(#expression, __FILE__, __LINE__), 0)) #endif +#define nethack_enter(argc, argv) nethack_enter_winnt() + #endif /* NTCONF_H */ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 6bb6cfc29..c7d275071 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -57,12 +57,14 @@ extern void FDECL(nethack_exit, (int)); extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ extern int redirect_stdout; /* from sys/share/pcsys.c */ extern int GUILaunched; -HANDLE hStdOut; char *NDECL(exename); char default_window_sys[] = "mswin"; +#ifndef WIN32CON +HANDLE hStdOut; boolean NDECL(fakeconsole); void NDECL(freefakeconsole); #endif +#endif #if defined(MSWIN_GRAPHICS) extern void NDECL(mswin_destroy_reg); @@ -93,6 +95,8 @@ char *argv[]; { boolean resuming; + nethack_enter(argc, argv); + sys_early_init(); #ifdef WIN32 Strcpy(default_window_sys, "tty"); @@ -358,7 +362,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, dir); } if (argc > 1) { -#if defined(WIN32) +#if defined(WIN32) && !defined(WIN32CON) int sfd = 0; boolean tmpconsole = FALSE; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); @@ -368,7 +372,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { -#if defined(WIN32) +#if defined(WIN32) && !defined(WIN32CON) #if 0 if (!hStdOut) { @@ -395,7 +399,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ initoptions(); #endif prscore(argc, argv); -#ifdef WIN32 +#if defined(WIN32) && !defined(WIN32CON) if (tmpconsole) { getreturn("to exit"); freefakeconsole(); @@ -421,7 +425,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ #endif nhusage(); -#ifdef WIN32 +#if defined(WIN32) && !defined(WIN32CON) if (tmpconsole) { getreturn("to exit"); freefakeconsole(); @@ -918,7 +922,7 @@ authorize_wizard_mode() #define PATH_SEPARATOR '\\' #endif -#ifdef WIN32 +#if defined(WIN32) && !defined(WIN32CON) static char exenamebuf[PATHLEN]; extern HANDLE hConIn; extern HANDLE hConOut; diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 035c2f885..51bbad444 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nttty.c $NHDT-Date: 1525643540 2018/05/06 21:52:20 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.77 $ */ +/* NetHack 3.6 nttty.c $NHDT-Date: 1524931557 2018/04/28 16:05:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.71 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ @@ -8,8 +8,8 @@ * Initial Creation M. Allison 1993/01/31 * Switch to low level console output routines M. Allison 2003/10/01 * Restrict cursor movement until input pending M. Lehotay 2003/10/02 - * Call Unicode version of output API on NT R. Chason 2005/10/28 - * Use of back buffer to improve performance B. House 2018/05/06 + * Call Unicode version of output API on NT R. Chason 2005/10/28 + * Use of back buffer to improve performance B. House 2018/05/06 * */ @@ -21,6 +21,34 @@ #include #include "win32api.h" +/* + * Console Buffer Flipping Support + * + * To minimize the number of calls into the WriteConsoleOutputXXX methods, + * we implement a notion of a console back buffer which keeps the next frame + * of console output as it is being composed. When ready to show the new + * frame, we compare this next frame to what is currently being output and + * only call WriteConsoleOutputXXX for those console values that need to + * change. + * + */ + +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ + | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_CHARACTER (' ') + +#define CONSOLE_UNDEFINED_ATTRIBUTE (0) +#define CONSOLE_UNDEFINED_CHARACTER ('\0') + +typedef struct { + WCHAR character; + WORD attribute; +} cell_t; + +cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE }; +cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER, + CONSOLE_UNDEFINED_ATTRIBUTE }; + /* * The following WIN32 Console API routines are used in this file. * @@ -50,19 +78,11 @@ static boolean NDECL(check_font_widths); static void NDECL(set_known_good_console_font); static void NDECL(restore_original_console_font); -/* Win32 Console handles for input and output */ -HANDLE hConIn; -HANDLE hConOut; - /* Win32 Screen buffer,coordinate,console I/O information */ -CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi; COORD ntcoord; INPUT_RECORD ir; /* Support for changing console font if existing glyph widths are too wide */ -boolean console_font_changed; -CONSOLE_FONT_INFOEX original_console_font_info; -UINT original_console_code_page; extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ extern int redirect_stdout; @@ -74,9 +94,8 @@ extern int redirect_stdout; * immediately after it is displayed, yet not bother when started * from the command line. */ -int GUILaunched; +int GUILaunched = FALSE; /* Flag for whether unicode is supported */ -static boolean has_unicode; static boolean init_ttycolor_completed; #ifdef PORT_DEBUG static boolean display_cursor_info = FALSE; @@ -107,14 +126,41 @@ struct console_t { int current_nhcolor; int current_nhattr[ATR_INVERSE+1]; COORD cursor; + HANDLE hConOut; + HANDLE hConIn; + CONSOLE_SCREEN_BUFFER_INFO origcsbi; + int width; + int height; + boolean has_unicode; + int buffer_size; + cell_t * front_buffer; + cell_t * back_buffer; + WCHAR cpMap[256]; + boolean font_changed; + CONSOLE_FONT_INFOEX original_font_info; + UINT original_code_page; } console = { 0, (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED), (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED), NO_COLOR, {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE}, - {0, 0} + {0, 0}, + NULL, + NULL, + { 0 }, + 0, + 0, + FALSE, + 0, + NULL, + NULL, + { 0 }, + FALSE, + { 0 }, + 0 }; + static DWORD ccount, acount; #ifndef CLR_MAX #define CLR_MAX 16 @@ -152,209 +198,32 @@ SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; -/* CP437 to Unicode mapping according to the Unicode Consortium */ -static const WCHAR cp437[] = { - 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, - 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, - 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, - 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, - 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 -}; +/* Console buffer flipping support */ -/* - * cpConsole provides the mapping of characters in the console code page to - * UNICODE. It maps a character to at most two WCHARs storing the number of - * WCHARs in count. - * - * NOTE: cpConsole is only valid if has_unicode is TRUE. - */ - -typedef struct { - WCHAR characters[2]; - int count; -} CodePageMapping; - -static CodePageMapping cpConsole[256]; - -static void initialize_cp_console() -{ - if (has_unicode) { - UINT codePage = GetConsoleOutputCP(); - - for (int i = 0; i < 256; i++) { - char c = (char)i; - cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, - &cpConsole[i].characters[0], 2); - } - } -} - -/* - * Console Buffer Flipping Support - * - * To minimize the number of calls into the WriteConsoleOutputXXX methods, - * we implement a notion of a console back buffer which keeps the next frame - * of console output as it is being composed. When ready to show the new - * frame, we compare this next frame to what is currently being output and - * only call WriteConsoleOutputXXX for those console values that need to - * change. - * - */ - -#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ - | FOREGROUND_BLUE) -#define CONSOLE_CLEAR_CHARACTER (' ') - -typedef struct { - WCHAR characters[2]; - int count; - WORD attribute; -} cell_t; - -typedef struct { - cell_t * cells; -} console_buffer_t; - -static int buffer_width; -static int buffer_height; - -console_buffer_t back_buffer; -console_buffer_t front_buffer; -cell_t clear_cell; -cell_t undefined_cell; - -static boolean buffer_flipping_initialized = FALSE; - -static void check_buffer_size(int width, int height); -static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); - -static void back_buffer_flip(); - -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, - int x, int y); -static void back_buffer_clear_to_end_of_line(int x, int y); -static void back_buffer_write(cell_t * cell, int x, int y); - -static void initialize_buffer_flipping(int width, int height) -{ - if (buffer_flipping_initialized) { - check_buffer_size(width, height); - return; - } - - buffer_width = 0; - buffer_height = 0; - - back_buffer.cells = NULL; - front_buffer.cells = NULL; - - clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; - clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; - clear_cell.characters[1] = 0; - clear_cell.count = 1; - - undefined_cell = clear_cell; - undefined_cell.count = 0; - - check_buffer_size(width, height); - - buffer_flipping_initialized = TRUE; -} - -static void resize_buffer(console_buffer_t * buffer, cell_t * fill, - int width, int height) -{ - cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); - cell_t * dst = cells; - cell_t * sentinel = dst + (width * height); - - while (dst != sentinel) - *dst++ = *fill; - - int height_to_copy = (buffer_height > height ? height : buffer_height); - int bytes_to_copy = (buffer_width > width ? width : buffer_width) - * sizeof(cell_t); - - for (int y = 0; y < height_to_copy; y++) - memcpy(cells + (width * y), buffer->cells + (buffer_width * y), - bytes_to_copy); - - free(buffer->cells); - buffer->cells = cells; -} - -static void check_buffer_size(int width, int height) -{ - if (width != buffer_width || height != buffer_height) { - resize_buffer(&back_buffer, &clear_cell, width, height); - resize_buffer(&front_buffer, &undefined_cell, width, height); - buffer_width = width; - buffer_height = height; - } -} - -static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) -{ - ntassert(x >= 0 && x < buffer_width); - ntassert(y >= 0 && ((y < buffer_height) || - (y == buffer_height && x == 0))); - - return buffer->cells + (buffer_width * y) + x; -} +boolean do_immediate_flips = FALSE; static void back_buffer_flip() { - if (!buffer_flipping_initialized) - return; - - cell_t * back = back_buffer.cells; - cell_t * front = front_buffer.cells; + cell_t * back = console.back_buffer; + cell_t * front = console.front_buffer; COORD pos; + DWORD unused; - for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { - for (pos.X = 0; pos.X < buffer_width; pos.X++) { + for (pos.Y = 0; pos.Y < console.height; pos.Y++) { + for (pos.X = 0; pos.X < console.width; pos.X++) { if (back->attribute != front->attribute) { - WriteConsoleOutputAttribute(hConOut, &back->attribute, - 1, pos, &acount); + WriteConsoleOutputAttribute(console.hConOut, &back->attribute, + 1, pos, &unused); front->attribute = back->attribute; } - if (back->count != front->count || - back->characters[0] != front->characters[0] || - back->characters[1] != front->characters[1]) { - if (has_unicode) { - WriteConsoleOutputCharacterW(hConOut, back->characters, - back->count, pos, &ccount); + if (back->character != front->character) { + if (console.has_unicode) { + WriteConsoleOutputCharacterW(console.hConOut, + &back->character, 1, pos, &unused); } else { - char ch = (char)back->characters[0]; - WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, - &ccount); + char ch = (char)back->character; + WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos, + &unused); } *front = *back; } @@ -364,47 +233,45 @@ static void back_buffer_flip() } } -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, - int x, int y) +void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y) { - ntassert(x >= 0 && x < buffer_width); - ntassert(y >= 0 && y < buffer_height); + ntassert(x >= 0 && x < console.width); + ntassert(y >= 0 && ((y < console.height) || (y == console.height && + x == 0))); + + cell_t * dst = buffer + console.width * y + x; + cell_t * sentinel = buffer + console.buffer_size; + while (dst != sentinel) + *dst++ = *fill; + + if (do_immediate_flips && buffer == console.back_buffer) + back_buffer_flip(); +} + +static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y) +{ + ntassert(x >= 0 && x < console.width); + ntassert(y >= 0 && ((y < console.height) || (y == console.height && + x == 0))); + cell_t * dst = buffer + console.width * y + x; + cell_t *sentinel = buffer + console.width * (y + 1); - cell_t * dst = buffer_get_cell(buffer, x, y); - cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; - if (iflags.debug.immediateflips && buffer == &back_buffer) + if (do_immediate_flips) back_buffer_flip(); } -static void back_buffer_write(cell_t * cell, int x, int y) +void buffer_write(cell_t * buffer, cell_t * cell, COORD pos) { - ntassert(x >= 0 && x < buffer_width); - ntassert(y >= 0 && y < buffer_height); + ntassert(pos.X >= 0 && pos.X < console.width); + ntassert(pos.Y >= 0 && pos.Y < console.height); - cell_t * dst = buffer_get_cell(&back_buffer, x, y); + cell_t * dst = buffer + (console.width * pos.Y) + pos.X; *dst = *cell; - if (iflags.debug.immediateflips) - back_buffer_flip(); -} - -static void back_buffer_clear_to_end_of_line(int x, int y) -{ - ntassert(x >= 0 && x < buffer_width); - ntassert(y >= 0 && y < buffer_height); - - cell_t * cell; - cell_t *sentinel; - - cell = buffer_get_cell(&back_buffer, x, y); - sentinel = buffer_get_cell(&back_buffer, 0, y+1); - while (cell != sentinel) - *cell++ = clear_cell; - - if (iflags.debug.immediateflips) + if (do_immediate_flips && buffer == console.back_buffer) back_buffer_flip(); } @@ -414,10 +281,6 @@ static void back_buffer_clear_to_end_of_line(int x, int y) void gettty() { - console_font_changed = FALSE; - - check_and_set_font(); - #ifndef TEXTCOLOR int k; #endif @@ -460,12 +323,8 @@ void tty_startup(wid, hgt) int *wid, *hgt; { - int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; - - if (twid > 80) - twid = 80; - *wid = twid; - *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + *wid = console.width; + *hgt = console.height; set_option_mod_status("mouse_support", SET_IN_GAME); } @@ -473,6 +332,7 @@ void tty_number_pad(state) int state; { + // do nothing } void @@ -487,23 +347,9 @@ tty_end_screen() { clear_screen(); really_move_cursor(); - if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { - - buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); - buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); - - DWORD ccnt; - COORD newcoord; - - newcoord.X = 0; - newcoord.Y = 0; - FillConsoleOutputAttribute( - hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, - csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); - FillConsoleOutputCharacter( - hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); - } - FlushConsoleInputBuffer(hConIn); + buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); + back_buffer_flip(); + FlushConsoleInputBuffer(console.hConIn); } static BOOL @@ -522,7 +368,7 @@ DWORD ctrltype; hangup(0); #endif #if defined(SAFERHANGUP) - CloseHandle(hConIn); /* trigger WAIT_FAILED */ + CloseHandle(console.hConIn); /* trigger WAIT_FAILED */ return TRUE; #endif default: @@ -530,119 +376,27 @@ DWORD ctrltype; } } -/* - * ntty_open() is called in several places. It is called by win_tty_init - * passing in a mode of zero. It is then later called again by pcmain passing - * in a mode of one. Finally, it can also be called by process_options also - * with a mode of one. - * - * barthouse - The fact this is getting called multiple times needs to be - * reviewed and perhaps cleaned up. - * - */ +/* called by pcmain() and process_options() */ void nttty_open(mode) -int mode; +int mode; // unused { - HANDLE hStdOut; DWORD cmode; - long mask; - - has_unicode = ((GetVersion() & 0x80000000) == 0); - - initialize_cp_console(); - - GUILaunched = 0; - - try : - /* The following lines of code were suggested by - * Bob Landau of Microsoft WIN32 Developer support, - * as the only current means of determining whether - * we were launched from the command prompt, or from - * the NT program manager. M. Allison - */ - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - - if (hStdOut) { - GetConsoleScreenBufferInfo(hStdOut, &origcsbi); - } else if (mode) { - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - - if (!hStdOut && !hStdIn) { - /* Bool rval; */ - AllocConsole(); - AttachConsole(GetCurrentProcessId()); - /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ - freopen("CON", "w", stdout); - freopen("CON", "r", stdin); - } - mode = 0; - goto try; - } else { - /* barthouse - Need to understand how this can happen and - * whether we should bail instead of returning. - */ - return; - } - - /* Obtain handles for the standard Console I/O devices */ - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConOut = GetStdHandle(STD_OUTPUT_HANDLE); - - GetConsoleScreenBufferInfo(hConOut, &csbi); - - int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; - - /* NOTE: We currently force to a width of 80 due to unresolved issues - * within the TTY code. These issues will need to resolved before - * we could allow widths > 80. We will always need a width of - * atleast 80. - */ - - int width = 80; - - /* If the window is not big enough to meet our minimum height needs, - * grow the console's buffer to be large enough. The user will have - * to manually extend the size of the window. - */ - - height = max(25, height); - - COORD size = { width, height }; - SetConsoleScreenBufferSize(hConOut, size); - - initialize_buffer_flipping(width, height); load_keyboard_handler(); /* Initialize the function pointer that points to - * the kbhit() equivalent, in this TTY case nttty_kbhit() - */ + * the kbhit() equivalent, in this TTY case nttty_kbhit() + */ nt_kbhit = nttty_kbhit; - GetConsoleMode(hConIn, &cmode); -#ifdef NO_MOUSE_ALLOWED - mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT - | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; -#else - mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT - | ENABLE_WINDOW_INPUT; -#endif - /* Turn OFF the settings specified in the mask */ - cmode &= ~mask; -#ifndef NO_MOUSE_ALLOWED - cmode |= ENABLE_MOUSE_INPUT; -#endif - SetConsoleMode(hConIn, cmode); if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } - LI = height; - CO = width; + LI = console.height; + CO = console.width; - console.cursor.X = console.cursor.Y = 0; really_move_cursor(); } @@ -653,7 +407,7 @@ boolean *valid; boolean numberpad; int portdebug; { - int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug); + int ch = pProcessKeystroke(console.hConIn, ir, valid, numberpad, portdebug); /* check for override */ if (ch && ch < MAX_OVERRIDES && key_overrides[ch]) ch = key_overrides[ch]; @@ -663,7 +417,7 @@ int portdebug; int nttty_kbhit() { - return pNHkbhit(hConIn, &ir); + return pNHkbhit(console.hConIn, &ir); } int @@ -675,7 +429,7 @@ tgetch() really_move_cursor(); return (program_state.done_hup) ? '\033' - : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod, + : pCheckInput(console.hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc); } @@ -689,7 +443,7 @@ int *x, *y, *mod; really_move_cursor(); ch = (program_state.done_hup) ? '\033' - : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); + : pCheckInput(console.hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); if (!ch) { *x = cc.x; *y = cc.y; @@ -708,7 +462,8 @@ really_move_cursor() oldtitle[39] = '\0'; } Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle, - ttyDisplay->curx, ttyDisplay->cury, console.cursor.X, console.cursor.Y); + ttyDisplay->curx, ttyDisplay->cury, + console.cursor.X, console.cursor.Y); (void) SetConsoleTitle(newtitle); } #endif @@ -716,9 +471,8 @@ really_move_cursor() console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; } - SetConsoleCursorPosition(hConOut, console.cursor); - back_buffer_flip(); + SetConsoleCursorPosition(console.hConOut, console.cursor); } void @@ -778,6 +532,7 @@ char ch; { boolean inverse = FALSE; cell_t cell; + switch (ch) { case '\n': console.cursor.Y++; @@ -795,19 +550,13 @@ char ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? - BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; cell.attribute = console.attr; - if (has_unicode) { - cell.characters[0] = cpConsole[ch].characters[0]; - cell.characters[1] = cpConsole[ch].characters[1]; - cell.count = cpConsole[ch].count; - } else { - cell.characters[0] = ch; - cell.characters[1] = 0; - cell.count = 1; - } - back_buffer_write(&cell, console.cursor.X, console.cursor.Y); + cell.character = (console.has_unicode ? console.cpMap[ch] : ch); + + buffer_write(console.back_buffer, &cell, console.cursor); + console.cursor.X++; } } @@ -817,11 +566,46 @@ char ch; * for win32. It is used for glyphs only, not text. */ +/* CP437 to Unicode mapping according to the Unicode Consortium */ +static const WCHAR cp437[] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 +}; + void g_putch(in_ch) int in_ch; { - cell_t cell; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -834,50 +618,29 @@ int in_ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + + cell_t cell; + cell.attribute = console.attr; - cell.characters[1] = 0; - cell.count = 1; - if (has_unicode) - cell.characters[0] = cp437[ch]; - else - cell.characters[0] = ch; - back_buffer_write(&cell, console.cursor.X, console.cursor.Y); + cell.character = (console.has_unicode ? cp437[ch] : ch); + + buffer_write(console.back_buffer, &cell, console.cursor); } void cl_end() { - ntassert(ttyDisplay->curx >= 0 && ttyDisplay->curx < buffer_width); - ntassert(ttyDisplay->cury >= 0 && ttyDisplay->cury < buffer_height); - console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; - - back_buffer_clear_to_end_of_line(console.cursor.X, console.cursor.Y); - + buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X, + console.cursor.Y); tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } void raw_clear_screen() { - if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { - - buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); - buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); - - DWORD ccnt; - COORD newcoord; - - newcoord.X = 0; - newcoord.Y = 0; - FillConsoleOutputAttribute( - hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, - csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); - FillConsoleOutputCharacter( - hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); - - } + buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); } void @@ -905,27 +668,8 @@ backsp() void cl_eos() { - int cy = ttyDisplay->cury + 1; - if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { - - buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, - ttyDisplay->cury); - buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, - ttyDisplay->cury); - - DWORD ccnt; - COORD newcoord; - - newcoord.X = ttyDisplay->curx; - newcoord.Y = ttyDisplay->cury; - - FillConsoleOutputAttribute( - hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, - csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); - FillConsoleOutputCharacter(hConOut, ' ', - csbi.dwSize.X * csbi.dwSize.Y - cy, - newcoord, &ccnt); - } + buffer_fill_to_end(console.back_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } @@ -1120,12 +864,12 @@ void toggle_mouse_support() { DWORD cmode; - GetConsoleMode(hConIn, &cmode); + GetConsoleMode(console.hConIn, &cmode); if (iflags.wc_mouse_support) cmode |= ENABLE_MOUSE_INPUT; else cmode &= ~ENABLE_MOUSE_INPUT; - SetConsoleMode(hConIn, cmode); + SetConsoleMode(console.hConIn, cmode); } #endif @@ -1154,7 +898,7 @@ win32con_debug_keystrokes() xputs("\n"); while (!valid || ch != 27) { nocmov(ttyDisplay->curx, ttyDisplay->cury); - ReadConsoleInput(hConIn, &ir, 1, &count); + ReadConsoleInput(console.hConIn, &ir, 1, &count); if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) ch = process_keystroke(&ir, &valid, iflags.num_pad, 1); } @@ -1327,10 +1071,10 @@ VA_DECL(const char *, fmt) else { if(!init_ttycolor_completed) init_ttycolor(); + xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); - really_move_cursor(); } VA_END(); return; @@ -1785,7 +1529,7 @@ check_font_widths() { CONSOLE_FONT_INFOEX console_font_info; console_font_info.cbSize = sizeof(console_font_info); - BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE, + BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info); /* get console window and DC @@ -1886,12 +1630,12 @@ set_known_good_console_font() { CONSOLE_FONT_INFOEX console_font_info; console_font_info.cbSize = sizeof(console_font_info); - BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE, + BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info); - console_font_changed = TRUE; - original_console_font_info = console_font_info; - original_console_code_page = GetConsoleOutputCP(); + console.font_changed = TRUE; + console.original_font_info = console_font_info; + console.original_code_page = GetConsoleOutputCP(); wcscpy_s(console_font_info.FaceName, sizeof(console_font_info.FaceName) @@ -1899,12 +1643,10 @@ set_known_good_console_font() L"Consolas"); success = SetConsoleOutputCP(437); - if (!success) - raw_print("Unable to set console code page to 437\n"); + ntassert(success); - success = SetCurrentConsoleFontEx(hConOut, FALSE, &console_font_info); - if (!success) - raw_print("Unable to set console font to Consolas\n"); + success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info); + ntassert(success); } /* restore_original_console_font will restore the console font and code page @@ -1913,20 +1655,204 @@ set_known_good_console_font() void restore_original_console_font() { - if (console_font_changed) { + if (console.font_changed) { BOOL success; raw_print("Restoring original font and code page\n"); - success = SetConsoleOutputCP(original_console_code_page); + success = SetConsoleOutputCP(console.original_code_page); if (!success) raw_print("Unable to restore original code page\n"); - success = SetCurrentConsoleFontEx(hConOut, FALSE, - &original_console_font_info); + success = SetCurrentConsoleFontEx(console.hConOut, FALSE, + &console.original_font_info); if (!success) raw_print("Unable to restore original font\n"); - console_font_changed = FALSE; + console.font_changed = FALSE; } } +/* set_cp_map() creates a mapping of every possible character of a code + * page to its corresponding WCHAR. This is necessary due to the high + * cost of making calls to MultiByteToWideChar() for every character we + * wish to print to the console. + */ + +void set_cp_map() +{ + if (console.has_unicode) { + UINT codePage = GetConsoleOutputCP(); + + for (int i = 0; i < 256; i++) { + char c = (char)i; + int count = MultiByteToWideChar(codePage, 0, &c, 1, + &console.cpMap[i], 1); + ntassert(count == 1); + } + } +} + +/* early_raw_print() is used during early game intialization prior to the + * setting up of the windowing system. This allows early errors and panics + * to have there messages displayed. + * + * early_raw_print() eventually gets replaced by tty_raw_print(). + * + */ + +void early_raw_print(const char *s) +{ + if (console.hConOut == NULL) + return; + + WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; + DWORD unused; + + while (*s != '\0') { + switch (*s) { + case '\n': + console.cursor.Y++; + /* fall through */ + case '\r': + console.cursor.X = 0; + break; + case '\b': + console.cursor.X--; + break; + default: + WriteConsoleOutputAttribute(console.hConOut, &attribute, + 1, console.cursor, &unused); + WriteConsoleOutputCharacterA(console.hConOut, s, + 1, console.cursor, &unused); + console.cursor.X++; + + if (console.cursor.X == console.width) { + console.cursor.Y++; + console.cursor.X = 0; + } + } + s++; + } + + SetConsoleCursorPosition(console.hConOut, console.cursor); + +} + +/* nethack_enter_nttty() is the first thing that is called from main. + * + * We initialize all console state to support rendering to the console + * through out flipping support at this time. This allows us to support + * raw_print prior to our returning. + * + * During this early initialization, we also determine the width and + * height of the console that will be used. This width and height will + * not later change. + * + * We also check and set the console font to a font that we know will work + * well with nethack. + * + * The intent of this early initialization is to get all state that is + * not dependent upon game options initialized allowing us to simplify + * any additional initialization that might be needed when we are actually + * asked to open. + * + * Other then the call below which clears the entire console buffer, no + * other code outputs directly to the console other then the code that + * handles flipping the back buffer. + * + */ + +void nethack_enter_nttty() +{ + /* set up state needed by early_raw_print() */ + windowprocs.win_raw_print = early_raw_print; + + console.cursor.X = 0; + console.cursor.Y = 0; + + console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE); + ntassert(console.hConOut != NULL); // NOTE: this assert will not print + + GetConsoleScreenBufferInfo(console.hConOut, &console.origcsbi); + + /* Testing of widths != COLNO has not turned up any problems. Need + * to do a bit more testing and then we are likely to enable having + * console width match window width. + */ +#if 0 + console.width = console.origcsbi.srWindow.Right - + console.origcsbi.srWindow.Left + 1; + console.Width = max(console.Width, COLNO); +#else + console.width = COLNO; +#endif + + console.height = console.origcsbi.srWindow.Bottom - + console.origcsbi.srWindow.Top + 1; + console.height = max(console.height, ROWNO + 3); + + console.buffer_size = console.width * console.height; + + /* clear the entire console buffer */ + int size = console.origcsbi.dwSize.X * console.origcsbi.dwSize.Y; + DWORD unused; + FillConsoleOutputAttribute( + console.hConOut, CONSOLE_CLEAR_ATTRIBUTE, + size, console.cursor, &unused); + + FillConsoleOutputCharacter( + console.hConOut, CONSOLE_CLEAR_CHARACTER, + size, console.cursor, &unused); + + SetConsoleCursorPosition(console.hConOut, console.cursor); + + /* At this point early_raw_print will output */ + + console.hConIn = GetStdHandle(STD_INPUT_HANDLE); + ntassert(console.hConIn != NULL); + + /* grow the size of the console buffer if it is not wide enough */ + if (console.origcsbi.dwSize.X < console.width) { + COORD size = { + size.Y = console.origcsbi.dwSize.Y, + size.X = console.width + }; + + SetConsoleScreenBufferSize(console.hConOut, size); + } + + /* setup front and back buffers */ + int buffer_size_bytes = sizeof(cell_t) * console.buffer_size; + + console.front_buffer = (cell_t *)malloc(buffer_size_bytes); + buffer_fill_to_end(console.front_buffer, &undefined_cell, 0, 0); + + console.back_buffer = (cell_t *)malloc(buffer_size_bytes); + buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0); + + /* determine whether OS version has unicode support */ + console.has_unicode = ((GetVersion() & 0x80000000) == 0); + + /* check the font before we capture the code page map */ + check_and_set_font(); + set_cp_map(); + + /* Set console mode */ + DWORD cmode, mask; + GetConsoleMode(console.hConIn, &cmode); +#ifdef NO_MOUSE_ALLOWED + mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT + | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; +#else + mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT + | ENABLE_WINDOW_INPUT; +#endif + /* Turn OFF the settings specified in the mask */ + cmode &= ~mask; +#ifndef NO_MOUSE_ALLOWED + cmode |= ENABLE_MOUSE_INPUT; +#endif + SetConsoleMode(console.hConIn, cmode); + +} + #endif /* WIN32 */ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 023889881..067ba5abd 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -207,7 +207,7 @@ VA_DECL(const char *, s) /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); - if (!strncmpi(windowprocs.name, "tty", 3)) { + if (windowprocs.name != NULL && !strncmpi(windowprocs.name, "tty", 3)) { buf[0] = '\n'; (void) vsprintf(&buf[1], s, VA_ARGS); Strcat(buf, "\n"); @@ -473,9 +473,19 @@ void ntassert_failed(const char * exp, const char * file, int line) DebugBreak(); } + // strip off the newline + message[strlen(message) - 1] = '\0'; error(message); } +/* nethack_enter_winnt() is the first thing called from main */ +void nethack_enter_winnt() +{ +#ifdef WIN32CON + nethack_enter_nttty(); +#endif +} + #endif /* WIN32 */ /*winnt.c*/ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index dbfc6d863..31b3167d7 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3398,10 +3398,6 @@ int dir; { if (dir != WININIT) return; -#if defined(WIN32CON) - if (!strncmpi(windowprocs.name, "tty", 3)) - nttty_open(0); -#endif return; } From 039687cf5fd4bd2614439d148464c232d83c7a69 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sat, 12 May 2018 18:06:23 -0700 Subject: [PATCH 28/42] Fix for bug 324 (aka H4216). We now will use nhraykey by default if the players keyboard layout is non-english. nhraykey properly handles non-english input. We also now support changing altkeyhandler in game. --- include/ntconf.h | 4 +- src/options.c | 7 +- sys/winnt/nttty.c | 200 +++++++++++++++++++++++++--------------------- sys/winnt/stubs.c | 6 -- 4 files changed, 113 insertions(+), 104 deletions(-) diff --git a/include/ntconf.h b/include/ntconf.h index 88db55b84..36a87e2e4 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -203,7 +203,9 @@ extern void NDECL(win32_abort); extern void FDECL(nttty_preference_update, (const char *)); extern void NDECL(toggle_mouse_support); extern void FDECL(map_subkeyvalue, (char *)); -extern void NDECL(load_keyboard_handler); +#if defined(WIN32CON) +extern void FDECL(set_altkeyhandler, (const char *)); +#endif extern void NDECL(raw_clear_screen); #include diff --git a/src/options.c b/src/options.c index b0c125051..4eea256a7 100644 --- a/src/options.c +++ b/src/options.c @@ -263,7 +263,7 @@ static struct Comp_Opt { DISP_IN_GAME }, { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/ { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/ - { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME }, + { "altkeyhandler", "alternate key handler", 20, SET_IN_GAME }, #ifdef BACKWARD_COMPAT { "boulder", "deprecated (use S_boulder in sym file instead)", 1, SET_IN_GAME }, @@ -2651,9 +2651,8 @@ boolean tinitial, tfrom_file; bad_negation(fullname, FALSE); return FALSE; } else if ((op = string_for_opt(opts, negated)) != 0) { -#ifdef WIN32 - (void) strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5); - load_keyboard_handler(); +#if defined(WIN32CON) + set_altkeyhandler(op); #endif } else return FALSE; diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 51bbad444..d641b2981 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -190,13 +190,19 @@ typedef int(__stdcall *SOURCEAUTHOR)(char **); typedef int(__stdcall *KEYHANDLERNAME)(char **, int); -HANDLE hLibrary; -PROCESS_KEYSTROKE pProcessKeystroke; -NHKBHIT pNHkbhit; -CHECKINPUT pCheckInput; -SOURCEWHERE pSourceWhere; -SOURCEAUTHOR pSourceAuthor; -KEYHANDLERNAME pKeyHandlerName; +typedef struct { + char * name; // name without DLL extension + HANDLE hLibrary; + PROCESS_KEYSTROKE pProcessKeystroke; + NHKBHIT pNHkbhit; + CHECKINPUT pCheckInput; + SOURCEWHERE pSourceWhere; + SOURCEAUTHOR pSourceAuthor; + KEYHANDLERNAME pKeyHandlerName; +} keyboard_handler_t; + +keyboard_handler_t keyboard_handler; + /* Console buffer flipping support */ @@ -383,7 +389,6 @@ int mode; // unused { DWORD cmode; - load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() */ @@ -407,7 +412,8 @@ boolean *valid; boolean numberpad; int portdebug; { - int ch = pProcessKeystroke(console.hConIn, ir, valid, numberpad, portdebug); + int ch = keyboard_handler.pProcessKeystroke( + console.hConIn, ir, valid, numberpad, portdebug); /* check for override */ if (ch && ch < MAX_OVERRIDES && key_overrides[ch]) ch = key_overrides[ch]; @@ -417,7 +423,7 @@ int portdebug; int nttty_kbhit() { - return pNHkbhit(console.hConIn, &ir); + return keyboard_handler.pNHkbhit(console.hConIn, &ir); } int @@ -429,8 +435,8 @@ tgetch() really_move_cursor(); return (program_state.done_hup) ? '\033' - : pCheckInput(console.hConIn, &ir, &count, iflags.num_pad, 0, &mod, - &cc); + : keyboard_handler.pCheckInput( + console.hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc); } int @@ -443,7 +449,8 @@ int *x, *y, *mod; really_move_cursor(); ch = (program_state.done_hup) ? '\033' - : pCheckInput(console.hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); + : keyboard_handler.pCheckInput( + console.hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); if (!ch) { *x = cc.x; *y = cc.y; @@ -909,20 +916,23 @@ win32con_handler_info() { char *buf; int ci; - if (!pSourceAuthor && !pSourceWhere) + if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere) pline("Keyboard handler source info and author unavailable."); else { - if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) { + if (keyboard_handler.pKeyHandlerName && + keyboard_handler.pKeyHandlerName(&buf, 1)) { xputs("\n"); xputs("Keystroke handler loaded: \n "); xputs(buf); } - if (pSourceAuthor && pSourceAuthor(&buf)) { + if (keyboard_handler.pSourceAuthor && + keyboard_handler.pSourceAuthor(&buf)) { xputs("\n"); xputs("Keystroke handler Author: \n "); xputs(buf); } - if (pSourceWhere && pSourceWhere(&buf)) { + if (keyboard_handler.pSourceWhere && + keyboard_handler.pSourceWhere(&buf)) { xputs("\n"); xputs("Keystroke handler source code available at:\n "); xputs(buf); @@ -974,86 +984,79 @@ register char *op; key_overrides[idx] = val; } -void -load_keyboard_handler() +void unload_keyboard_handler() { - char suffx[] = ".dll"; - char *truncspot; -#define MAX_DLLNAME 25 - char kh[MAX_ALTKEYHANDLER]; - if (iflags.altkeyhandler[0]) { - if (hLibrary) { /* already one loaded apparently */ - FreeLibrary(hLibrary); - hLibrary = (HANDLE) 0; - pNHkbhit = (NHKBHIT) 0; - pCheckInput = (CHECKINPUT) 0; - pSourceWhere = (SOURCEWHERE) 0; - pSourceAuthor = (SOURCEAUTHOR) 0; - pKeyHandlerName = (KEYHANDLERNAME) 0; - pProcessKeystroke = (PROCESS_KEYSTROKE) 0; - } - if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0) - *truncspot = '\0'; - (void) strncpy(kh, iflags.altkeyhandler, - (MAX_ALTKEYHANDLER - sizeof suffx) - 1); - kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; - Strcat(kh, suffx); - Strcpy(iflags.altkeyhandler, kh); - hLibrary = LoadLibrary(kh); - if (hLibrary) { - pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress( - hLibrary, TEXT("ProcessKeystroke")); - pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit")); - pCheckInput = - (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput")); - pSourceWhere = - (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere")); - pSourceAuthor = - (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor")); - pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress( - hLibrary, TEXT("KeyHandlerName")); - } + ntassert(keyboard_handler.hLibrary != NULL); + + FreeLibrary(keyboard_handler.hLibrary); + memset(&keyboard_handler, 0, sizeof(keyboard_handler_t)); +} + +boolean +load_keyboard_handler(const char * inName) +{ + char path[MAX_ALTKEYHANDLER + 4]; + strcpy(path, inName); + strcat(path, ".dll"); + + HANDLE hLibrary = LoadLibrary(path); + + if (hLibrary == NULL) + return FALSE; + + PROCESS_KEYSTROKE pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress( + hLibrary, TEXT("ProcessKeystroke")); + NHKBHIT pNHkbhit = (NHKBHIT) GetProcAddress( + hLibrary, TEXT("NHkbhit")); + CHECKINPUT pCheckInput = + (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput")); + + if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) + { + return FALSE; + } else { + if (keyboard_handler.hLibrary != NULL) + unload_keyboard_handler(); + + keyboard_handler.hLibrary = hLibrary; + + keyboard_handler.pProcessKeystroke = pProcessKeystroke; + keyboard_handler.pNHkbhit = pNHkbhit; + keyboard_handler.pCheckInput = pCheckInput; + + keyboard_handler.pSourceWhere = + (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere")); + keyboard_handler.pSourceAuthor = + (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor")); + keyboard_handler.pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress( + hLibrary, TEXT("KeyHandlerName")); } - if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { - if (hLibrary) { - FreeLibrary(hLibrary); - hLibrary = (HANDLE) 0; - pNHkbhit = (NHKBHIT) 0; - pCheckInput = (CHECKINPUT) 0; - pSourceWhere = (SOURCEWHERE) 0; - pSourceAuthor = (SOURCEAUTHOR) 0; - pKeyHandlerName = (KEYHANDLERNAME) 0; - pProcessKeystroke = (PROCESS_KEYSTROKE) 0; - } - (void) strncpy(kh, "nhdefkey.dll", - (MAX_ALTKEYHANDLER - sizeof suffx) - 1); - kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; - Strcpy(iflags.altkeyhandler, kh); - hLibrary = LoadLibrary(kh); - if (hLibrary) { - pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress( - hLibrary, TEXT("ProcessKeystroke")); - pCheckInput = - (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput")); - pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit")); - pSourceWhere = - (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere")); - pSourceAuthor = - (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor")); - pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress( - hLibrary, TEXT("KeyHandlerName")); - } + + return TRUE; +} + +void set_altkeyhandler(const char * inName) +{ + if (strlen(inName) >= MAX_ALTKEYHANDLER) { + config_error_add("altkeyhandler name '%s' is too long", inName); + return; } - if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { - if (!hLibrary) - raw_printf("\nNetHack was unable to load keystroke handler.\n"); - else { - FreeLibrary(hLibrary); - hLibrary = (HANDLE) 0; - raw_printf("\nNetHack keystroke handler is invalid.\n"); - } - exit(EXIT_FAILURE); + + char name[MAX_ALTKEYHANDLER]; + strcpy(name, inName); + + /* We support caller mistakenly giving name with '.dll' extension */ + char * ext = strchr(name, '.'); + if (ext != NULL) *ext = '\0'; + + if (load_keyboard_handler(name)) + strcpy(iflags.altkeyhandler, name); + else { + config_error_add("unable to load altkeyhandler '%s'", name); + return; } + + return; } /* this is used as a printf() replacement when the window @@ -1853,6 +1856,17 @@ void nethack_enter_nttty() #endif SetConsoleMode(console.hConIn, cmode); + /* load default keyboard handler */ + HKL keyboard_layout = GetKeyboardLayout(0); + DWORD primary_language = (DWORD) keyboard_layout & 0x3f; + + if (primary_language == LANG_ENGLISH) { + if (!load_keyboard_handler("nhdefkey")) + error("Unable to load nhdefkey.dll"); + } else { + if (!load_keyboard_handler("nhraykey")) + error("Unable to load nhdefkey.dll"); + } } #endif /* WIN32 */ diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 712164dc1..61e031c7f 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -136,12 +136,6 @@ register char *op; return; } -void -load_keyboard_handler() -{ - return; -} - /* this is used as a printf() replacement when the window * system isn't initialized yet */ From 45c59857f773d3e958fb5ac4126ac43f67cc42b2 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 May 2018 06:41:57 -0700 Subject: [PATCH 29/42] fix "a Vlad the Impaler" Killing Vlad while he was in bat/fog cloud/wolf form gave poorly worded feedback when he reverted to vampire form. --- src/mon.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mon.c b/src/mon.c index b088460ec..2ccb585cb 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1522540516 2018/03/31 23:55:16 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.250 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1526132509 2018/05/12 13:41:49 $ $NHDT-Branch: master $:$NHDT-Revision: 1.252 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1876,9 +1876,13 @@ register struct monst *mtmp; else mtmp->cham = mndx; if (canspotmon(mtmp)) { + const char *whom = mtmp->data->mname; + /* was using a_monnam(mtmp) but that's weird if mtmp is named: "Dracula suddenly transforms and rises as Dracula" */ - pline(upstart(buf), an(mtmp->data->mname)); + if (!type_is_pname(mtmp->data)) + whom = an(whom); + pline(upstart(buf), whom); vamp_rise_msg = TRUE; } newsym(x, y); From f89968a97388df17336edeb229c1daa1af95833c Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 12 May 2018 01:05:29 -0700 Subject: [PATCH 30/42] fix #H7140 - list MSGTYPE values shows empty strings The 'O' menu's 'list' for MSGTYPE settings showed truncated versions of really long message strings but didn't show anything except the hide/stop/norep setting for ordinary length ones. 3.6.0 showed the latter correctly but suffered buffer overflow for the former; the fix for that had a typo/thinko in it. --- src/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/options.c b/src/options.c index b0c125051..6a265e006 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1510963525 2017/11/18 00:05:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.319 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1526112322 2018/05/12 08:05:22 $ $NHDT-Branch: master $:$NHDT-Revision: 1.323 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4821,7 +4821,7 @@ boolean setinitial, setfromfile; if (strlen(tmp->pattern) > ln) Strcat(strncat(mtbuf, tmp->pattern, ln - 3), "...\""); else - Strcat(mtbuf, "\""); + Strcat(strcat(mtbuf, tmp->pattern), "\""); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mtbuf, MENU_UNSELECTED); tmp = tmp->next; From 650d5230ec7c1a95109c1acbdcf6409e12cf9cc9 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sat, 12 May 2018 19:45:16 -0700 Subject: [PATCH 31/42] Fix memory leak. See bug 1169. --- win/win32/mhmain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index f64ab7665..6c6bfea7d 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -795,6 +795,7 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (!OpenClipboard(hWnd)) { NHMessageBox(hWnd, TEXT("Cannot open clipboard"), MB_OK | MB_ICONERROR); + free(p); return 0; } @@ -803,6 +804,7 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char)); if (hglbCopy == NULL) { CloseClipboard(); + free(p); return FALSE; } From 3b2f7e86e0330f6515781f52d81713471cd02542 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 May 2018 15:19:39 -0400 Subject: [PATCH 32/42] more status updates - prevent an overflow - add make_things_fit() --- win/tty/wintty.c | 490 +++++++++++++++++++++++++++++------------------ 1 file changed, 303 insertions(+), 187 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index dbfc6d863..25df05d5e 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -177,12 +177,15 @@ STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); #ifdef STATUS_HILITES -STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); +STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P, int *, int *)); STATIC_DCL void NDECL(render_status); STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); -STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); STATIC_DCL boolean NDECL(check_windowdata); +STATIC_DCL int NDECL(condition_size); +STATIC_DCL int FDECL(make_things_fit, (BOOLEAN_P)); +STATIC_DCL void FDECL(shrink_enc, (int)); +STATIC_DCL void FDECL(shrink_dlvl, (int)); #endif /* @@ -3444,8 +3447,9 @@ const char *fieldnames[] = { #ifdef STATUS_HILITES static int FDECL(condcolor, (long, unsigned long *)); static int FDECL(condattr, (long, unsigned long *)); -static long tty_condition_bits; static unsigned long *tty_colormasks; +static long tty_condition_bits; +int cond_disp_width[2]; /* 2: current and previous */ static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: first index is for current and previous */ @@ -3470,6 +3474,11 @@ static struct condition_t { { BL_MASK_FLY, {"Fly", "Fly", "Fl"}}, { BL_MASK_RIDE, {"Ride", "Rid", "Ri"}}, }; +static const char *encvals[3][6] = { + { "", "Burdened", "Stressed", "Strained", "Overtaxed", "Overloaded"}, + { "", "Burden", "Stress", "Strain", "Overtax", "Overload" }, + { "", "Brd", "Strs", "Strn", "Ovtx", "Ovld" } +}; static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, @@ -3478,7 +3487,13 @@ static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; + static boolean windowdata_init = FALSE; +static int cond_shrinklvl = 0, cond_width_at_shrink = 0; +static int enclev = 0, enc_shrinklvl = 0; +static dl_shrinklvl = 0; +static boolean truncation_expected = FALSE; + /* This controls whether to skip fields that aren't * flagged as requiring updating during the current * render_status(). @@ -3585,6 +3600,7 @@ int fldidx, chg UNUSED, percent, color; genericptr_t ptr; unsigned long *colormasks; { + int i; long *condptr = (long *) ptr; char *text = (char *) ptr; boolean do_color = FALSE; @@ -3607,7 +3623,17 @@ unsigned long *colormasks; tty_colormasks = colormasks; tty_status[NOW][fldidx].valid = TRUE; tty_status[NOW][fldidx].dirty = TRUE; + truncation_expected = FALSE; break; + case BL_CAP: + for (i = 0; i < SIZE(encvals); ++i) { + if (!strcmp(encvals[enc_shrinklvl][i], + status_vals[BL_CAP])) { + enclev = i; + break; + } + } + /*FALLTHRU*/ default: tty_status[NOW][fldidx].idx = fldidx; Sprintf(status_vals[fldidx], @@ -3637,9 +3663,9 @@ unsigned long *colormasks; tty_status[NOW][fldidx].lth = 0; } - /* The core botl engine sends BL_LEVELDESC with trailing blanks - included. Let's suppress one of the trailing blanks */ - if (fldidx == BL_LEVELDESC) { + /* The core botl engine sends trailing blanks for some fields + Let's suppress the trailing blanks */ + if (fldidx == BL_LEVELDESC || fldidx == BL_HUNGER) { char *lastchar = eos(status_vals[fldidx]); lastchar--; while (lastchar && *lastchar == ' ' @@ -3655,12 +3681,58 @@ unsigned long *colormasks; if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - - if (check_fields(force_update)) + if (make_things_fit(force_update) || truncation_expected) render_status(); return; } +int +make_things_fit(force_update) +boolean force_update; +{ + int trycnt, fitting = 0, condsz = 0, requirement = 0; + int rowsz[2], otheroptions = 0; + boolean check = FALSE; + + condsz = condition_size(); + for (trycnt = 0; trycnt < 6 && !fitting; ++trycnt) { + check = check_fields(force_update, &rowsz[0], &rowsz[1]); + if (!check) return 0; + + requirement = rowsz[1]; + if (requirement < wins[WIN_STATUS]->cols - 1) { + fitting = requirement; + break; /* we're good */ + } + if (trycnt < 2) { + if (cond_shrinklvl < trycnt + 1) { + cond_shrinklvl = trycnt + 1; + condsz = condition_size(); + cond_width_at_shrink = cond_disp_width[NOW]; + } + continue; + } + if (cond_shrinklvl >= 2) { + /* We've exhausted the condition identifiers shrinkage, + * so let's try something other things... + */ + if (otheroptions == 0 || otheroptions == 1) { + /* try shrinking the encumbrance word */ + shrink_enc(otheroptions + 1); + otheroptions++; + } else if (otheroptions == 2) { + shrink_dlvl(1); + otheroptions++; + } else { + /* Last resort - turn on trunction */ + truncation_expected = TRUE; + otheroptions++; + } + } + } + return fitting; +} + /* * This is the routine where we figure out where each field * should be placed, and flag whether the on-screen details @@ -3668,10 +3740,11 @@ unsigned long *colormasks; * This is now done at an individual field case-by-case level. */ boolean -check_fields(forcefields) +check_fields(forcefields, topsz, bottomsz) boolean forcefields; +int *topsz, *bottomsz; { - int c, i, row, col; + int c, i, row, col, trackx, idx; boolean valid = TRUE, matchprev = FALSE, update_right; if (!windowdata_init && !check_windowdata()) @@ -3679,13 +3752,12 @@ boolean forcefields; for (row = 0; row < 2; ++row) { col = 1; + trackx = 1; update_right = FALSE; for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { - int idx = fieldorder[row][i]; - + idx = fieldorder[row][i]; if (!status_activefields[idx]) continue; - if (!tty_status[NOW][idx].valid) valid = FALSE; @@ -3696,29 +3768,30 @@ boolean forcefields; if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) update_right = TRUE; - /* - * Check values against those already on the dislay. - * - Is the additional processing time for this worth it? - */ - matchprev = FALSE; - if (do_field_opt && tty_status[NOW][idx].dirty) { - /* compare values */ - const char *ob, *nb; /* old byte, new byte */ + if (!update_right && !forcefields) { + /* + * Check values against those already on the dislay. + * - Is the additional processing time for this worth it? + */ + matchprev = FALSE; + if (do_field_opt && tty_status[NOW][idx].dirty) { + /* compare values */ + const char *ob, *nb; /* old byte, new byte */ - c = col - 1; - ob = &wins[WIN_STATUS]->data[row][c]; - nb = status_vals[idx]; - while (*nb && c < wins[WIN_STATUS]->cols) { - if (*nb != *ob) - break; - nb++; - ob++; - c++; + c = col - 1; + ob = &wins[WIN_STATUS]->data[row][c]; + nb = status_vals[idx]; + while (*nb && c < wins[WIN_STATUS]->cols) { + if (*nb != *ob) + break; + nb++; + ob++; + c++; + } + if (!*nb && c > col - 1) + matchprev = TRUE; } - if (!*nb && c > col - 1) - matchprev = TRUE; - } - + } /* * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so @@ -3726,18 +3799,201 @@ boolean forcefields; * Then, render_status() will see that flag setting * and ensure that the tty cell content is updated. * After the field has been updated, render_status() - * will also clear .redraw. + * will also clear .redraw and .dirty. */ if (forcefields || update_right || !matchprev || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) - tty_status[NOW][idx].redraw = TRUE; + tty_status[NOW][idx].redraw = TRUE; col += tty_status[NOW][idx].lth; } + if (row && bottomsz) + *bottomsz = col + tty_status[NOW][idx].lth; + else if (topsz) + *topsz = col + tty_status[NOW][idx].lth; } return valid; } +/* + * This is what places a field on the tty display. + * If val isn't null, it will be used rather than + * fld (it takes precedence). + */ +void +tty_putstatusfield(fld, val, x, y) +struct tty_status_fields *fld; +const char *val; +int x,y; +{ + int i, n, ncols, lth; + struct WinDesc *cw = 0; + const char *text = (char *)0; + + if ((cw = wins[NHW_STATUS]) == (struct WinDesc *) 0) + panic("Invalid WinDesc\n"); + + ncols = cw->cols; + if (val) { + text = val; + lth = strlen(text); + } else if (fld) { + text = status_vals[fld->idx]; + lth = fld->lth; + } + if (!text) return; + + print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); + + if (x <= ncols) { + tty_curs(NHW_STATUS, x, y); + for (i = 0; i < lth; ++i) { + n = i + x; + if (n < ncols && *text) { + (void) putchar(*text); + ttyDisplay->curx++; + cw->curx++; + cw->data[y][n-1] = *text; + text++; + } + } + } else { + /* Now we're truncating */ + if (truncation_expected) + ; /* but we new in advance */ + } +} + +int +condition_size() +{ + long mask = 0L; + int c, x; + boolean fitting = FALSE; + + x = 0; + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) { + x++; /* for spacer */ + x += (int) strlen(conditions[c].text[cond_shrinklvl]); + } + } + tty_status[NOW][BL_CONDITION].lth = x; + cond_disp_width[NOW] = x; + return x; +} + +void +shrink_enc(lvl) +int lvl; +{ + /* shrink or restore the encumbrance word */ + if (lvl == 0 || lvl <= 2) { + enc_shrinklvl = lvl; + Strcpy(status_vals[BL_CAP], encvals[lvl][enclev]); + } + tty_status[NOW][BL_CAP].lth = strlen(status_vals[BL_CAP]); +} + +void +shrink_dlvl(lvl) +int lvl; +{ + /* try changing Dlvl: to Dl: */ + char buf[BUFSZ]; + char *levval =index(status_vals[BL_LEVELDESC], ':'); + + if (levval) { + if (lvl == 0) + Strcpy(buf, "Dlvl"); + else + Strcpy(buf, "Dl"); + + Strcat(buf, levval); + Strcpy(status_vals[BL_LEVELDESC], buf); + tty_status[NOW][BL_LEVELDESC].lth = + strlen(status_vals[BL_LEVELDESC]); + } +} + +/* + * Ensure the underlying status window data start out + * blank and null-terminated. + */ +boolean +check_windowdata(VOID_ARGS) +{ + if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) { + paniclog("check_windowdata", " null status window."); + return FALSE; + } else if (!windowdata_init) { + int i, n = wins[WIN_STATUS]->cols; + + for (i = 0; i < wins[WIN_STATUS]->cols; ++i) { + wins[WIN_STATUS]->data[0][i] = ' '; + wins[WIN_STATUS]->data[1][i] = ' '; + } + wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ + wins[WIN_STATUS]->data[1][n - 1] = '\0'; /* null terminate */ + windowdata_init = TRUE; + } + return TRUE; +} + +#ifdef TEXTCOLOR +/* + * Return what color this condition should + * be displayed in based on user settings. + */ +int condcolor(bm, bmarray) +long bm; +unsigned long *bmarray; +{ + int i; + + if (bm && bmarray) + for (i = 0; i < CLR_MAX; ++i) { + if (bmarray[i] && (bm & bmarray[i])) + return i; + } + return NO_COLOR; +} +#endif /* TEXTCOLOR */ + +int condattr(bm, bmarray) +long bm; +unsigned long *bmarray; +{ + int attr = 0; + int i; + + if (bm && bmarray) { + for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) { + if (bmarray[i] && (bm & bmarray[i])) { + switch(i) { + case HL_ATTCLR_DIM: + attr |= HL_DIM; + break; + case HL_ATTCLR_BLINK: + attr |= HL_BLINK; + break; + case HL_ATTCLR_ULINE: + attr |= HL_ULINE; + break; + case HL_ATTCLR_INVERSE: + attr |= HL_INVERSE; + break; + case HL_ATTCLR_BOLD: + attr |= HL_BOLD; + break; + } + } + } + } + return attr; +} + #define Begin_Attr(m) \ if (m) { \ if ((m) & HL_BOLD) \ @@ -3770,7 +4026,7 @@ void render_status(VOID_ARGS) { long mask = 0L; - int i, c, row, shrinklvl = 0, attrmask = 0; + int i, c, row, attrmask = 0; struct WinDesc *cw = 0; boolean do_color = FALSE, fit = FALSE; struct tty_status_fields *nullfield = (struct tty_status_fields *)0; @@ -3814,7 +4070,6 @@ render_status(VOID_ARGS) * | Condition Codes | * +-----------------+ */ - shrinklvl = set_cond_shrinklvl(x, cw->cols); for (c = 0; c < SIZE(conditions); ++c) { mask = conditions[c].mask; if ((tty_condition_bits & mask) == mask) { @@ -3828,9 +4083,11 @@ render_status(VOID_ARGS) term_start_color(coloridx); } } + if (x >= cw->cols && !truncation_expected) + impossible("Unexpected condition placement overflow"); tty_putstatusfield(nullfield, - conditions[c].text[shrinklvl], x, y); - x += (int) strlen(conditions[c].text[shrinklvl]); + conditions[c].text[cond_shrinklvl], x, y); + x += (int) strlen(conditions[c].text[cond_shrinklvl]); if (iflags.hilite_delta) { if (do_color && coloridx != NO_COLOR) term_end_color(); @@ -3935,156 +4192,15 @@ render_status(VOID_ARGS) } } } + if (cond_disp_width[NOW] < cond_width_at_shrink) { + cond_shrinklvl = 0; /* reset */ + cond_width_at_shrink = condition_size(); + shrink_enc(0); + shrink_dlvl(0); + } return; } -/* - * This is what places a field on the tty display. - * If val isn't null, it will be used rather than - * fld (it takes precedence). - */ -void -tty_putstatusfield(fld, val, x, y) -struct tty_status_fields *fld; -const char *val; -int x,y; -{ - int i, n, ncols, lth; - struct WinDesc *cw = 0; - const char *text = (char *)0; - - if ((cw = wins[NHW_STATUS]) == (struct WinDesc *) 0) - panic("Invalid WinDesc\n"); - - ncols = cw->cols; - if (val) { - text = val; - lth = strlen(text); - } else if (fld) { - text = status_vals[fld->idx]; - lth = fld->lth; - } - if (!text) return; - - print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); - - tty_curs(NHW_STATUS, x, y); - for (i = 0; i < lth; ++i) { - n = i + x; - if (n < ncols && *text) { - (void) putchar(*text); - ttyDisplay->curx++; - cw->curx++; - cw->data[y][n-1] = *text; - text++; - } - } -} - -int -set_cond_shrinklvl(col, ncols) -int col, ncols; -{ - long mask = 0L; - int j, c, x, avail, shrinklvl = 0; - boolean fitting = FALSE; - - avail = ncols - col; - /* determine appropriate shrinklvl required */ - for (j = 0; j < 3 && !fitting; ++j) { - x = 0; - for (c = 0; c < SIZE(conditions); ++c) { - mask = conditions[c].mask; - if ((tty_condition_bits & mask) == mask) { - x++; /* for spacer */ - x += (int) strlen(conditions[c].text[shrinklvl]); - } - } - if (x < avail) - fitting = TRUE; - else if (shrinklvl < 2) - shrinklvl++; - } - return shrinklvl; -} - -/* - * Ensure the underlying status window data start out - * blank and null-terminated. - */ -boolean -check_windowdata(VOID_ARGS) -{ - if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) { - paniclog("check_windowdata", " null status window."); - return FALSE; - } else if (!windowdata_init) { - int i, n = wins[WIN_STATUS]->cols; - - for (i = 0; i < wins[WIN_STATUS]->cols; ++i) - wins[WIN_STATUS]->data[0][i] = ' '; - wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ - for (i = 0; i < wins[WIN_STATUS]->cols; ++i) - wins[WIN_STATUS]->data[1][i] = ' '; - wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ - windowdata_init = TRUE; - } - return TRUE; -} - -#ifdef TEXTCOLOR -/* - * Return what color this condition should - * be displayed in based on user settings. - */ -int condcolor(bm, bmarray) -long bm; -unsigned long *bmarray; -{ - int i; - - if (bm && bmarray) - for (i = 0; i < CLR_MAX; ++i) { - if (bmarray[i] && (bm & bmarray[i])) - return i; - } - return NO_COLOR; -} -#endif /* TEXTCOLOR */ - -int condattr(bm, bmarray) -long bm; -unsigned long *bmarray; -{ - int attr = 0; - int i; - - if (bm && bmarray) { - for (i = HL_ATTCLR_DIM; i < BL_ATTCLR_MAX; ++i) { - if (bmarray[i] && (bm & bmarray[i])) { - switch(i) { - case HL_ATTCLR_DIM: - attr |= HL_DIM; - break; - case HL_ATTCLR_BLINK: - attr |= HL_BLINK; - break; - case HL_ATTCLR_ULINE: - attr |= HL_ULINE; - break; - case HL_ATTCLR_INVERSE: - attr |= HL_INVERSE; - break; - case HL_ATTCLR_BOLD: - attr |= HL_BOLD; - break; - } - } - } - } - return attr; -} - #endif /* STATUS_HILITES */ #endif /* TTY_GRAPHICS */ From 3dbbd188d9d0e51d78dfc4f0fb999be781538f4b Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 13 May 2018 12:49:52 -0700 Subject: [PATCH 33/42] Fixing typo. --- sys/winnt/nttty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d641b2981..33bfbb630 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1865,7 +1865,7 @@ void nethack_enter_nttty() error("Unable to load nhdefkey.dll"); } else { if (!load_keyboard_handler("nhraykey")) - error("Unable to load nhdefkey.dll"); + error("Unable to load nhraykey.dll"); } } From 0afd2570cb335d2d3c8048787fd348b41b0caa89 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 13 May 2018 13:29:13 -0700 Subject: [PATCH 34/42] Removing temporary debugging code and fixing compiler warnings. --- sys/winnt/nttty.c | 2 +- win/win32/mhdlg.c | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 33bfbb630..1b7d59886 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1858,7 +1858,7 @@ void nethack_enter_nttty() /* load default keyboard handler */ HKL keyboard_layout = GetKeyboardLayout(0); - DWORD primary_language = (DWORD) keyboard_layout & 0x3f; + DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f; if (primary_language == LANG_ENGLISH) { if (!load_keyboard_handler("nhdefkey")) diff --git a/win/win32/mhdlg.c b/win/win32/mhdlg.c index a91eecf20..6bc7d4eb3 100644 --- a/win/win32/mhdlg.c +++ b/win/win32/mhdlg.c @@ -391,10 +391,6 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case NM_KILLFOCUS: { - char buf[64]; - sprintf(buf, "KILLFOCUS %lx\n", (unsigned long) control); - OutputDebugStringA(buf); - if (data->focus == data->control_race) { data->focus = NULL; ListView_RedrawItems(data->control_race, 0, data->race_count - 1); @@ -406,9 +402,6 @@ PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; case NM_SETFOCUS: { - char buf[64]; - sprintf(buf, "SETFOCUS %lx\n", (unsigned long) control); - OutputDebugStringA(buf); data->focus = control; if (control == data->control_race) { @@ -716,15 +709,9 @@ plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (lpdis->itemID < 0) return FALSE; - HWND control = GetDlgItem(hWnd, wParam); + HWND control = GetDlgItem(hWnd, (int) wParam); int i = lpdis->itemID; - { - char buf[64]; - sprintf(buf, "DRAW %lx %d\n", (unsigned long)control, i); - OutputDebugStringA(buf); - } - const char * string; boolean ok = TRUE; @@ -774,12 +761,6 @@ plselDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) client_rt.left + ListView_GetColumnWidth(lpdis->hwndItem, 0), lpdis->rcItem.bottom); DrawFocusRect(lpdis->hDC, &rect); - - { - char buf[64]; - sprintf(buf, "FOCUS %lx %d\n", (unsigned long)control, i); - OutputDebugStringA(buf); - } } } From 2b8ac8af9eaa8940b8dc0b7c73929336b5149bb4 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 May 2018 16:42:11 -0400 Subject: [PATCH 35/42] missing stubs for NetHackW.exe --- sys/winnt/stubs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 61e031c7f..469a0bdb2 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -170,4 +170,14 @@ more() return; } +void +nethack_enter_nttty() +{ + return; +} + +void +set_altkeyhandler(const char *inName) +{ +} #endif /* TTYSTUBS */ From 860b9c35c13b291a451c782395f272416fcc6204 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 13 May 2018 21:24:14 -0400 Subject: [PATCH 36/42] testing build with STATUS_HILITES --- win/tty/wintty.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 7b1802176..77835a5ec 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2445,7 +2445,9 @@ char ch; print_vt_code2(AVTC_SELECT_WINDOW, window); switch (cw->type) { +#ifndef STATUS_HILITES case NHW_STATUS: +#endif case NHW_MAP: case NHW_BASE: tty_curs(window, x, y); @@ -2501,6 +2503,10 @@ const char *str; register struct WinDesc *cw = 0; register char *ob; register long i, n0; +#ifndef STATUS_HILITES + register const char *nb; + register long j; +#endif /* Assume there's a real problem if the window is missing -- * probably a panic message @@ -3421,7 +3427,52 @@ char *posbar; * | STATUS CODE | * +------------------+ */ - + +/* + * ---------------------------------------------------------------- + * tty_status_update + * + * Called from the NetHack core and receives info hand-offs + * from the core, processes them, storing some information + * for rendering to the tty. + * -> make_things_fit() + * -> render_status() + * + * make_things_fit + * + * Called from tty_status_update(). It calls check_fields() + * (described next) to get the required number of columns + * and tries a few different ways to squish a representation + * of the status window values onto the 80 column tty display. + * ->check_fields() + * ->condition_size() - get the width of all conditions + * ->shrink_enc() - shrink encumbrance message word + * ->shrink_dlvl() - reduce the width of Dlvl:42 + * + * check_fields + * + * Verifies that all the fields are ready for display, and + * returns FALSE if called too early in the startup + * processing sequence. It also figures out where everything + * needs to go, taking the current shrinking attempts into + * account. It returns number of columns needed back to + * make_things_fit(), so make_things_fit() can make attempt + * to make adjustments. + * + * render_status + * + * Goes through each of the two status row's fields and + * calls tty_putstatusfield() to place them on the display. + * ->tty_putstatusfield() + * + * tty_putstatusfield() + * + * Move the cursor to the target spot, and output the field + * asked for by render_status(). + * + * ---------------------------------------------------------------- + */ + /* * The following data structures come from the genl_ routines in * src/windows.c and as such are considered to be on the window-port @@ -3841,7 +3892,7 @@ int x,y; print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); - if (x <= ncols) { + if (x <= ncols && y < 2) { tty_curs(NHW_STATUS, x, y); for (i = 0; i < lth; ++i) { n = i + x; From 53c7cb8c78c2de69deec251f56bd28f6e9b08a72 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 13 May 2018 18:54:20 -0700 Subject: [PATCH 37/42] Changes to xputc_core to handle cursor correctly. --- sys/winnt/nttty.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d641b2981..61bd36f40 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -542,7 +542,8 @@ char ch; switch (ch) { case '\n': - console.cursor.Y++; + if (console.cursor.Y < console.height - 1) + console.cursor.Y++; /* fall through */ case '\r': console.cursor.X = 1; @@ -565,6 +566,12 @@ char ch; buffer_write(console.back_buffer, &cell, console.cursor); console.cursor.X++; + + if (console.cursor.X == console.width) { + console.cursor.X = 0; + if (console.cursor.Y < console.height - 1) + console.cursor.Y++; + } } } From 1f877dbca1ed0e92b61ef7a84b7eb5980f18e812 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 13 May 2018 20:46:43 -0700 Subject: [PATCH 38/42] Additional changes to xputc_core() and early_raw_print() to manage the cursor position correctly. This is needed to handle raw printing correctly. Added check for when we might be running off the bottom of the screen when handling msmsg(). Added runtime checks to keep cursor always within bounds. --- sys/winnt/nttty.c | 117 ++++++++++++++++++++++++++++++---------------- 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 61bd36f40..6dfb77471 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -458,6 +458,15 @@ int *x, *y, *mod; return ch; } +static void set_console_cursor(int x, int y) +{ + ntassert(x >= 0 && x < console.width); + ntassert(y >= 0 && y < console.height); + + console.cursor.X = max(0, min(console.width - 1, x)); + console.cursor.Y = max(0, min(console.height - 1, y)); +} + static void really_move_cursor() { @@ -474,10 +483,9 @@ really_move_cursor() (void) SetConsoleTitle(newtitle); } #endif - if (ttyDisplay) { - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; - } + if (ttyDisplay) + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); + back_buffer_flip(); SetConsoleCursorPosition(console.hConOut, console.cursor); } @@ -488,26 +496,25 @@ register int x, y; { ttyDisplay->cury = y; ttyDisplay->curx = x; - console.cursor.X = x; - console.cursor.Y = y; + + set_console_cursor(x, y); } void nocmov(x, y) int x, y; { - console.cursor.X = x; - console.cursor.Y = y; ttyDisplay->curx = x; ttyDisplay->cury = y; + + set_console_cursor(x, y); } void xputc(ch) char ch; { - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); xputc_core(ch); } @@ -518,10 +525,8 @@ const char *s; int k; int slen = strlen(s); - if (ttyDisplay) { - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; - } + if (ttyDisplay) + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); if (s) { for (k = 0; k < slen && s[k]; ++k) @@ -537,6 +542,9 @@ void xputc_core(ch) char ch; { + ntassert(console.cursor.X >= 0 && console.cursor.X < console.width); + ntassert(console.cursor.Y >= 0 && console.cursor.Y < console.height); + boolean inverse = FALSE; cell_t cell; @@ -549,7 +557,12 @@ char ch; console.cursor.X = 1; break; case '\b': - console.cursor.X--; + if (console.cursor.X > 1) { + console.cursor.X--; + } else if(console.cursor.Y > 0) { + console.cursor.X = console.width - 1; + console.cursor.Y--; + } break; default: inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse); @@ -565,14 +578,18 @@ char ch; buffer_write(console.back_buffer, &cell, console.cursor); - console.cursor.X++; - - if (console.cursor.X == console.width) { - console.cursor.X = 0; - if (console.cursor.Y < console.height - 1) + if (console.cursor.X == console.width - 1) { + if (console.cursor.Y < console.height - 1) { + console.cursor.X = 1; console.cursor.Y++; + } + } else { + console.cursor.X++; } } + + ntassert(console.cursor.X >= 0 && console.cursor.X < console.width); + ntassert(console.cursor.Y >= 0 && console.cursor.Y < console.height); } /* @@ -623,8 +640,7 @@ int in_ch; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse); console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ? @@ -644,8 +660,7 @@ int in_ch; void cl_end() { - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X, console.cursor.Y); tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); @@ -667,15 +682,14 @@ clear_screen() void home() { - console.cursor.X = console.cursor.Y = 0; ttyDisplay->curx = ttyDisplay->cury = 0; + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); } void backsp() { - console.cursor.X = ttyDisplay->curx; - console.cursor.Y = ttyDisplay->cury; + set_console_cursor(ttyDisplay->curx, ttyDisplay->cury); xputc_core('\b'); } @@ -1082,6 +1096,17 @@ VA_DECL(const char *, fmt) if(!init_ttycolor_completed) init_ttycolor(); + /* if we have generated too many messages ... ask the user to + * confirm and then clear. + */ + if (console.cursor.Y > console.height - 4) { + xputs("Hit to continue."); + while (pgetchar() != '\n') + ; + raw_clear_screen(); + set_console_cursor(1, 0); + } + xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); @@ -1714,35 +1739,49 @@ void early_raw_print(const char *s) if (console.hConOut == NULL) return; + ntassert(console.cursor.X >= 0 && console.cursor.X < console.width); + ntassert(console.cursor.Y >= 0 && console.cursor.Y < console.height); + WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; DWORD unused; while (*s != '\0') { switch (*s) { case '\n': - console.cursor.Y++; + if (console.cursor.Y < console.height - 1) + console.cursor.Y++; /* fall through */ case '\r': - console.cursor.X = 0; + console.cursor.X = 1; break; case '\b': - console.cursor.X--; + if (console.cursor.X > 1) { + console.cursor.X--; + } else if(console.cursor.Y > 0) { + console.cursor.X = console.width - 1; + console.cursor.Y--; + } break; default: WriteConsoleOutputAttribute(console.hConOut, &attribute, 1, console.cursor, &unused); WriteConsoleOutputCharacterA(console.hConOut, s, 1, console.cursor, &unused); - console.cursor.X++; - - if (console.cursor.X == console.width) { - console.cursor.Y++; - console.cursor.X = 0; + if (console.cursor.X == console.width - 1) { + if (console.cursor.Y < console.height - 1) { + console.cursor.X = 1; + console.cursor.Y++; + } + } else { + console.cursor.X++; } } s++; } + ntassert(console.cursor.X >= 0 && console.cursor.X < console.width); + ntassert(console.cursor.Y >= 0 && console.cursor.Y < console.height); + SetConsoleCursorPosition(console.hConOut, console.cursor); } @@ -1776,9 +1815,6 @@ void nethack_enter_nttty() /* set up state needed by early_raw_print() */ windowprocs.win_raw_print = early_raw_print; - console.cursor.X = 0; - console.cursor.Y = 0; - console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE); ntassert(console.hConOut != NULL); // NOTE: this assert will not print @@ -1802,9 +1838,11 @@ void nethack_enter_nttty() console.buffer_size = console.width * console.height; + /* clear the entire console buffer */ int size = console.origcsbi.dwSize.X * console.origcsbi.dwSize.Y; DWORD unused; + set_console_cursor(0, 0); FillConsoleOutputAttribute( console.hConOut, CONSOLE_CLEAR_ATTRIBUTE, size, console.cursor, &unused); @@ -1813,9 +1851,10 @@ void nethack_enter_nttty() console.hConOut, CONSOLE_CLEAR_CHARACTER, size, console.cursor, &unused); + set_console_cursor(1, 0); SetConsoleCursorPosition(console.hConOut, console.cursor); - /* At this point early_raw_print will output */ + /* At this point early_raw_print will work */ console.hConIn = GetStdHandle(STD_INPUT_HANDLE); ntassert(console.hConIn != NULL); From fba7c06fd63cfde58acbaf3f901f8f8582ffb5e0 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 14 May 2018 21:09:01 -0400 Subject: [PATCH 39/42] put back the functionality of commandline --debug:immediateflips overwritten recently --- sys/winnt/nttty.c | 8 +++----- sys/winnt/stubs.c | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 6dfb77471..9b26a5e3f 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -206,8 +206,6 @@ keyboard_handler_t keyboard_handler; /* Console buffer flipping support */ -boolean do_immediate_flips = FALSE; - static void back_buffer_flip() { cell_t * back = console.back_buffer; @@ -250,7 +248,7 @@ void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y) while (dst != sentinel) *dst++ = *fill; - if (do_immediate_flips && buffer == console.back_buffer) + if (iflags.debug.immediateflips && buffer == console.back_buffer) back_buffer_flip(); } @@ -265,7 +263,7 @@ static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y) while (dst != sentinel) *dst++ = clear_cell; - if (do_immediate_flips) + if (iflags.debug.immediateflips) back_buffer_flip(); } @@ -277,7 +275,7 @@ void buffer_write(cell_t * buffer, cell_t * cell, COORD pos) cell_t * dst = buffer + (console.width * pos.Y) + pos.X; *dst = *cell; - if (do_immediate_flips && buffer == console.back_buffer) + if (iflags.debug.immediateflips && buffer == console.back_buffer) back_buffer_flip(); } diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 469a0bdb2..ef161ae9b 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -179,5 +179,6 @@ nethack_enter_nttty() void set_altkeyhandler(const char *inName) { + return; } #endif /* TTYSTUBS */ From 2e8b69d5ff2d896c9768455c105ad428c566538e Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 14 May 2018 21:13:37 -0400 Subject: [PATCH 40/42] some tty per field rendering and optimization --- doc/fixes36.2 | 1 + win/tty/wintty.c | 77 +++++++++++++++++++++++++++--------------------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ca45e5826..35d75d637 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -17,6 +17,7 @@ Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository Platform- and/or Interface-Specific Fixes ----------------------------------------- windows-tty: Specify both width and height when creating font for width testing +tty: some optimizations for performance and per field rendering Code Cleanup and Reorganization diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 77835a5ec..b9ac757c0 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3650,6 +3650,8 @@ unsigned long *colormasks; int i; long *condptr = (long *) ptr; char *text = (char *) ptr; + char *lastchar = (char *) 0; + char *fval = (char *) 0; boolean do_color = FALSE; boolean force_update = FALSE; @@ -3672,15 +3674,6 @@ unsigned long *colormasks; tty_status[NOW][fldidx].dirty = TRUE; truncation_expected = FALSE; break; - case BL_CAP: - for (i = 0; i < SIZE(encvals); ++i) { - if (!strcmp(encvals[enc_shrinklvl][i], - status_vals[BL_CAP])) { - enclev = i; - break; - } - } - /*FALLTHRU*/ default: tty_status[NOW][fldidx].idx = fldidx; Sprintf(status_vals[fldidx], @@ -3692,16 +3685,9 @@ unsigned long *colormasks; tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); tty_status[NOW][fldidx].valid = TRUE; tty_status[NOW][fldidx].dirty = TRUE; - break; } - /* Special additional processing for hitpointbar */ - if (iflags.wc2_hitpointbar && fldidx == BL_HP) { - hpbar_percent = percent; - hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; - } - /* The core botl engine sends a single blank to the window port for carrying-capacity when its unused. Let's suppress that */ if (tty_status[NOW][fldidx].lth == 1 @@ -3710,24 +3696,49 @@ unsigned long *colormasks; tty_status[NOW][fldidx].lth = 0; } - /* The core botl engine sends trailing blanks for some fields - Let's suppress the trailing blanks */ - if (fldidx == BL_LEVELDESC || fldidx == BL_HUNGER) { - char *lastchar = eos(status_vals[fldidx]); - lastchar--; - while (lastchar && *lastchar == ' ' - && lastchar >= status_vals[fldidx]) { - *lastchar-- = '\0'; - tty_status[NOW][fldidx].lth--; - } + /* default processing above was required before these */ + switch (fldidx) { + case BL_HP: + if (iflags.wc2_hitpointbar) { + /* Special additional processing for hitpointbar */ + hpbar_percent = percent; + hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; + } + break; + case BL_LEVELDESC: + case BL_HUNGER: + /* The core sends trailing blanks for some fields + Let's suppress the trailing blanks */ + char *lastchar = eos(status_vals[fldidx]); + lastchar = eos(status_vals[fldidx]); + lastchar--; + while (lastchar && *lastchar == ' ' + && lastchar >= status_vals[fldidx]) { + *lastchar-- = '\0'; + tty_status[NOW][fldidx].lth--; + } + break; + case BL_TITLE: + if (iflags.wc2_hitpointbar) + tty_status[NOW][fldidx].lth += 2; /* '[' and ']' */ + break; + case BL_GOLD: + tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ + break; + case BL_CAP: + fval = status_vals[fldidx]; + if (fval) { + if (*fval == ' ') + fval++; + for (i = 0; i < SIZE(encvals); ++i) { + if (!strcmp(encvals[enc_shrinklvl][i], fval)) { + enclev = i; + break; /* for */ + } + } + } + break; } - - /* Some other special case fixups */ - if (iflags.wc2_hitpointbar && fldidx == BL_TITLE) - tty_status[NOW][fldidx].lth += 2; /* [ and ] */ - if (fldidx == BL_GOLD) - tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - if (make_things_fit(force_update) || truncation_expected) render_status(); return; From 26654ef0797db5ba68c4ffd5ac4c3b55a5ecfdd1 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 14 May 2018 22:25:25 -0400 Subject: [PATCH 41/42] a few cut-and-paste errors --- win/tty/wintty.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index b9ac757c0..b13318cc2 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3538,7 +3538,7 @@ static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ static boolean windowdata_init = FALSE; static int cond_shrinklvl = 0, cond_width_at_shrink = 0; static int enclev = 0, enc_shrinklvl = 0; -static dl_shrinklvl = 0; +static int dl_shrinklvl = 0; static boolean truncation_expected = FALSE; /* This controls whether to skip fields that aren't @@ -3709,7 +3709,6 @@ unsigned long *colormasks; case BL_HUNGER: /* The core sends trailing blanks for some fields Let's suppress the trailing blanks */ - char *lastchar = eos(status_vals[fldidx]); lastchar = eos(status_vals[fldidx]); lastchar--; while (lastchar && *lastchar == ' ' From aaddab5450a42efcf233e98e3837ca642471c34d Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 15 May 2018 01:10:32 -0400 Subject: [PATCH 42/42] catch up on fixes36.2 updates --- doc/fixes36.2 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 35d75d637..413e7f0f0 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -8,6 +8,9 @@ shift to the next major release. General Fixes and Modified Features ----------------------------------- last line of config file wasn't being heeded if it had no newline +list MSGTYPE values shows empty strings as reported in H7140 +Killing Vlad while he was in bat/fog cloud/wolf form gave poorly + worded feedback when he reverted to vampire form Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -16,7 +19,23 @@ Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository Platform- and/or Interface-Specific Fixes ----------------------------------------- +windows-gui: In nethackw, there could be conflicts between menu accelerators + and an extra choice accelerator to fix H7132. windows-tty: Specify both width and height when creating font for width testing +windows-tty: To counter lag problems that were occuring with the Win32 console + port, implement a console back buffer to reduce the number of calls made to + WriteConsoleOutputXXX +windows-tty: Additional changes to xputc_core() and early_raw_print() to manage + the cursor position correctly as that is needed to handle raw printing + correctly +windows-tty: Added check for when we might be running off the bottom of the + screen when handling msmsg() +windows-tty: Added runtime checks to keep cursor always within bounds +windows-tty: Fix memory leaks as reported in H5779 +windows-tty: Use nhraykey by default if the players keyboard layout is + non-english as reported in H4216 +windows-tty: We now support changing altkeyhandler in game +windows: Added ntassert() mechanism for Windows based port use tty: some optimizations for performance and per field rendering