diff ui.c @ 513:ef5a2aa8382b

Refactor input handling.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 05 Jun 2012 22:16:42 +0300
parents f71c59cbc5a7
children 436e86afa70a
line wrap: on
line diff
--- a/ui.c	Tue Jun 05 19:56:57 2012 +0300
+++ b/ui.c	Tue Jun 05 22:16:42 2012 +0300
@@ -6,7 +6,6 @@
 #include "util.h"
 #include "ui.h"
 
-#define STATUS_YPOS 0
 
 nn_window_t *chatWindows[SET_MAX_WINDOWS],
             *currWin = NULL;
@@ -292,27 +291,6 @@
 }
 
 
-char *nnwin_prompt_requester(const char *info, BOOL allowEmpty)
-{
-    char buf[512], *ptr;
-
-    echo();
-    wattrset(stdscr, A_NORMAL);
-    wbkgdset(stdscr, COLOR_PAIR(0));
-    waddstr(stdscr, info);
-    wgetnstr(stdscr, buf, sizeof(buf) - 1);
-    noecho();
-
-    str_trim_right(buf);
-    ptr = str_trim_left(buf);
-
-    if (allowEmpty || ptr[0])
-        return th_strdup(ptr);
-    else
-        return NULL;
-}
-
-
 static void nnwin_print_str(WINDOW *win, const char *fmt, BOOL clip)
 {
     const char *s = fmt;
@@ -345,7 +323,7 @@
 }
 
 
-void nnwin_update(BOOL force, nn_editbuf_t *ebuf, char *username, int usercolor)
+void nnwin_update(BOOL force, BOOL mask, nn_editbuf_t *ebuf, char *username, int usercolor)
 {
     int sx, sy;
     
@@ -454,20 +432,244 @@
     {
         int yoffs = ebuf->pos / scrWidth,
             xoffs = ebuf->pos % scrWidth;
-        char *tmp;
-
-        ebuf->dirty = FALSE;
-        ebuf->data[ebuf->len] = 0;
-        tmp = nn_username_decode(th_strdup(ebuf->data));
 
         wmove(stdscr, scrHeight - 3, 0);
         wattrset(stdscr, A_NORMAL);
         wbkgdset(stdscr, COLOR_PAIR(0));
-        waddnstr(stdscr, tmp, ebuf->len);
+
+        ebuf->dirty = FALSE;
+        if (mask)
+        {
+            size_t i;
+            for (i = 0; i < ebuf->len; i++)
+                waddch(stdscr, '*');
+        }
+        else
+        {
+            char *tmp;
+            ebuf->data[ebuf->len] = 0;
+            tmp = nn_username_decode(th_strdup(ebuf->data));
+            waddnstr(stdscr, tmp, ebuf->len);
+            th_free(tmp);
+        }
         wmove(stdscr, scrHeight - 3 + yoffs, xoffs);
 
-        th_free(tmp);
     }
 
     wrefresh(stdscr);
 }
