diff --git a/Doc/library/curses.rst b/Doc/library/curses.rst index 853ff6ab7332a6..ca6b12ec5d61e4 100644 --- a/Doc/library/curses.rst +++ b/Doc/library/curses.rst @@ -1084,6 +1084,9 @@ Window objects and the color pair with :func:`pair_number`. The character byte is the locale-encoded byte of the cell's character, consistent with :meth:`instr`. + On a wide-character build, a character that does not fit in a single byte + in the current locale has a character byte of ``0``; + use :meth:`instr` to read such characters. .. method:: window.insch(ch[, attr]) diff --git a/Lib/test/test_curses.py b/Lib/test/test_curses.py index a75789cdda7b46..80c3c564dc6271 100644 --- a/Lib/test/test_curses.py +++ b/Lib/test/test_curses.py @@ -517,7 +517,7 @@ def test_read_from_window(self): with self.subTest(ch=ch): stdscr.addstr(2, 0, ch) self.assertEqual(stdscr.instr(2, 0, 1), b) - self.assertEqual(stdscr.inch(2, 0) & curses.A_CHARTEXT, b[0]) + self.assertEqual(stdscr.inch(2, 0), b[0]) def test_coordinate_errors(self): # Addressing a cell outside the window raises curses.error. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 12641b51c1e90d..2f8f7d64bd60b9 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -1903,10 +1903,10 @@ _curses_window_insch_impl(PyCursesWindowObject *self, int group_left_1, } #ifdef HAVE_NCURSESW -/* winch() returns the low 8 bits of the character's code point with no locale - conversion, unlike instr(), so recover the locale byte from the wide cell - when the character maps to exactly one byte, keeping the attribute and color - bits in RTN. A character with no single-byte form is left to winch(). */ +/* ncursesw's winch() returns the character's whole code point instead of its + locale byte, overflowing the chtype's 8-bit character field into the color + and attribute bits, so rebuild the value from the locale byte plus the + attributes and color pair reported by getcchar(). */ static chtype curses_cell_locale_byte(chtype rtn, const cchar_t *cell) { @@ -1915,18 +1915,19 @@ curses_cell_locale_byte(chtype rtn, const cchar_t *cell) short pair; /* getcchar() is not guaranteed to write the text of an empty cell. */ wstr[0] = L'\0'; - if (getcchar(cell, wstr, &attrs, &pair, NULL) == ERR - || wstr[0] == L'\0' || wstr[1] != L'\0') - { + if (getcchar(cell, wstr, &attrs, &pair, NULL) == ERR) { return rtn; } /* wctob() mirrors ncurses' own _nc_to_char(): the single-byte form, or EOF - when the character has none in this locale. */ - int byte = wctob(wstr[0]); - if (byte != EOF) { - rtn = (rtn & ~(chtype)A_CHARTEXT) | (unsigned char)byte; + when the character has none in this locale (then use 0). */ + int byte = 0; + if (wstr[0] != L'\0' && wstr[1] == L'\0') { + byte = wctob(wstr[0]); + if (byte == EOF) { + byte = 0; + } } - return rtn; + return (chtype)byte | (attrs & ~(attr_t)A_COLOR) | COLOR_PAIR(pair); } #endif