From 426ef4d8d20b9daed47be5ed6ee42b43af40664c Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 16 Oct 2022 21:42:18 -0400 Subject: [PATCH 1/4] Add Unicode support to the map --- sys/windows/windsys.c | 22 ++++++++++++--- sys/windows/winos.h | 4 +-- win/win32/mhmap.c | 63 ++++++++++++++++++++++++++++++------------- win/win32/mswproc.c | 3 +++ 4 files changed, 69 insertions(+), 23 deletions(-) diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index af51e9c5b..42115121c 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -543,10 +543,26 @@ winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength return dst; } -WCHAR -winos_ascii_to_wide(const unsigned char c) +void +winos_ascii_to_wide(WCHAR dst[3], UINT32 c) { - return cp437[c]; +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + if (c <= 0xFFFF) { + dst[0] = (WCHAR) c; + dst[1] = L'\0'; + } else { + /* UTF-16 surrogate pair */ + dst[0] = (WCHAR) ((c >> 10) + 0xD7C0); + dst[1] = (WCHAR) ((c & 0x3FF) + 0xDC00); + dst[2] = L'\0'; + } + } else +#endif + { + dst[0] = cp437[c]; + dst[1] = L'\0'; + } } BOOL winos_font_support_cp437(HFONT hFont) diff --git a/sys/windows/winos.h b/sys/windows/winos.h index 55300bda0..132b153e0 100644 --- a/sys/windows/winos.h +++ b/sys/windows/winos.h @@ -12,8 +12,8 @@ extern const WCHAR cp437[256]; WCHAR * winos_ascii_to_wide_str(const unsigned char * src, WCHAR * dst, size_t dstLength); -WCHAR -winos_ascii_to_wide(const unsigned char c); +void +winos_ascii_to_wide(WCHAR dst[3], UINT32 c); BOOL winos_font_support_cp437(HFONT hFont); diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 1212395cb..723a0f7ce 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -49,6 +49,7 @@ typedef struct mswin_nethack_map_window { POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ + HFONT hMapFontUnicode; /* font for Unicode mode */ boolean bUnicodeFont; /* font supports unicode page 437 */ int tileWidth; /* width of tile in pixels at 96 dpi */ @@ -252,6 +253,12 @@ mswin_map_layout(HWND hWnd, LPSIZE map_size) data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); + // Same as above, but with ANSI_CHARSET for IBM and Unicode modes + lgfnt.lfCharSet = ANSI_CHARSET; + if (data->hMapFontUnicode) + DeleteObject(data->hMapFontUnicode); + data->hMapFontUnicode = CreateFontIndirect(&lgfnt); + // set tile size to match font metrics data->xBackTile = textMetrics.tmAveCharWidth; @@ -626,6 +633,8 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); + if (data->hMapFontUnicode) + DeleteObject(data->hMapFontUnicode); if (data->hBackBuffer) DeleteBitmap(data->hBackBuffer); if (data->backBufferDC) @@ -911,9 +920,11 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) { if (data->map[i][j].glyph >= 0) { - char ch; - WCHAR wch; + glyph_info *glyphinfo; + uint32 ch; + WCHAR wch[3]; int color; + uint32 rgbcolor; // unsigned special; // int mgch; HBRUSH back_brush; @@ -925,12 +936,23 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) FillRect(data->backBufferDC, rect, blackBrush); DeleteObject(blackBrush); - #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) - nhglyph2charcolor(data->map[i][j], &ch, &color); - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); - #else - ch = (char) data->map[i][j].ttychar; - color = (int) data->map[i][j].gm.sym.color; + glyphinfo = &data->map[i][j]; + ch = glyphinfo->ttychar; + color = (int) glyphinfo->gm.sym.color; + rgbcolor = nhcolor_to_RGB(color); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8) + && glyphinfo->gm.u + && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; + if (glyphinfo->gm.u->ucolor != 0) { + rgbcolor = RGB( + (glyphinfo->gm.u->ucolor >> 16) & 0xFF, + (glyphinfo->gm.u->ucolor >> 8) & 0xFF, + (glyphinfo->gm.u->ucolor >> 0) & 0xFF); + } + } +#endif if (((data->map[i][j].gm.glyphflags & MG_PET) && iflags.hilite_pet) || ((data->map[i][j].gm.glyphflags & (MG_DETECT | MG_BW_LAVA)) && iflags.use_inverse)) { @@ -946,21 +968,23 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) break; default: OldFg = - SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + SetTextColor(data->backBufferDC, rgbcolor); } } else { - OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + OldFg = SetTextColor(data->backBufferDC, rgbcolor); } - #endif - if (data->bUnicodeFont) { - wch = winos_ascii_to_wide(ch); - if (wch == 0x2591 || wch == 0x2592) { + if (data->bUnicodeFont || SYMHANDLING(H_UTF8)) { + winos_ascii_to_wide(wch, ch); + if (wch[0] == 0x2591 || wch[0] == 0x2592) { int intensity = 80; HBRUSH brush = CreateSolidBrush(RGB(intensity, intensity, intensity)); FillRect(data->backBufferDC, rect, brush); DeleteObject(brush); - intensity = (wch == 0x2591 ? 100 : 200); - brush = CreateSolidBrush(RGB(intensity, intensity, intensity)); + intensity = (wch[0] == 0x2591 ? 1 : 2); + brush = CreateSolidBrush(RGB( + GetRValue(rgbcolor)*intensity/2, + GetGValue(rgbcolor)*intensity/2, + GetBValue(rgbcolor)*intensity/2)); RECT smallRect = {0}; smallRect.left = rect->left + 1; smallRect.top = rect->top + 1; @@ -969,12 +993,15 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) FillRect(data->backBufferDC, &smallRect, brush); DeleteObject(brush); } else { - DrawTextW(data->backBufferDC, &wch, 1, rect, + SelectObject(data->backBufferDC, data->hMapFontUnicode); + DrawTextW(data->backBufferDC, wch, -1, rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } } else { - DrawTextA(data->backBufferDC, &ch, 1, rect, + char ch8 = (char) ch; + SelectObject(data->backBufferDC, data->hMapFont); + DrawTextA(data->backBufferDC, &ch8, 1, rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_SINGLELINE); } diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 0b409ab06..efc655f12 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -90,6 +90,9 @@ struct window_procs mswin_procs = { | WC_SPLASH_SCREEN | WC_POPUP_DIALOG | WC_MOUSE_SUPPORT, #ifdef STATUS_HILITES WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS | +#endif +#ifdef ENHANCED_SYMBOLS + WC2_U_UTF8STR | WC2_U_24BITCOLOR | #endif 0L, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ From c5674fd10c42645a2af0755abc315b1977cd7a8a Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 16 Oct 2022 21:42:42 -0400 Subject: [PATCH 2/4] Fix crashes when copying to clipboard --- win/win32/mhstatus.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 0660af8a7..77e0b6900 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -199,15 +199,17 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) size_t space_remaining = msg_data->max_size; for (int line = 0; line < NHSW_LINES; line++) { - mswin_status_line *status_line = data->status_lines[line].lines; + mswin_status_line *status_line = &data->status_lines->lines[line]; for (int i = 0; i < status_line->status_strings.count; i++) { mswin_status_string * status_string = status_line->status_strings.status_strings[i]; - if (status_string->space_in_front) { - strncat(msg_data->buffer, " ", space_remaining); + if (status_string->str != NULL) { + if (status_string->space_in_front) { + strncat(msg_data->buffer, " ", space_remaining); + space_remaining = msg_data->max_size - strlen(msg_data->buffer); + } + strncat(msg_data->buffer, status_string->str, space_remaining); space_remaining = msg_data->max_size - strlen(msg_data->buffer); } - strncat(msg_data->buffer, status_string->str, space_remaining); - space_remaining = msg_data->max_size - strlen(msg_data->buffer); } strncat(msg_data->buffer, "\r\n", space_remaining); space_remaining = msg_data->max_size - strlen(msg_data->buffer); From f7aa79f9391fb8f5f4eecca80df583eb51ff4737 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 16 Oct 2022 22:32:11 -0400 Subject: [PATCH 3/4] Copy Unicode to the clipboard --- win/win32/mhmain.c | 120 ++++++++++++++++++++++++++++++++++++++++----- win/win32/mhmap.c | 30 ++++++++++++ win/win32/mhmsg.h | 10 ++++ 3 files changed, 147 insertions(+), 13 deletions(-) diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index e11dd33d0..f10e953ed 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -35,8 +35,11 @@ static void register_main_window_class(void); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); static void nhlock_windows(BOOL lock); -static char *nh_compose_ascii_screenshot(); -static void mswin_apply_window_style_all(); +static char *nh_compose_ascii_screenshot(void); +#ifdef ENHANCED_SYMBOLS +static WCHAR *nh_compose_unicode_screenshot(void); +#endif +static void mswin_apply_window_style_all(void); // returns strdup() created pointer - callee assumes the ownership HWND @@ -871,42 +874,79 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) break; case IDM_SETTING_SCREEN_TO_CLIPBOARD: { - char *p; + char *p = NULL; +#ifdef ENHANCED_SYMBOLS + WCHAR *wp = NULL; +#endif + unsigned chr_size = 1; size_t len; HANDLE hglbCopy; - char *p_copy; - p = nh_compose_ascii_screenshot(); - if (!p) - return 0; - len = strlen(p); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + wp = nh_compose_unicode_screenshot(); + if (!wp) + return 0; + len = wcslen(wp); + chr_size = sizeof(WCHAR); + } else +#endif + { + p = nh_compose_ascii_screenshot(); + if (!p) + return 0; + len = strlen(p); + } if (!OpenClipboard(hWnd)) { NHMessageBox(hWnd, TEXT("Cannot open clipboard"), MB_OK | MB_ICONERROR); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif return 0; } EmptyClipboard(); - hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(char)); + hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * chr_size); if (hglbCopy == NULL) { CloseClipboard(); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif return FALSE; } - p_copy = (char *) GlobalLock(hglbCopy); - strncpy(p_copy, p, len); - p_copy[len] = 0; // null character +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + WCHAR *p_copy = (WCHAR *) GlobalLock(hglbCopy); + wcsncpy(p_copy, wp, len); + p_copy[len] = 0; // null character + } else +#endif + { + char *p_copy = (char *) GlobalLock(hglbCopy); + strncpy(p_copy, p, len); + p_copy[len] = 0; // null character + } GlobalUnlock(hglbCopy); - SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy); +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) + SetClipboardData(CF_UNICODETEXT, hglbCopy); + else +#endif + SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy); CloseClipboard(); free(p); +#ifdef ENHANCED_SYMBOLS + free(wp); +#endif } break; case IDM_SETTING_SCREEN_TO_FILE: { @@ -1276,3 +1316,57 @@ nh_compose_ascii_screenshot(void) free(text); return retval; } + +#ifdef ENHANCED_SYMBOLS +// returns malloc() created pointer - callee assumes the ownership +static WCHAR * +nh_compose_unicode_screenshot(void) +{ + WCHAR *retval; + PMSNHMsgGetText text; + PMSNHMsgGetWideText wtext; + size_t retsize; + const size_t max_size = 3 * TEXT_BUFFER_SIZE; + + retval = (WCHAR *) malloc(max_size * sizeof(WCHAR)); + retsize = 0; + + text = + (PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE); + text->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ + + wtext = + (PMSNHMsgGetWideText) malloc(sizeof(MSNHMsgGetWideText) + + TEXT_BUFFER_SIZE * sizeof(WCHAR)); + wtext->max_size = + TEXT_BUFFER_SIZE + - 1; /* make sure we always have 0 at the end of the buffer */ + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + retsize += MultiByteToWideChar(CP_ACP, 0, + text->buffer, strlen(text->buffer), + retval + retsize, max_size - retsize); + + ZeroMemory(wtext->buffer, TEXT_BUFFER_SIZE * sizeof(WCHAR)); + SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETWIDETEXT, (LPARAM) wtext); + wcsncpy(retval + retsize, wtext->buffer, max_size - retsize - 1); + retsize += wcslen(retval + retsize); + + ZeroMemory(text->buffer, TEXT_BUFFER_SIZE); + SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, + (WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text); + retsize += MultiByteToWideChar(CP_ACP, 0, + text->buffer, strlen(text->buffer), + retval + retsize, max_size - retsize); + retval[retsize] = L'\0'; + + free(text); + free(wtext); + return retval; +} +#endif diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 723a0f7ce..bee0b8282 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -765,6 +765,36 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } break; +#ifdef ENHANCED_SYMBOLS + case MSNH_MSG_GETWIDETEXT: { + PMSNHMsgGetWideText msg_data = (PMSNHMsgGetWideText) lParam; + size_t index; + int col, row; + + index = 0; + for (row = 0; row < ROWNO; row++) { + for (col = 0; col < COLNO; col++) { + glyph_info *glyphinfo; + uint32 ch; + if (index >= msg_data->max_size) + break; + glyphinfo = &data->map[col][row]; + if (glyphinfo->gm.u && glyphinfo->gm.u->utf8str) { + ch = glyphinfo->gm.u->utf32ch; + } else { + ch = glyphinfo->ttychar; + } + winos_ascii_to_wide(msg_data->buffer + index, ch); + index += wcslen(msg_data->buffer + index); + } + if (index >= msg_data->max_size - 1) + break; + msg_data->buffer[index++] = '\r'; + msg_data->buffer[index++] = '\n'; + } + } break; +#endif + case MSNH_MSG_RANDOM_INPUT: nhassert(0); // unexpected break; diff --git a/win/win32/mhmsg.h b/win/win32/mhmsg.h index 9ccd1bd2d..90413e0cc 100644 --- a/win/win32/mhmsg.h +++ b/win/win32/mhmsg.h @@ -22,6 +22,9 @@ #define MSNH_MSG_GETTEXT 111 #define MSNH_MSG_UPDATE_STATUS 112 #define MSNH_MSG_RANDOM_INPUT 113 +#ifdef ENHANCED_SYMBOLS +#define MSNH_MSG_GETWIDETEXT 114 +#endif typedef struct mswin_nhmsg_add_wnd { winid wid; @@ -71,6 +74,13 @@ typedef struct mswin_nhmsg_get_text { char buffer[TEXT_BUFFER_SIZE]; } MSNHMsgGetText, *PMSNHMsgGetText; +#ifdef ENHANCED_SYMBOLS +typedef struct mswin_nhmsg_get_wide_text { + size_t max_size; + WCHAR buffer[TEXT_BUFFER_SIZE]; +} MSNHMsgGetWideText, *PMSNHMsgGetWideText; +#endif + typedef struct mswin_nhmsg_update_status { struct mswin_status_lines * status_lines; } MSNHMsgUpdateStatus, *PMSNHMsgUpdateStatus; From c801f3ce00b7d435416c725a8ac8afb8e0252270 Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 16 Oct 2022 22:57:28 -0400 Subject: [PATCH 4/4] Write Unicode to text save file --- win/win32/mhmain.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index f10e953ed..a53646a0d 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -988,9 +988,26 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) if (!GetSaveFileName(&ofn)) return FALSE; - text = nh_compose_ascii_screenshot(); - if (!text) - return FALSE; +#ifdef ENHANCED_SYMBOLS + if (SYMHANDLING(H_UTF8)) { + text = NULL; + wtext = nh_compose_unicode_screenshot(); + if (!wtext) + return FALSE; + tlen = wcslen(wtext); + } else +#endif + { + text = nh_compose_ascii_screenshot(); + if (!text) + return FALSE; + + tlen = strlen(text); + wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t)); + if (!wtext) + panic("out of memory"); + MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen); + } pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8")); if (!pFile) { @@ -998,14 +1015,10 @@ onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) _stprintf(buf, TEXT("Cannot open %s for writing!"), filename); NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR); free(text); + free(wtext); return FALSE; } - tlen = strlen(text); - wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t)); - if (!wtext) - panic("out of memory"); - MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen); fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile); fclose(pFile); free(text);