+
+
+void nnwin_input_process(nn_editbuf_t *editBuf, nn_editstate_t *editState,
+    BOOL (*callback)(int, nn_editbuf_t *, nn_editstate_t *))
+{
+    int c, cnt = 0;
+    
+    // Handle several buffered keypresses at once
+    do
+    {
+        c = wgetch(stdscr);
+        
+        /* Handle various problematic cases where terminal 
+         * keycodes do not get properly translated by curses
+         */
+        if (c == 10 || c == 13)
+            c = KEY_ENTER;
+        else
+        if (c == 0x1b)
+        {
+            // ^[O
+            c = wgetch(stdscr);
+            if (c == 'O')
+            {
+                c = wgetch(stdscr);
+                switch (c)
+                {
+                case 'd':
+                    c = 0x204;
+                    break;
+                case 'c':
+                    c = 0x206;
+                    break;
+                default:
+                    editState->debugMsg("Unhandled ESC-O key sequence 0x%02x\n", c);
+                    break;
+                }
+            }
+            // ^[[
+            else if (c == '[')
+            {
+                c = wgetch(stdscr);
+                switch (c)
+                {
+                case 0x31:
+                    c = wgetch(stdscr);
+                    if (c >= 0x31 && c <= 0x39)
+                        c = KEY_F(c - 0x30);
+                    else
+                        c = ERR;
+                    break;
+
+                case 0x32:
+                    c = KEY_IC;
+                    break;
+                case 0x33:
+                    c = KEY_DC;
+                    break;
+
+                case 0x35:
+                    c = KEY_PPAGE;
+                    break;
+                case 0x36:
+                    c = KEY_NPAGE;
+                    break;
+
+                case 0x37:
+                    c = KEY_HOME;
+                    break;
+                case 0x38:
+                    c = KEY_END;
+                    break;
+
+                default:
+                    editState->debugMsg("Unhandled ESC-[*~ key sequence 0x%02x\n", c);
+                    c = ERR;
+                    break;
+                }
+                // Get the trailing ~
+                if (c != ERR)
+                    wgetch(stdscr);
+            }
+            else
+            if (c >= 0x31 && c <= 0x39)
+            {
+                c = c - 0x30 + 0x5000;
+            }
+            else
+            {
+                editState->debugMsg("Unhandled ESC key sequence 0x%02x\n", c);
+            }
+        }
+#if defined(__WIN32) && defined(PDCURSES)
+        else
+        if (c >= 0x198 && c <= 0x1a0)
+        {
+            c = c - 0x198 + 0x5000;
+        }
+#endif
+
+        switch (c)
+        {
+#ifdef KEY_RESIZE
+        case KEY_RESIZE:
+            resize_term(0, 0);
+            erase();
+            timeout(SET_DELAY);
+            nnwin_reset();
+            editState->update = TRUE;
+            break;
+#endif
+
+        case 0x204: // ctrl+left arrow = Skip words left
+        case 0x20b:
+            while (editBuf->pos > 0 && isspace((int) editBuf->data[editBuf->pos - 1]))
+                editBuf->pos--;
+            while (editBuf->pos > 0 && !isspace((int) editBuf->data[editBuf->pos - 1]))
+                editBuf->pos--;
+            editBuf->dirty = TRUE;
+            break;
+
+        case 0x206: // ctrl+right arrow = Skip words right
+        case 0x210:
+            while (editBuf->pos < editBuf->len && isspace((int) editBuf->data[editBuf->pos]))
+                editBuf->pos++;
+            while (editBuf->pos < editBuf->len && !isspace((int) editBuf->data[editBuf->pos]))
+                editBuf->pos++;
+            editBuf->dirty = TRUE;
+            break;
+
+        case KEY_HOME:
+            nn_editbuf_setpos(editBuf, 0);
+            break;
+        case KEY_END:
+            nn_editbuf_setpos(editBuf, editBuf->len);
+            break;
+        case KEY_LEFT:
+            nn_editbuf_setpos(editBuf, editBuf->pos - 1);
+            break;
+        case KEY_RIGHT:
+            nn_editbuf_setpos(editBuf, editBuf->pos + 1);
+            break;
+
+        case KEY_BACKSPACE:
+        case 0x08:
+        case 0x7f:
+            nn_editbuf_delete(editBuf, editBuf->pos - 1);
+            nn_editbuf_setpos(editBuf, editBuf->pos - 1);
+            break;
+
+        case KEY_DC: // Delete character
+            nn_editbuf_delete(editBuf, editBuf->pos);
+            break;
+
+        case KEY_IC: // Ins = Toggle insert / overwrite mode
+            editState->insertMode = !editState->insertMode;
+            break;
+
+        case KEY_F(2): // F2 = Clear editbuffer
+            nn_editbuf_clear(editBuf);
+            break;
+
+        case 0x0c: // Ctrl + L
+            editState->update = TRUE;
+            break;
+
+        case ERR:
+            // Ignore
+            break;
+
+        default:
+            if (!callback(c, editBuf, editState))
+            {
+                if (isprint(c) || c == 0xe4 || c == 0xf6 || c == 0xc4 || c == 0xd6)
+                {
+                    if (editState->insertMode)
+                        nn_editbuf_insert(editBuf, editBuf->pos, c);
+                    else
+                        nn_editbuf_write(editBuf, editBuf->pos, c);
+                    nn_editbuf_setpos(editBuf, editBuf->pos + 1);
+                }
+                else
+                    editState->debugMsg("Unhandled key: 0x%02x\n", c);
+            }
+            break;
+        }
+    }
+    while (c != ERR && ++cnt < 10);
+}
+
+
+
+char *nnwin_prompt_requester(BOOL allowEmpty, nn_editstate_t *editState,
+    BOOL (*callback)(int, nn_editbuf_t *, nn_editstate_t *),
+    void (*update)(nn_editbuf_t *, nn_editstate_t *))
+{
+    nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE);
+    char *res;
+
+    editState->done = FALSE;
+    while (!editState->isError && !editState->exitProg && !editState->done)
+    {
+        nnwin_input_process(editBuf, editState, callback);
+        update(editBuf, editState);
+    }    
+    
+    if (allowEmpty || editBuf->len > 0)
+        res = nn_editbuf_get_string(editBuf, 0, editBuf->len);
+    else
+        res = NULL;
+
+    nn_editbuf_free(editBuf);
+    
+    return res;
+}