# HG changeset patch # User Matti Hamalainen # Date 1338923802 -10800 # Node ID ef5a2aa8382b5415935df7f6d472bcd0a0d2db43 # Parent 93c8ba1ef55f618e3f61d864d075387d85f8e4f8 Refactor input handling. diff -r 93c8ba1ef55f -r ef5a2aa8382b main.c --- a/main.c Tue Jun 05 19:56:57 2012 +0300 +++ b/main.c Tue Jun 05 22:16:42 2012 +0300 @@ -19,11 +19,9 @@ #ifdef __WIN32 #define SET_CONFIG_FILE "nnchat.txt" #define SET_DIR_SEPARATOR "\\" -#define SET_DELAY (0) #else #define SET_CONFIG_FILE ".nnchat" #define SET_DIR_SEPARATOR "/" -#define SET_DELAY (5) #endif #define SET_PROFILE_PREFIX "http://www.newbienudes.com/profile/%s/" @@ -63,6 +61,9 @@ *setBrowser = NULL; cfgitem_t *cfg = NULL; +nn_editbuf_t *editHistBuf[SET_MAX_HISTORY+2]; +int editHistPos = 0, + editHistMax = 0; /* Logging mode flags */ @@ -313,6 +314,19 @@ } +void debugMsg(const char *fmt, ...) +{ + if (optDebug) + { + va_list ap; + + va_start(ap, fmt); + printMsgV(NULL, LOG_FILE|LOG_WINDOW, fmt, ap); + va_end(ap); + } +} + + void errorFunc(struct _nn_conn_t *conn, const char *fmt, va_list ap) { (void) conn; @@ -1292,24 +1306,161 @@ } +BOOL processUserInput(int c, nn_editbuf_t *editBuf, nn_editstate_t *editState) +{ + // Chat window switching via Meta/Esc-[1..9] + if (c >= 0x5001 && c <= 0x5009) + { + nn_window_t *win = nnwin_get(c - 0x5000); + if (win != NULL) + { + currWin = win; + editState->update = TRUE; + } + } + else + switch (c) + { + case KEY_ENTER: + // Call the user input handler + if (editBuf->len > 0) + { + int result; + + if (editHistMax > 0) + { + nn_editbuf_free(editHistBuf[SET_MAX_HISTORY+1]); + editHistBuf[SET_MAX_HISTORY+1] = NULL; + memmove(&editHistBuf[2], &editHistBuf[1], + editHistMax * sizeof(editHistBuf[0])); + } + + editHistPos = 0; + editHistBuf[1] = nn_editbuf_copy(editBuf); + if (editHistMax < SET_MAX_HISTORY) + editHistMax++; + + result = nn_handle_input(editState->conn, editBuf->data, editBuf->len); + + nn_editbuf_clear(editBuf); + + if (result < 0) + { + errorMsg("Fatal error handling user input: %s\n", editBuf->data); + editState->isError = TRUE; + } + else + { + // Update time value of last sent message for unidle timeouts + editState->prevKeepAlive = time(NULL); + } + } + break; + + case KEY_NPAGE: + case KEY_PPAGE: + // Page Up / Page Down + if (currWin != NULL) + { + int oldPos = currWin->pos, page = (scrHeight - 4) / 3; + + currWin->pos += (c == KEY_NPAGE) ? - page : page; + + if (currWin->pos >= currWin->data->n - page) + currWin->pos = currWin->data->n - page; + if (currWin->pos < 0) + currWin->pos = 0; + + if (oldPos != currWin->pos) + editState->update = TRUE; + } + break; + + case KEY_UP: // Backwards in input history + if (editHistPos == 0) + { + nn_editbuf_free(editHistBuf[0]); + editHistBuf[0] = nn_editbuf_copy(editBuf); + } + if (editHistPos < editHistMax) + { + editHistPos++; + nn_editbuf_free(editBuf); + editBuf = nn_editbuf_copy(editHistBuf[editHistPos]); + } + break; + + case KEY_DOWN: // Forwards in input history + if (editHistPos > 0) + { + editHistPos--; + nn_editbuf_free(editBuf); + editBuf = nn_editbuf_copy(editHistBuf[editHistPos]); + } + break; + + case KEY_F(5): // F5 = Ignore mode + setIgnoreMode = setIgnoreMode; + printMsgQ(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF"); + break; + + case 0x03: // ^C = quit + case KEY_F(9): // F9 = Quit + printMsg(currWin, "Quitting per user request (%d/0x%x).\n", c, c); + editState->exitProg = TRUE; + break; + + case 0x09: // Tab = complete username or command + nn_tabcomplete_buffer(editBuf); + break; + + default: + return FALSE; + } + + return TRUE; +} + + +BOOL processUserPrompt(int c, nn_editbuf_t *editBuf, nn_editstate_t *editState) +{ + (void) editBuf; + + switch (c) + { + case KEY_ENTER: + editState->done = TRUE; + break; + + default: + return FALSE; + } + + return TRUE; +} + + +void updateUserPrompt(nn_editbuf_t *editBuf, nn_editstate_t *editState) +{ + nnwin_update(editState->update, editState->mask, editBuf, optUserName, optUserColor); +} + + int main(int argc, char *argv[]) { + char *tmpStr; + int index, updateCount = 0; + BOOL argsOK, colorSet = FALSE; nn_conn_t *conn = NULL; - int updateCount = 0; - BOOL argsOK, isError = FALSE, - exitProg = FALSE, - colorSet = FALSE, - insertMode = TRUE; - time_t prevKeepAlive; - char *tmpStr; nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE); - nn_editbuf_t *histBuf[SET_MAX_HISTORY+2]; - int histPos = 0, histMax = 0, index; - + nn_editstate_t editState; cfgitem_t *tmpcfg; char *setHomeDir = NULL; - memset(histBuf, 0, sizeof(histBuf)); + memset(editHistBuf, 0, sizeof(editHistBuf)); + memset(&editState, 0, sizeof(editState)); + editState.insertMode = TRUE; + editState.debugMsg = debugMsg; // Initialize th_init("NNChat", "Newbie Nudes chat client", NN_VERSION, @@ -1417,6 +1568,7 @@ if (optUserNameCmd != NULL) { + THMSG(1, "Username set on commandline.\n"); optUserName = optUserNameCmd; optPassword = optPasswordCmd; } @@ -1453,14 +1605,26 @@ if (cursesInit) { - nnwin_update(TRUE, NULL, optUserName, optUserColor); - } + printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname); + printMsg(NULL, "%s\n", th_prog_author); + printMsg(NULL, "%s\n", th_prog_license); + + nnwin_update(TRUE, FALSE, NULL, optUserName, optUserColor); - // Check if we have username and password - if (cursesInit && (optUserName == NULL || optPassword == NULL)) - { - optUserName = nnwin_prompt_requester("You can avoid this prompt by issuing '/save' after logging in.\nNN username: ", FALSE); - optPassword = nnwin_prompt_requester("NN password: ", TRUE); + // Check if we have username and password + if (optUserName == NULL || optPassword == NULL) + { + printMsg(NULL, "Please enter your NN login credentials.\n"); + printMsg(NULL, "You can avoid doing this every time by issuing '/save' after logging in.\n"); + + printMsg(NULL, "Enter your NN username ...\n"); + optUserName = nnwin_prompt_requester(FALSE, &editState, processUserPrompt, updateUserPrompt); + + editState.mask = TRUE; + printMsg(NULL, "Enter your NN password ...\n"); + optPassword = nnwin_prompt_requester(TRUE, &editState, processUserPrompt, updateUserPrompt); + editState.mask = FALSE; + } } if (optUserName == NULL || optPassword == NULL) @@ -1476,6 +1640,8 @@ errorMsg("Could not create connection structure.\n"); goto err_exit; } + + editState.conn = conn; // Are we using a proxy? if (optProxyType != NN_PROXY_NONE && optProxyServer != NULL) @@ -1541,25 +1707,12 @@ nn_usercmd_init(); // Initialize random numbers - prevKeepAlive = time(NULL); - srandom((int) prevKeepAlive); - - if (cursesInit) - { - // Initialize rest of interactive UI code - nn_editbuf_clear(editBuf); - - // First update of screen - nnwin_update(TRUE, editBuf, optUserName, optUserColor); - - printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname); - printMsg(NULL, "%s\n", th_prog_author); - printMsg(NULL, "%s\n", th_prog_license); - } + editState.prevKeepAlive = time(NULL); + srandom((int) editState.prevKeepAlive); // Enter mainloop nn_conn_reset(conn); - while (!isError && !exitProg) + while (!editState.isError && !editState.exitProg) { int retries = 3, cres; @@ -1569,7 +1722,7 @@ { while (conn->ptr < conn->in_ptr && *(conn->in_ptr - 1) == 0 && - retries > 0 && !isError) + retries > 0 && !editState.isError) { // nn_conn_dump_buffer(stderr, conn); int result = nn_parse_protocol(conn); @@ -1589,326 +1742,29 @@ nn_conn_buf_skip(conn, strlen(conn->ptr) + 1); } else - isError = TRUE; + editState.isError = TRUE; } } else if (cres < 0 || !nn_conn_check(conn)) - isError = TRUE; + editState.isError = TRUE; // Handle user input if (cursesInit) { - int c, cnt = 0; - BOOL update = FALSE; - - // 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 == 0x1b) - { - // ^[O - c = wgetch(stdscr); - if (c == 'O') - { - c = wgetch(stdscr); - switch (c) - { - case 'd': - c = 0x204; - break; - case 'c': - c = 0x206; - break; - default: - if (optDebug) - printMsg(currWin, "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: - if (optDebug) - printMsg(currWin, "Unhandled ESC-[*~ key sequence 0x%02x\n", c); - c = ERR; - break; - } - // Get the trailing ~ - if (c != ERR) - wgetch(stdscr); - } - if (c >= 0x31 && c <= 0x39) - { - // Chat window switching via Meta/Esc-[1..9] - nn_window_t *win = nnwin_get(c - 0x30); - if (win != NULL) - { - currWin = win; - update = TRUE; - } - c = ERR; - } - else - { - if (optDebug) - printMsg(currWin, "Unhandled ESC key sequence 0x%02x\n", c); - } - } -#if defined(__WIN32) && defined(PDCURSES) - else if (c >= 0x198 && c <= 0x1a0) - { - // Chat window switching via Meta/Esc-[1..9] - nn_window_t *win = nnwin_get(c - 0x198); - if (win != NULL) - { - currWin = win; - update = TRUE; - } - c = ERR; - } -#endif - - switch (c) - { -#ifdef KEY_RESIZE - case KEY_RESIZE: - resize_term(0, 0); - erase(); - timeout(SET_DELAY); - nnwin_reset(); - update = TRUE; - break; -#endif - - case KEY_ENTER: - case '\n': - case '\r': - // Call the user input handler - if (editBuf->len > 0) - { - int result; - - if (histMax > 0) - { - nn_editbuf_free(histBuf[SET_MAX_HISTORY+1]); - histBuf[SET_MAX_HISTORY+1] = NULL; - memmove(&histBuf[2], &histBuf[1], histMax * sizeof(histBuf[0])); - } - - histPos = 0; - histBuf[1] = nn_editbuf_copy(editBuf); - if (histMax < SET_MAX_HISTORY) histMax++; - - result = nn_handle_input(conn, editBuf->data, editBuf->len); - - nn_editbuf_clear(editBuf); - - if (result < 0) - { - errorMsg("Fatal error handling user input: %s\n", editBuf->data); - isError = TRUE; - } - else - { - // Update time value of last sent message for unidle timeouts - prevKeepAlive = time(NULL); - } - } - break; - - case KEY_UP: // Backwards in input history - if (histPos == 0) - { - nn_editbuf_free(histBuf[0]); - histBuf[0] = nn_editbuf_copy(editBuf); - } - if (histPos < histMax) - { - histPos++; - nn_editbuf_free(editBuf); - editBuf = nn_editbuf_copy(histBuf[histPos]); - } - break; - - case KEY_DOWN: // Forwards in input history - if (histPos > 0) - { - histPos--; - nn_editbuf_free(editBuf); - editBuf = nn_editbuf_copy(histBuf[histPos]); - } - break; - - 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 - insertMode = !insertMode; - break; - - case KEY_F(2): // F2 = Clear editbuffer - nn_editbuf_clear(editBuf); - break; - - case KEY_F(5): // F5 = Ignore mode - setIgnoreMode = !setIgnoreMode; - printMsgQ(currWin, "Ignore mode = %s\n", setIgnoreMode ? "ON" : "OFF"); - break; - -#if 0 - case KEY_F(8): // F8 = Debug - optDebug = !optDebug; - update = TRUE; - break; -#endif - - case 0x03: // ^C = quit - case KEY_F(9): // F9 = Quit - printMsg(currWin, "Quitting per user request (%d/0x%x).\n", c, c); - exitProg = TRUE; - break; - - case 0x09: // Tab = complete username or command - nn_tabcomplete_buffer(editBuf); - break; - - case 0x0c: // Ctrl + L - update = TRUE; - break; - - case KEY_NPAGE: - case KEY_PPAGE: - // Page Up / Page Down - if (currWin != NULL) - { - int oldPos = currWin->pos, page = scrHeight - 4; - - currWin->pos += (c == KEY_NPAGE) ? - page : page; - - if (currWin->pos >= currWin->data->n - page) - currWin->pos = currWin->data->n - page; - if (currWin->pos < 0) - currWin->pos = 0; - - if (oldPos != currWin->pos) - update = TRUE; - } - break; - - case ERR: - // Ignore - break; - - default: - if (isprint(c) || c == 0xe4 || c == 0xf6 || c == 0xc4 || c == 0xd6) - { - if (insertMode) - nn_editbuf_insert(editBuf, editBuf->pos, c); - else - nn_editbuf_write(editBuf, editBuf->pos, c); - nn_editbuf_setpos(editBuf, editBuf->pos + 1); - } - else - { - if (optDebug) - printMsg(currWin, "Unhandled key: 0x%02x\n", c); - } - break; - } - } - while (c != ERR && !exitProg && ++cnt < 10); - - nnwin_update(update, editBuf, optUserName, optUserColor); - } // cursesInit + nnwin_input_process(editBuf, &editState, processUserInput); + nnwin_update(editState.update, editState.mask, editBuf, optUserName, optUserColor); + } if (++updateCount > 10) { time_t tmpTime = time(NULL); - if (tmpTime - prevKeepAlive > SET_KEEPALIVE) + if (tmpTime - editState.prevKeepAlive > SET_KEEPALIVE) { size_t n = ((size_t) random()) % th_llist_length(setIdleMessages); qlist_t *node = th_llist_get_nth(setIdleMessages, n); nn_conn_send_msg(conn, optUserNameEnc, node->data); - prevKeepAlive = tmpTime; + editState.prevKeepAlive = tmpTime; } if (!colorSet) @@ -1916,8 +1772,12 @@ colorSet = TRUE; nn_conn_send_msg_v(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); } + + if (cursesInit) + { + nnwin_update(FALSE, editState.mask, editBuf, optUserName, optUserColor); + } - nnwin_update(FALSE, editBuf, optUserName, optUserColor); updateCount = 0; } @@ -1932,7 +1792,7 @@ nn_editbuf_free(editBuf); for (index = 0; index <= SET_MAX_HISTORY; index++) - nn_editbuf_free(histBuf[index]); + nn_editbuf_free(editHistBuf[index]); #ifdef __WIN32 if (errorMessages) diff -r 93c8ba1ef55f -r ef5a2aa8382b ui.c --- 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; +} diff -r 93c8ba1ef55f -r ef5a2aa8382b ui.h --- a/ui.h Tue Jun 05 19:56:57 2012 +0300 +++ b/ui.h Tue Jun 05 22:16:42 2012 +0300 @@ -7,9 +7,13 @@ #define LIBNNUI_H #ifdef __WIN32 +#define SET_DELAY (0) // Undefine because both windows.h and curses.h #define it #undef MOUSE_MOVED +#else +#define SET_DELAY (5) #endif + #ifdef HAVE_NCURSES_H #include #else @@ -17,7 +21,7 @@ #endif #include "th_types.h" #include "th_string.h" - +#include "network.h" #define SET_MAX_WINDOWS (32) #define NN_BACKBUF_LEN (512) // Backbuffer size (in lines) @@ -43,6 +47,15 @@ } nn_window_t; +typedef struct +{ + time_t prevKeepAlive; + BOOL insertMode, exitProg, isError, update, mask, done; + nn_conn_t *conn; + void (*debugMsg)(const char *fmt, ...); +} nn_editstate_t; + + extern nn_window_t *currWin; extern BOOL cursesInit; extern int scrHeight, scrWidth; @@ -51,7 +64,7 @@ void nnwin_shutdown(); void nnwin_reset(void); -void nnwin_update(BOOL force, nn_editbuf_t *ebuf, char *optUserName, int optUserColor); +void nnwin_update(BOOL force, BOOL mask, nn_editbuf_t *ebuf, char *optUserName, int optUserColor); nn_window_t * nnwin_main_window(); nn_window_t * nnwin_get(const int index); @@ -62,6 +75,12 @@ void nnwin_close(nn_window_t *win); int nnwin_print(nn_window_t *win, const char *fmt); -char * nnwin_prompt_requester(const char *info, BOOL allowEmpty); + +void nnwin_input_process(nn_editbuf_t *editBuf, nn_editstate_t *editState, + BOOL (*callback)(int, nn_editbuf_t *, nn_editstate_t *)); + +char * nnwin_prompt_requester(BOOL allowEmpty, nn_editstate_t *, + BOOL (*callback)(int, nn_editbuf_t *, nn_editstate_t *), + void (*update)(nn_editbuf_t *, nn_editstate_t *)); #endif diff -r 93c8ba1ef55f -r ef5a2aa8382b util.c --- a/util.c Tue Jun 05 19:56:57 2012 +0300 +++ b/util.c Tue Jun 05 22:16:42 2012 +0300 @@ -426,10 +426,7 @@ char *str; size_t siz; - if (buf == NULL) - return NULL; - - if (end > buf->len || start >= buf->len) + if (buf == NULL || end > buf->len || start >= buf->len) return NULL; if (start <= end)