--- a/ncurses/curses.priv.h +++ b/ncurses/curses.priv.h @@ -2294,7 +2294,10 @@ #if defined(_NC_WINDOWS_NATIVE) && !defined(_NC_MSC) && !USE_NAMED_PIPES /* * MinGW has wide-character functions, but they do not work correctly. + * Declare the originals first so a later is not macro-expanded. */ +#include +#include extern int __MINGW_NOTHROW _nc_wctomb(char *, wchar_t); #define wctomb(s,wc) _nc_wctomb(s,wc) #define wcrtomb(s,wc,n) _nc_wctomb(s,wc) --- a/ncurses/tinfo/lib_win32con.c +++ b/ncurses/tinfo/lib_win32con.c @@ -653,6 +653,21 @@ return result; } +/* Whether handle_mouse() turns this record into an event: wheel, a button + * change (press or release), or a drag. */ +static bool +mouse_wanted(const SCREEN *sp, const MOUSE_EVENT_RECORD *mer) +{ + int held = (int) (mer->dwButtonState & BUTTON_MASK); + + if (mer->dwEventFlags & MOUSE_WHEELED) + return TRUE; + if (held != sp->_drv_mouse_new_buttons) + return TRUE; + return (mer->dwEventFlags & MOUSE_MOVED) && held + && (sp->_mouse_mask & REPORT_MOUSE_POSITION); +} + #define AdjustY() (WINCONSOLE.buffered \ ? 0 \ : (int) WINCONSOLE.SBI.srWindow.Top) @@ -661,36 +676,47 @@ handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer) { MEVENT work; - bool result = FALSE; + int old_buttons; + int new_buttons; assert(sp); - sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons; - sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK; + if (sp->_drv_mouse_tail >= FIFO_SIZE) + return FALSE; - /* - * We're only interested if the button is pressed or released. - * FIXME: implement continuous event-tracking. - */ - if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) { - memset(&work, 0, sizeof(work)); + memset(&work, 0, sizeof(work)); + work.x = mer.dwMousePosition.X; + work.y = mer.dwMousePosition.Y - AdjustY(); + + /* the wheel reports like xterm: button 4 up, button 5 down */ + if (mer.dwEventFlags & MOUSE_WHEELED) { + work.bstate = ((SHORT) HIWORD(mer.dwButtonState) > 0) + ? BUTTON4_PRESSED + : BUTTON5_PRESSED; + sp->_drv_mouse_fifo[sp->_drv_mouse_tail++] = work; + return TRUE; + } - if (sp->_drv_mouse_new_buttons) { - work.bstate |= decode_mouse(sp, sp->_drv_mouse_new_buttons); + old_buttons = sp->_drv_mouse_new_buttons; + new_buttons = (int) (mer.dwButtonState & BUTTON_MASK); + sp->_drv_mouse_old_buttons = old_buttons; + sp->_drv_mouse_new_buttons = new_buttons; + + if (new_buttons != old_buttons) { + if (new_buttons & ~old_buttons) { + work.bstate = decode_mouse(sp, new_buttons & ~old_buttons); } else { /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ - work.bstate |= (decode_mouse(sp, sp->_drv_mouse_old_buttons) - >> 1); - result = TRUE; + work.bstate = decode_mouse(sp, old_buttons & ~new_buttons) >> 1; } - - work.x = mer.dwMousePosition.X; - work.y = mer.dwMousePosition.Y - AdjustY(); - - sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work; - sp->_drv_mouse_tail += 1; + } else if ((mer.dwEventFlags & MOUSE_MOVED) && new_buttons + && (sp->_mouse_mask & REPORT_MOUSE_POSITION)) { + work.bstate = REPORT_MOUSE_POSITION; /* drag */ + } else { + return FALSE; } - return result; + sp->_drv_mouse_fifo[sp->_drv_mouse_tail++] = work; + return TRUE; } static int @@ -813,6 +839,13 @@ returnCode(found); } +#if USE_WIDEC_SUPPORT +/* UTF-8 bytes of the last non-ASCII key event not yet read */ +static int utf8_pend[4]; +static int utf8_len, utf8_pos; +static unsigned utf8_high; +#endif + NCURSES_EXPORT(int) _nc_console_twait( const SCREEN *sp, @@ -845,6 +878,14 @@ TR(TRACE_IEVENT, ("start twait: hdl=%p, %d milliseconds, mode: %d", hdl, milliseconds, mode)); +#if USE_WIDEC_SUPPORT + if ((mode & TW_INPUT) && utf8_pos < utf8_len) { + if (timeleft) + *timeleft = milliseconds; + return TW_INPUT; + } +#endif + if (milliseconds < 0) milliseconds = NC_INFINITY; @@ -940,9 +981,7 @@ continue; case MOUSE_EVENT: T(("twait:event MOUSE_EVENT")); - if (decode_mouse(sp, - (inp_rec.Event.MouseEvent.dwButtonState - & BUTTON_MASK)) == 0) { + if (!mouse_wanted(sp, &inp_rec.Event.MouseEvent)) { CONSUME(); } else if (mode & TW_MOUSE) { code = TW_MOUSE; @@ -1024,6 +1063,16 @@ T((T_CALLED("lib_win32con::_nc_console_read(%p)"), sp)); +#if USE_WIDEC_SUPPORT + /* wget_wch() decodes the input as a byte stream in the locale's + * multibyte encoding (UTF-8), so non-ASCII UTF-16 key events are + * handed over one UTF-8 byte per call. */ + if (utf8_pos < utf8_len) { + *buf = utf8_pend[utf8_pos++]; + returnCode(1); + } +#endif + while ((b = read_keycode(hdl, &inp_rec, 1, &nRead))) { if (b && nRead > 0) { if (rc < 0) @@ -1034,6 +1083,36 @@ continue; *buf = (int) inp_rec.Event.KeyEventChar; vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; +#if USE_WIDEC_SUPPORT + if (*buf >= 0x80) { + unsigned cp = (unsigned) *buf; + if (cp >= 0xD800 && cp < 0xDC00) { + utf8_high = cp; + continue; + } + if (cp >= 0xDC00 && cp < 0xE000) { + if (!utf8_high) + continue; + cp = 0x10000 + ((utf8_high - 0xD800) << 10) + (cp - 0xDC00); + } + utf8_high = 0; + utf8_len = 0; + if (cp < 0x800) { + utf8_pend[utf8_len++] = (int) (0xC0 | (cp >> 6)); + } else if (cp < 0x10000) { + utf8_pend[utf8_len++] = (int) (0xE0 | (cp >> 12)); + utf8_pend[utf8_len++] = (int) (0x80 | ((cp >> 6) & 0x3F)); + } else { + utf8_pend[utf8_len++] = (int) (0xF0 | (cp >> 18)); + utf8_pend[utf8_len++] = (int) (0x80 | ((cp >> 12) & 0x3F)); + utf8_pend[utf8_len++] = (int) (0x80 | ((cp >> 6) & 0x3F)); + } + utf8_pend[utf8_len++] = (int) (0x80 | (cp & 0x3F)); + *buf = utf8_pend[0]; + utf8_pos = 1; + break; + } +#endif /* * There are 24 virtual function-keys, and typically * 12 function-keys on a keyboard. Use the shift-modifier --- a/ncurses/widechar/widechars.c +++ b/ncurses/widechar/widechars.c @@ -97,20 +97,10 @@ wchar_t temp; if (s != NULL && n != 0) { + /* _nc_mbtowc() returns the bytes used, not a character count */ count = _nc_mbtowc(&temp, s, n); - if (count == 1) { - int check = WideCharToMultiByte(CP_UTF8, - 0, - &temp, - 1, - NULL, - 0, /* compute length only */ - NULL, - NULL); - TR(TRACE_BITS, ("\tcheck ->%d\n", check)); - if (check > 0 && (size_t) check <= n) { - result = check; - } + if (count > 0 && (size_t) count <= n) { + result = count; } } else { result = 0; --- a/ncurses/win32con/win32_driver.c +++ b/ncurses/win32con/win32_driver.c @@ -87,8 +87,13 @@ if (ch & A_BOLD) res |= FOREGROUND_INTENSITY; - if (ch & A_DIM) - res |= BACKGROUND_INTENSITY; + /* dim lowers the foreground: bright -> normal, light gray -> dark gray */ + if ((ch & A_DIM) && !(ch & A_BOLD)) { + if (res & FOREGROUND_INTENSITY) + res &= ~FOREGROUND_INTENSITY; + else if ((res & 7) == 7) + res = (res & ~7) | FOREGROUND_INTENSITY; + } return res; } @@ -159,7 +164,6 @@ int y, int x, cchar_t *str, int limit) { int actual = 0; - MakeArray(ci, CHAR_INFO, limit); COORD loc, siz; SMALL_RECT rec; int i; @@ -169,39 +173,71 @@ AssertTCB(); SetSP(); - for (i = actual = 0; i < limit; i++) { - ch = str[i]; - if (isWidecExt(ch)) - continue; - ci[actual].CharInfoChar = CharOf(ch); - ci[actual].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes, - AttrOf(ch)); - if (AttrOf(ch) & A_ALTCHARSET) { - if (_nc_wacs) { - int which = CharOf(ch); - if (which > 0 - && which < ACS_LEN - && CharOf(_nc_wacs[which]) != 0) { - ci[actual].CharInfoChar = CharOf(_nc_wacs[which]); + /* + * The console stores a double-width character as two cells flagged + * leading/trailing byte. Never start or end a write inside one, and + * emit both halves so the columns after it stay put. + */ + if (limit > 0 && x > 0 && isWidecExt(str[0])) { + --str; + --x; + ++limit; + } + if (limit > 0 && x + limit < screen_columns(sp) && isWidecExt(str[limit])) + ++limit; + + { + MakeArray(ci, CHAR_INFO, limit); + + for (i = actual = 0; i < limit; i++) { + ch = str[i]; + if (isWidecExt(ch)) { + if (actual > 0 + && (ci[actual - 1].Attributes & COMMON_LVB_LEADING_BYTE)) { + ci[actual] = ci[actual - 1]; + ci[actual].Attributes = (WORD) + ((ci[actual].Attributes & ~COMMON_LVB_LEADING_BYTE) + | COMMON_LVB_TRAILING_BYTE); } else { ci[actual].CharInfoChar = ' '; + ci[actual].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes, + AttrOf(ch)); } + ++actual; + continue; } + ci[actual].CharInfoChar = CharOf(ch); + ci[actual].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes, + AttrOf(ch)); + if (AttrOf(ch) & A_ALTCHARSET) { + if (_nc_wacs) { + int which = CharOf(ch); + if (which > 0 + && which < ACS_LEN + && CharOf(_nc_wacs[which]) != 0) { + ci[actual].CharInfoChar = CharOf(_nc_wacs[which]); + } else { + ci[actual].CharInfoChar = ' '; + } + } + } + if (i + 1 < limit && isWidecExt(str[i + 1])) + ci[actual].Attributes |= COMMON_LVB_LEADING_BYTE; + ++actual; } - ++actual; - } - loc.X = (SHORT) 0; - loc.Y = (SHORT) 0; - siz.X = (SHORT) actual; - siz.Y = 1; - - rec.Left = (SHORT) x; - rec.Top = (SHORT) (y + AdjustY()); - rec.Right = (SHORT) (x + limit - 1); - rec.Bottom = rec.Top; + loc.X = (SHORT) 0; + loc.Y = (SHORT) 0; + siz.X = (SHORT) actual; + siz.Y = 1; + + rec.Left = (SHORT) x; + rec.Top = (SHORT) (y + AdjustY()); + rec.Right = (SHORT) (x + actual - 1); + rec.Bottom = rec.Top; - return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec); + return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec); + } } #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n) #else