tSupport Unicode in text input - vaccinewars - be a doctor and try to vaccinate the world
 (HTM) git clone git://src.adamsgaard.dk/vaccinewars
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 594e648055b50a8e1bda0b1401e16502fb48d14c
 (DIR) parent a1765422bbab17983838549b5ef7e909e3fd3247
 (HTM) Author: Ben Webb <ben@salilab.org>
       Date:   Sun,  3 Jan 2021 21:57:57 -0800
       
       Support Unicode in text input
       
       When in a UTF-8 locale, allow Unicode characters
       tto be input to prompts (e.g. for the user's name).
       Closes #60.
       
       Diffstat:
         M ChangeLog.md                        |       5 +++++
         M src/curses_client/curses_client.c   |      58 ++++++++++++++++++++++---------
       
       2 files changed, 47 insertions(+), 16 deletions(-)
       ---
 (DIR) diff --git a/ChangeLog.md b/ChangeLog.md
       t@@ -1,3 +1,8 @@
       +# HEAD
       +- The text-mode client should now support Unicode input when in UTF-8
       +  locales, e.g. allowing player names containing accented characters
       +  to be input (#60).
       +
        # 1.6.1 - 2020-12-11
        - Improved display in non-English text-mode clients; previously
          columns were not aligned properly in some cases and occasionally
 (DIR) diff --git a/src/curses_client/curses_client.c b/src/curses_client/curses_client.c
       t@@ -2272,7 +2272,8 @@ Player *ListPlayers(Player *Play, gboolean Select, char *Prompt)
        char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly,
                         char *displaystr, char passwdchar)
        {
       -  int i, c, x;
       +  int ibyte, ichar, x;
       +  gunichar c;
          gboolean DecimalPoint, Suffix;
          GString *text;
          gchar *ReturnString;
       t@@ -2289,47 +2290,72 @@ char *nice_input(char *prompt, int sy, int sx, gboolean digitsonly,
          attrset(TextAttr);
          if (displaystr) {
            if (passwdchar) {
       -      for (i = strlen(displaystr); i; i--)
       +      int i;
       +      for (i = strcharlen(displaystr); i; i--)
                addch((guint)passwdchar);
            } else {
              addstr(displaystr);
            }
       -    i = strlen(displaystr);
       +    ibyte = strlen(displaystr);
       +    ichar = strcharlen(displaystr);
            text = g_string_new(displaystr);
          } else {
       -    i = 0;
       +    ibyte = ichar = 0;
            text = g_string_new("");
          }
        
          curs_set(1);
          do {
       -    move(sy + (x + i) / Width, (x + i) % Width);
       +    move(sy + (x + ichar) / Width, (x + ichar) % Width);
            c = bgetch();
       -    if ((c == 8 || c == KEY_BACKSPACE || c == 127) && i > 0) {
       -      move(sy + (x + i - 1) / Width, (x + i - 1) % Width);
       +    if ((c == 8 || c == KEY_BACKSPACE || c == 127) && ichar > 0) {
       +      move(sy + (x + ichar - 1) / Width, (x + ichar - 1) % Width);
              addch(' ');
       -      i--;
       -      if (DecimalPoint && text->str[i] == '.')
       +      ichar--;
       +      if (LocaleIsUTF8) {
       +        char *p = g_utf8_find_prev_char(text->str, text->str+ibyte);
       +        assert(p);
       +        ibyte = p - text->str;
       +      } else {
       +        ibyte--;
       +      }
       +      if (DecimalPoint && text->str[ibyte] == '.')
                DecimalPoint = FALSE;
              if (Suffix)
                Suffix = FALSE;
       -      g_string_truncate(text, i);
       +      g_string_truncate(text, ibyte);
            } else if (!Suffix) {
              if ((digitsonly && c >= '0' && c <= '9') ||
       -          (!digitsonly && c >= 32 && c != '^' && c < 127)) {
       -        g_string_append_c(text, c);
       -        i++;
       -        addch((guint)passwdchar ? passwdchar : c);
       +          (!digitsonly && c >= 32 && c != '^' && c != 127)) {
       +        if (LocaleIsUTF8) {
       +          char utf8buf[20];
       +          gint utf8len = g_unichar_to_utf8(c, utf8buf);
       +          utf8buf[utf8len] = '\0';
       +          ibyte += utf8len;
       +          g_string_append(text, utf8buf);
       +          if (passwdchar) {
       +            addch((guint)passwdchar);
       +          } else {
       +            addstr(utf8buf);
       +          }
       +        } else {
       +          g_string_append_c(text, c);
       +          ibyte++;
       +          addch((guint)passwdchar ? passwdchar : c);
       +        }
       +        ichar++;
              } else if (digitsonly && (c == '.' || c == ',') && !DecimalPoint) {
                g_string_append_c(text, '.');
       -        i++;
       +        ibyte++;
       +        ichar++;
                addch((guint)passwdchar ? passwdchar : c);
                DecimalPoint = TRUE;
              } else if (digitsonly
                         && (c == 'M' || c == 'm' || c == 'k' || c == 'K')
                         && !Suffix) {
                g_string_append_c(text, c);
       -        i++;
       +        ibyte++;
       +        ichar++;
                addch((guint)passwdchar ? passwdchar : c);
                Suffix = TRUE;
              }