Win32TTY: Fix using a console font with wide glyphs
Added support to detect when the current console font has glyphs that are too wide and will cause rendering errors in the console. If detected, we warn the user and change the code page to 437 and the font to Consolas. At exit, if we had changed the font and code page then we will restore to the original font and code page.
This commit is contained in:
committed by
Pasi Kallinen
parent
3d2e59ecec
commit
6322aec829
@@ -300,6 +300,8 @@ extern const struct symdef defsyms[MAXPCHARS]; /* defaults */
|
||||
extern const struct symdef def_warnsyms[WARNCOUNT];
|
||||
extern int currentgraphics; /* from drawing.c */
|
||||
extern nhsym showsyms[];
|
||||
extern nhsym l_syms[];
|
||||
extern nhsym r_syms[];
|
||||
|
||||
extern struct symsetentry symset[NUM_GRAPHICS]; /* from drawing.c */
|
||||
#define SYMHANDLING(ht) (symset[currentgraphics].handling == (ht))
|
||||
|
||||
@@ -5114,6 +5114,7 @@ boolean setinitial, setfromfile;
|
||||
assign_graphics(ROGUESET);
|
||||
} else if (!rogueflag)
|
||||
assign_graphics(PRIMARY);
|
||||
preference_update("symset");
|
||||
need_redraw = TRUE;
|
||||
return TRUE;
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ int FDECL(process_keystroke,
|
||||
(INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
|
||||
static void NDECL(init_ttycolor);
|
||||
static void NDECL(really_move_cursor);
|
||||
static void NDECL(check_and_set_font);
|
||||
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;
|
||||
@@ -54,6 +58,11 @@ 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;
|
||||
|
||||
@@ -148,6 +157,10 @@ KEYHANDLERNAME pKeyHandlerName;
|
||||
void
|
||||
gettty()
|
||||
{
|
||||
console_font_changed = FALSE;
|
||||
|
||||
check_and_set_font();
|
||||
|
||||
#ifndef TEXTCOLOR
|
||||
int k;
|
||||
#endif
|
||||
@@ -171,6 +184,8 @@ const char *s;
|
||||
end_screen();
|
||||
if (s)
|
||||
raw_print(s);
|
||||
|
||||
restore_original_console_font();
|
||||
}
|
||||
|
||||
/* called by init_nhwindows() and resume_nhwindows() */
|
||||
@@ -514,45 +529,47 @@ char ch;
|
||||
* Overrides wintty.c function of the same name
|
||||
* 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;
|
||||
{
|
||||
/* 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
|
||||
};
|
||||
boolean inverse = FALSE;
|
||||
unsigned char ch = (unsigned char) in_ch;
|
||||
|
||||
@@ -853,6 +870,8 @@ const char *pref;
|
||||
toggle_mouse_support();
|
||||
#endif
|
||||
}
|
||||
if (stricmp(pref, "symset") == 0)
|
||||
check_and_set_font();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1466,4 +1485,179 @@ GetConsoleHwnd(void)
|
||||
return hwndFound;
|
||||
}
|
||||
#endif /*CHANGE_COLOR*/
|
||||
|
||||
static int CALLBACK EnumFontCallback(
|
||||
const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
|
||||
{
|
||||
LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
|
||||
*lf_ptr = *lf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check_and_set_font ensures that the current font will render the symbols
|
||||
* that are currently being used correctly. If they will not be rendered
|
||||
* correctly, then it will change the font to a known good font.
|
||||
*/
|
||||
void
|
||||
check_and_set_font()
|
||||
{
|
||||
if (!check_font_widths()) {
|
||||
raw_print("WARNING: glyphs too wide in console font."
|
||||
" Changing code page to 437 and font to Consolas\n");
|
||||
set_known_good_console_font();
|
||||
}
|
||||
}
|
||||
|
||||
/* check_font_widths returns TRUE if all glyphs in current console font
|
||||
* fit within the width of a single console cell.
|
||||
*/
|
||||
boolean
|
||||
check_font_widths()
|
||||
{
|
||||
CONSOLE_FONT_INFOEX console_font_info;
|
||||
console_font_info.cbSize = sizeof(console_font_info);
|
||||
BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
|
||||
&console_font_info);
|
||||
|
||||
/* get console window and DC
|
||||
* NOTE: the DC from the console window does not have the correct
|
||||
* font selected at this point.
|
||||
*/
|
||||
HWND hWnd = GetConsoleWindow();
|
||||
HDC hDC = GetDC(hWnd);
|
||||
|
||||
LOGFONTW logical_font;
|
||||
logical_font.lfCharSet = DEFAULT_CHARSET;
|
||||
wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
|
||||
logical_font.lfPitchAndFamily = 0;
|
||||
|
||||
/* getting matching console font */
|
||||
LOGFONTW matching_log_font = { 0 };
|
||||
EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
|
||||
(LPARAM) &matching_log_font, 0);
|
||||
|
||||
if (matching_log_font.lfHeight == 0) {
|
||||
raw_print("Unable to enumerate system fonts\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* create font matching console font */
|
||||
LOGFONTW console_font_log_font = matching_log_font;
|
||||
console_font_log_font.lfWeight = console_font_info.FontWeight;
|
||||
console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
|
||||
console_font_log_font.lfWidth = 0;
|
||||
HFONT console_font = CreateFontIndirectW(&console_font_log_font);
|
||||
|
||||
if (console_font == NULL) {
|
||||
raw_print("Unable to create console font\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* select font */
|
||||
HGDIOBJ saved_font = SelectObject(hDC, console_font);
|
||||
|
||||
/* determine whether it is a true type font */
|
||||
TEXTMETRICA tm;
|
||||
success = GetTextMetricsA(hDC, &tm);
|
||||
|
||||
if (!success) {
|
||||
raw_print("Unable to get console font text metrics\n");
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
|
||||
|
||||
/* determine which glyphs are used */
|
||||
boolean used[256];
|
||||
memset(used, 0, sizeof(used));
|
||||
for (int i = 0; i < SYM_MAX; i++) {
|
||||
used[l_syms[i]] = TRUE;
|
||||
used[r_syms[i]] = TRUE;
|
||||
}
|
||||
|
||||
int wcUsedCount = 0;
|
||||
wchar_t wcUsed[256];
|
||||
for (int i = 0; i < sizeof(used); i++)
|
||||
if (used[i])
|
||||
wcUsed[wcUsedCount++] = cp437[i];
|
||||
|
||||
/* measure the set of used glyphs to ensure they fit */
|
||||
boolean all_glyphs_fit = TRUE;
|
||||
|
||||
for (int i = 0; i < wcUsedCount; i++) {
|
||||
int width;
|
||||
if (isTrueType) {
|
||||
ABC abc;
|
||||
success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
|
||||
width = abc.abcA + abc.abcB + abc.abcC;
|
||||
} else {
|
||||
success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
|
||||
}
|
||||
|
||||
if (success && width > console_font_info.dwFontSize.X) {
|
||||
all_glyphs_fit = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clean_up:
|
||||
|
||||
SelectObject(hDC, saved_font);
|
||||
DeleteObject(console_font);
|
||||
|
||||
return all_glyphs_fit;
|
||||
}
|
||||
|
||||
/* set_known_good_console_font sets the code page and font used by the console
|
||||
* to settings know to work well with NetHack. It also saves the original
|
||||
* settings so that they can be restored prior to NetHack exit.
|
||||
*/
|
||||
void
|
||||
set_known_good_console_font()
|
||||
{
|
||||
CONSOLE_FONT_INFOEX console_font_info;
|
||||
console_font_info.cbSize = sizeof(console_font_info);
|
||||
BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
|
||||
&console_font_info);
|
||||
|
||||
console_font_changed = TRUE;
|
||||
original_console_font_info = console_font_info;
|
||||
original_console_code_page = GetConsoleOutputCP();
|
||||
|
||||
wcscpy_s(console_font_info.FaceName,
|
||||
sizeof(console_font_info.FaceName)
|
||||
/ sizeof(console_font_info.FaceName[0]),
|
||||
L"Consolas");
|
||||
|
||||
success = SetConsoleOutputCP(437);
|
||||
if (!success)
|
||||
raw_print("Unable to set console code page to 437\n");
|
||||
|
||||
success = SetCurrentConsoleFontEx(hConOut, FALSE, &console_font_info);
|
||||
if (!success)
|
||||
raw_print("Unable to set console font to Consolas\n");
|
||||
}
|
||||
|
||||
/* restore_original_console_font will restore the console font and code page
|
||||
* settings to what they were when NetHack was launched.
|
||||
*/
|
||||
void
|
||||
restore_original_console_font()
|
||||
{
|
||||
if (console_font_changed) {
|
||||
BOOL success;
|
||||
raw_print("Restoring original font and code page\n");
|
||||
success = SetConsoleOutputCP(original_console_code_page);
|
||||
if (!success)
|
||||
raw_print("Unable to restore original code page\n");
|
||||
|
||||
success = SetCurrentConsoleFontEx(hConOut, FALSE,
|
||||
&original_console_font_info);
|
||||
if (!success)
|
||||
raw_print("Unable to restore original font\n");
|
||||
|
||||
console_font_changed = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
Reference in New Issue
Block a user