AmendHub

Download:

jcs

/

subtext

/

amendments

/

81

session: Handle arrow keys in session_field_input

Handle backspace and character insertion when cursor is not at the end
of a field.
 
Have session_input_char return a short so we can return custom codes
> 255 for keys or other events.

jcs made amendment 81 over 2 years ago
--- session.c Fri Feb 18 15:00:49 2022 +++ session.c Mon Feb 21 15:20:58 2022 @@ -72,7 +72,8 @@ session_run(struct uthread *uthread, void *arg) Handle h; char date[9]; struct tm *date_tm; - unsigned char c, done = 0; + unsigned short c; + bool done = false; size_t len; /* until we negotiate otherwise */ @@ -127,7 +128,7 @@ get_another_char: c = session_input_char(s); if (s->ending) break; - if (c == '\r' || c == 0) + if (c == '\r' || c == 0 || c > 255) goto get_another_char; session_printf(s, "%c\r\n", c); @@ -145,7 +146,7 @@ get_another_char: /* goodbye */ session_output_string(s, "Goodbye!\r\n"); session_flush(s); - done = 1; + done = true; break; case 'm': case 'M': @@ -322,30 +323,70 @@ session_output_template(struct session *session, const return size; } -char +unsigned short session_input_char(struct session *session) { - unsigned char ret; + unsigned short ret; + short waiting_for = 1; + short consumed = 0; wait_for_char: - while (session->ibuflen == 0) { + while (session->ibuflen < waiting_for) { session->node_funcs->input(session); if (session->ending) return 0; if (session->abort_input) return 0; - if (session->ibuflen != 0) + if (session->ibuflen >= waiting_for) break; if (session->obuflen != 0 && session->chatting) return 0; uthread_yield(); } + if (session->ibuf[0] == '\33') { + /* look for a VT100 escape sequence */ + if (session->ibuflen == 1) { + waiting_for = 2; + goto wait_for_char; + } else if (session->ibuf[1] == '[') { + if (session->ibuflen == 2) { + waiting_for = 3; + goto wait_for_char; + } else { + consumed = 3; + switch (session->ibuf[2]) { + case 'A': + ret = KEY_UP; + break; + case 'B': + ret = KEY_DOWN; + break; + case 'C': + ret = KEY_RIGHT; + break; + case 'D': + ret = KEY_LEFT; + break; + default: + /* probably not good to pass it through as-is */ + ret = KEY_OTHER; + } + + goto done_consuming; + } + } + } + ret = session->ibuf[0]; - if (session->ibuflen == 1) + consumed = 1; + +done_consuming: + if (session->ibuflen == consumed) session->ibuflen = 0; else { - memmove(session->ibuf, session->ibuf + 1, session->ibuflen - 1); + memmove(session->ibuf, session->ibuf + consumed, + session->ibuflen - consumed); session->ibuflen--; } @@ -370,14 +411,16 @@ session_field_input(struct session *session, unsigned { short ilen = 0, ipos = 0, lastlen = 0; char *field; - unsigned char c, redraw = 0; + unsigned short c; + unsigned char chc; + bool redraw = false; session->abort_input = 0; field = xmalloczero(size); if (initial_input) { - ipos = strlcpy(field, initial_input, size); + ipos = ilen = strlcpy(field, initial_input, size); /* TODO: handle initial value being longer than width */ session_output_string(session, field); session_flush(session); @@ -398,48 +441,82 @@ session_field_input(struct session *session, unsigned break; case CONTROL_C: /* ^C */ goto field_input_bail; - case 8: /* backspace / ^H */ - case 127: /* delete (through telnet) */ + case BACKSPACE: /* ^H */ + case DELETE: /* backspace through telnet */ if (ipos == 0) continue; if (ipos < ilen) { /* l:3 p:2 f:ab[cursor]c -> l:2 p:2 f:a[cursor]c */ - redraw = 1; - BlockMove((Ptr)(field + ipos), (Ptr)(field + ipos - 1), - ilen - 1); + redraw = true; + memmove(field + ipos - 1, field + ipos, ilen - 1); } ipos--; ilen--; - field[ipos] = '\0'; + field[ilen] = '\0'; + session_output_string(session, + ansi(session, ANSI_BACKSPACE, ANSI_END)); + if (redraw) { - /* TODO */ - } else { session_output_string(session, - ansi(session, ANSI_BACKSPACE, ANSI_END)); - session_flush(session); + ansi(session, ANSI_SAVE_CURSOR, ANSI_END)); + session_output(session, field + ipos, + ilen - ipos); + session_output(session, " ", 1); + session_output_string(session, + ansi(session, ANSI_RESTORE_SAVED_CURSOR, ANSI_END)); } - + + session_flush(session); break; case '\r': case '\n': return field; + case KEY_LEFT: + if (ipos == 0) + continue; + ipos--; + session_output_string(session, + ansi(session, ANSI_BACK_N, 1, ANSI_END)); + session_flush(session); + break; + case KEY_RIGHT: + if (ipos == ilen) + continue; + ipos++; + session_output_string(session, + ansi(session, ANSI_FORWARD_N, 1, ANSI_END)); + session_flush(session); + break; default: if (c < 32 || c > 127) break; if (ilen >= size - 1) break; - if (ipos <= ilen) - /* TODO: move */ - ; + chc = c; + if (ipos < ilen) + memmove(field + ipos + 1, field + ipos, ilen - ipos); - field[ipos] = c; + field[ipos] = chc; ipos++; ilen++; - field[ipos] = '\0'; - session_output(session, mask ? &mask : (char *)&c, 1); + field[ilen] = '\0'; + session_output(session, mask ? &mask : (char *)&chc, 1); + + if (ipos < ilen) { + if (mask) { + /* TODO: repeat mask */ + } else { + session_output_string(session, + ansi(session, ANSI_SAVE_CURSOR, ANSI_END)); + session_output(session, field + ipos, + ilen - ipos); + session_output_string(session, + ansi(session, ANSI_RESTORE_SAVED_CURSOR, ANSI_END)); + } + } session_flush(session); } } @@ -456,7 +533,8 @@ session_multiline_input(struct session *session, short size_t size = 0, length = 0; size_t pos = 0; char *field = NULL; - unsigned char c, redraw = 0; + unsigned short c; + bool redraw = false; session->abort_input = 0; @@ -486,14 +564,14 @@ session_multiline_input(struct session *session, short goto multiline_input_bail; case CONTROL_D: /* ^D */ return field; - case 8: /* backspace / ^H */ - case 127: /* delete (through telnet) */ + case BACKSPACE: /* ^H */ + case DELETE: /* (backspace through telnet) */ if (pos == 0) continue; if (pos < length) { /* l:3 p:2 f:ab[cursor]c -> l:2 p:2 f:a[cursor]c */ - redraw = 1; + redraw = true; BlockMove((Ptr)(field + pos), (Ptr)(field + pos - 1), length - 1); } @@ -504,6 +582,7 @@ session_multiline_input(struct session *session, short if (redraw) { /* TODO */ + redraw = false; } else { session_output_string(session, ansi(session, ANSI_BACKSPACE, ANSI_END)); --- session.h Thu Jan 27 13:53:41 2022 +++ session.h Mon Feb 21 13:50:47 2022 @@ -35,8 +35,16 @@ enum session_input_state { #define CONTROL_C 3 #define CONTROL_D 4 +#define BACKSPACE 8 #define CONTROL_L 12 +#define DELETE 127 +#define KEY_UP (0x0100 | 'A') +#define KEY_DOWN (0x0100 | 'B') +#define KEY_RIGHT (0x0100 | 'C') +#define KEY_LEFT (0x0100 | 'D') +#define KEY_OTHER (0x0100 | 0xff) + struct node_funcs { void (*setup)(struct session *session); short (*input)(struct session *session); @@ -62,7 +70,7 @@ struct session { short obuflen; short ibuflen; enum session_input_state input_state; - unsigned char last_input; + unsigned short last_input; unsigned char abort_input; unsigned long last_input_at; unsigned short terminal_columns; @@ -91,7 +99,7 @@ struct session * session_create(char *node, char *via, struct node_funcs *node_funcs); void session_close(struct session *session); void session_idle(struct session *session); -char session_input_char(struct session *session); +unsigned short session_input_char(struct session *session); void session_flush(struct session *session); size_t session_output(struct session *session, const char *str, size_t len); size_t session_output_string(struct session *session, const char *str);