diff --git a/src/chat.c b/src/chat.c index d56d482..f34a1e4 100644 --- a/src/chat.c +++ b/src/chat.c @@ -283,13 +283,27 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) /* BACKSPACE key: Remove one character from line */ if (key == 0x107 || key == 0x8 || key == 0x7f) { if (ctx->pos > 0) { - ctx->line[--ctx->pos] = L'\0'; + del_char_from_buf(key, ctx->line, &ctx->pos, &ctx->len); if (x == 0) - mvwdelch(self->window, y - 1, x2 - 1); + wmove(self->window, y-1, x2-1); else - mvwdelch(self->window, y, x - 1); + wmove(self->window, y, x-1); } + } else if (key == KEY_LEFT && ctx->pos > 0) { + --ctx->pos; + + if (x == 0) + wmove(self->window, y-1, x2-1); + else + wmove(self->window, y, x-1); + } else if (key == KEY_RIGHT && ctx->line[ctx->pos] != L'\0') { + ++ctx->pos; + + if (x == x2-1) + wmove(self->window, y+1, 0); + else + wmove(self->window, y, x+1); } else /* Add printable chars to buffer and print on input space */ #if HAVE_WIDECHAR @@ -297,11 +311,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) #else if (isprint(key)) #endif - { - if (ctx->pos < (MAX_STR_SIZE-1)) { - mvwaddstr(self->window, y, x, wc_to_char(key)); - ctx->line[ctx->pos++] = key; - ctx->line[ctx->pos] = L'\0'; + { /* prevents buffer overflows and strange behaviour when cursor goes past the window */ + if ( (ctx->len < MAX_STR_SIZE-1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1)-1)) ) { + add_char_to_buf(key, ctx->line, &ctx->pos, &ctx->len); + + if (x == x2-1) + wmove(self->window, y+1, 0); + else + wmove(self->window, y, x+1); } } /* RETURN key: Execute command or print line */ @@ -354,8 +371,7 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) free(ctx); free(statusbar); } else { - ctx->line[0] = L'\0'; - ctx->pos = 0; + reset_buf(ctx->line, &ctx->pos, &ctx->len); } free(line); @@ -370,6 +386,9 @@ static void chat_onDraw(ToxWindow *self, Tox *m) ChatContext *ctx = self->chatwin; + wclear(ctx->linewin); + mvwprintw(ctx->linewin, 1, 0, "%s\n", wcs_to_char(ctx->line)); + /* Draw status bar */ StatusBar *statusbar = self->stb; mvwhline(statusbar->topline, 1, 0, ACS_HLINE, x); @@ -434,7 +453,6 @@ static void chat_onDraw(ToxWindow *self, Tox *m) } wprintw(statusbar->topline, "\n"); - mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x); wrefresh(self->window); } diff --git a/src/groupchat.c b/src/groupchat.c index 618cfb7..5344ab4 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -223,25 +223,41 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key) /* BACKSPACE key: Remove one character from line */ if (key == 0x107 || key == 0x8 || key == 0x7f) { if (ctx->pos > 0) { - ctx->line[--ctx->pos] = L'\0'; + del_char_from_buf(key, ctx->line, &ctx->pos, &ctx->len); if (x == 0) - mvwdelch(self->window, y - 1, x2 - 1); + wmove(self->window, y-1, x2-1); else - mvwdelch(self->window, y, x - 1); + wmove(self->window, y, x-1); } - } else - /* Add printable chars to buffer and print on input space */ + } else if (key == KEY_LEFT && ctx->pos > 0) { + --ctx->pos; + + if (x == 0) + wmove(self->window, y-1, x2-1); + else + wmove(self->window, y, x-1); + } else if (key == KEY_RIGHT && ctx->line[ctx->pos] != L'\0') { + ++ctx->pos; + + if (x == x2-1) + wmove(self->window, y+1, 0); + else + wmove(self->window, y, x+1); + } else #if HAVE_WIDECHAR if (iswprint(key)) #else if (isprint(key)) #endif - { - if (ctx->pos < (MAX_STR_SIZE-1)) { - mvwaddstr(self->window, y, x, wc_to_char(key)); - ctx->line[ctx->pos++] = key; - ctx->line[ctx->pos] = L'\0'; + { /* prevents buffer overflows and strange behaviour when cursor goes past the window */ + if ( (ctx->len < MAX_STR_SIZE-1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1)-1)) ) { + add_char_to_buf(key, ctx->line, &ctx->pos, &ctx->len); + + if (x == x2-1) + wmove(self->window, y+1, 0); + else + wmove(self->window, y, x+1); } } @@ -287,8 +303,7 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key) if (close_win) free(ctx); else { - ctx->line[0] = L'\0'; - ctx->pos = 0; + reset_buf(ctx->line, &ctx->pos, &ctx->len); } free(line); @@ -302,6 +317,10 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m) getmaxyx(self->window, y, x); ChatContext *ctx = self->chatwin; + + wclear(ctx->linewin); + mvwprintw(ctx->linewin, 1, 0, "%s\n", wcs_to_char(ctx->line)); + wclrtobot(ctx->sidebar); mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x); mvwvline(ctx->sidebar, 0, 0, ACS_VLINE, y-CHATBOX_HEIGHT); @@ -338,7 +357,7 @@ static void groupchat_onInit(ToxWindow *self, Tox *m) ChatContext *ctx = self->chatwin; ctx->history = subwin(self->window, y-CHATBOX_HEIGHT+1, x-SIDEBAR_WIDTH-1, 0, 0); scrollok(ctx->history, 1); - ctx->linewin = subwin(self->window, 2, x, y-CHATBOX_HEIGHT, 0); + ctx->linewin = subwin(self->window, CHATBOX_HEIGHT, x, y-CHATBOX_HEIGHT, 0); ctx->sidebar = subwin(self->window, y-CHATBOX_HEIGHT+1, SIDEBAR_WIDTH, 0, x-SIDEBAR_WIDTH); print_groupchat_help(ctx); diff --git a/src/misc_tools.c b/src/misc_tools.c index 0628cdc..7199857 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -8,6 +8,7 @@ #include #include "toxic_windows.h" +#include "misc_tools.h" // XXX: FIX unsigned char *hex_string_to_bin(char hex_string[]) @@ -158,3 +159,62 @@ bool valid_nick(uint8_t *nick) return true; } + +/* + * Buffer helper tools. Assumes buffers are no larger than MAX_STR_SIZE + */ + +/* Adds char to buffer at pos */ +void add_char_to_buf(wint_t ch, wchar_t *buf, size_t *pos, size_t *len) +{ + if (*pos < 0 || *len >= MAX_STR_SIZE) + return; + + /* if cursor is at end of line simply insert char at last position and increment */ + if (buf[*pos] == L'\0') { + buf[(*pos)++] = ch; + buf[*pos] = L'\0'; + ++(*len); + return; + } + + /* move all chars in front of pos one space forward and insert char in pos */ + int i; + + for (i = *len; i >= *pos && i >= 0; --i) + buf[i+1] = buf[i]; + + buf[(*pos)++] = ch; + ++(*len); +} + +/* Deletes the character before pos via the backspace key */ +void del_char_from_buf(wint_t ch, wchar_t *buf, size_t *pos, size_t *len) +{ + if (*pos <= 0) + return; + + /* if cursor is at end of line delete previous char */ + if (buf[*pos] == L'\0') { + buf[--(*pos)] = L'\0'; + --(*len); + return; + } + + int i; + + /* similar to add_char_to_buf but deletes a char */ + for (i = *pos-1; i <= *len; ++i) + buf[i] = buf[i+1]; + + --(*pos); + --(*len); +} + +/* sets pos and len to 0 */ +void reset_buf(wchar_t *buf, size_t *pos, size_t *len) +{ + buf[0] = L'\0'; + *pos = 0; + *len = 0; +} diff --git a/src/misc_tools.h b/src/misc_tools.h index 77515b6..ec83734 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -36,3 +36,16 @@ int name_compare(const void *nick1, const void *nick2); - cannot start with a space - must not contain contiguous spaces */ bool valid_nick(uint8_t *nick); + +/* + * Buffer helper tools. + */ + +/* Adds char to buffer at pos */ +void add_char_to_buf(wint_t ch, wchar_t *buf, size_t *pos, size_t *len); + +/* Deletes the character before pos via the backspace key */ +void del_char_from_buf(wint_t ch, wchar_t *buf, size_t *pos, size_t *len); + +/* sets pos and len to 0 */ +void reset_buf(wchar_t *buf, size_t *pos, size_t *len); \ No newline at end of file diff --git a/src/toxic_windows.h b/src/toxic_windows.h index 9fbe721..42a34b5 100644 --- a/src/toxic_windows.h +++ b/src/toxic_windows.h @@ -99,6 +99,7 @@ struct StatusBar { struct ChatContext { wchar_t line[MAX_STR_SIZE]; size_t pos; + size_t len; WINDOW *history; WINDOW *linewin; WINDOW *sidebar;