stdscr.move(2, 0)
stdscr.echochar(v)
self.assertEqual(self._read_char(2, 0), c)
- # insch() round-trips a byte only where its code point equals
- # the byte value (Latin-1): on a wide build ncurses winsch
- # stores a printable byte directly as a code point instead of
- # decoding it through the locale.
- if ord(c) < 0x100:
- stdscr.insch(1, 0, v)
- self.assertEqual(self._read_char(1, 0), c)
+ # insch() decodes the byte through the locale like addch(), so
+ # it round-trips the same character.
+ stdscr.insch(1, 0, v)
+ self.assertEqual(self._read_char(1, 0), c)
# The same characters supplied as a str. Unlike the int path above, a
# str is stored as a wide-character cell on a wide build, so every
--- /dev/null
+On a wide :mod:`curses` build, :meth:`curses.window.insch` now inserts a
+non-ASCII byte as the character it encodes in the window's encoding,
+consistently with :meth:`~curses.window.addch`, instead of its code point.
if (type == 0) {
return NULL;
}
+ if (type == 1) {
+ /* winsch() does not locale-decode a byte above 127 on a wide build,
+ unlike waddch(), so decode it here and insert it as a wide
+ character. (gh-153864) */
+ chtype cch = ch_ & A_CHARTEXT;
+ if (cch > 127) {
+ wint_t wc = btowc((int)cch);
+ if (wc != WEOF) {
+ wchar_t wstr[2] = { (wchar_t)wc, L'\0' };
+ attr_t cattr = (attr_t)((ch_ | attr) & ~(chtype)A_CHARTEXT);
+ if (curses_setcchar(&wch, wstr, cattr, PAIR_NUMBER(cattr)) == ERR) {
+ curses_window_set_error(self, "setcchar", "insch");
+ return NULL;
+ }
+ type = 2;
+ }
+ }
+ }
if (type == 2) {
if (!group_left_1) {
rtn = wins_wch(self->win, &wch);