//--- // fxBoot:terminal:read - Read primitive for the terminal device //--- #include "fxBoot/terminal.h" #include #include #include #include /* internal structure used to store many information */ struct { struct { unsigned short x; unsigned short y; int visible; off_t saved; } cursor; struct { uint8_t alpha: 1; uint8_t shift: 1; uint8_t ctrl: 1; uint8_t exit: 1; uint8_t const: 4; } mode; struct { size_t max; size_t size; off_t cursor; char *data; } buffer; } term_rdinfo; //--- // //--- void term_display_all(void) { /* stop the timer too avoid interrupt-loop */ if (terminal.private.timer.id >= 0) timer_pause(terminal.private.timer.id); /* mark special characte that the cursor is here */ if (term_rdinfo.cursor.visible == 1) term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] |= 0x80; /* restore terminal context */ terminal.cursor.x = term_rdinfo.cursor.x; terminal.cursor.y = term_rdinfo.cursor.y; terminal.buffer.cursor = term_rdinfo.cursor.saved; terminal_buffer_insert(term_rdinfo.buffer.data, term_rdinfo.buffer.size); /* display management */ dclear(terminal.private.color.bg); terminal_buffer_display(); dupdate(); /* remove cursor mark */ term_rdinfo.buffer.data[term_rdinfo.buffer.cursor] &= ~0x80; /* restart the timer */ if (terminal.private.timer.id >= 0) timer_start(terminal.private.timer.id); } //--- // Callback function //--- int terminal_cursor_handler(void) { term_rdinfo.cursor.visible ^= 1; term_display_all(); return (0); } //--- // buffer functions //--- /* term_buffer_remove(): Remove character based on current cursor position */ static void term_buffer_remove(void) { /* check if this action is possible */ if (term_rdinfo.buffer.cursor == 0) return; /* move data if needed */ if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) { memcpy( &term_rdinfo.buffer.data[term_rdinfo.buffer.cursor - 1], &term_rdinfo.buffer.data[term_rdinfo.buffer.cursor], term_rdinfo.buffer.size - term_rdinfo.buffer.cursor ); } /* force NULL-char and update cursor/size */ term_rdinfo.buffer.cursor = term_rdinfo.buffer.cursor - 1; term_rdinfo.buffer.data[--term_rdinfo.buffer.size - 1] = '\0'; } /* term_buffer_insert() - Insert character based on current cursor position */ static int term_buffer_insert(char n) { /* save space for the "\n\0" (EOL) */ if (term_rdinfo.buffer.size + 1 >= term_rdinfo.buffer.max) return (-1); /* move data if needed */ if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) { off_t i = term_rdinfo.buffer.size + 1; while (--i >= term_rdinfo.buffer.cursor) { term_rdinfo.buffer.data[i] = term_rdinfo.buffer.data[i - 1]; } } /* insert the character and force NULL-char */ term_rdinfo.buffer.data[term_rdinfo.buffer.cursor++] = n; term_rdinfo.buffer.data[++term_rdinfo.buffer.size] = '\0'; return (0); } //--- // key handling //--- // TODO // - F_UP -> history // - F_DOWN -> history static int term_key_handle_special(key_event_t key_event) { switch (key_event.key) { case KEY_SHIFT: term_rdinfo.mode.shift ^= 1; return (1); case KEY_ALPHA: term_rdinfo.mode.alpha ^= 1; return (1); case KEY_OPTN: term_rdinfo.mode.ctrl ^= 1; return (1); case KEY_DOT: term_buffer_insert(' '); return (1); case KEY_DEL: term_buffer_remove(); return (1); case KEY_EXE: /* Add End Of Line character */ term_rdinfo.buffer.data[term_rdinfo.buffer.size - 1] = '\n'; term_rdinfo.buffer.data[term_rdinfo.buffer.size] = '\0'; /* indicate that the EXE key has been pressed. */ term_rdinfo.mode.exit = 1; return (1); case KEY_LEFT: if (term_rdinfo.buffer.cursor > 0) term_rdinfo.buffer.cursor -= 1; return (1); case KEY_RIGHT: if (term_rdinfo.buffer.cursor < term_rdinfo.buffer.size - 1) term_rdinfo.buffer.cursor += 1; return (1); default: return (0); } } /* term_buffer_update() - Update the internal buffer with the given key code */ static int term_key_buffer_update(key_event_t key_event) { static const uint8_t keylist_alpha[] = { KEY_XOT, KEY_LOG, KEY_LN, KEY_SIN, KEY_COS, KEY_TAN, KEY_FRAC, KEY_FD, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_ARROW, KEY_7, KEY_8, KEY_9, KEY_4, KEY_5, KEY_6, KEY_MUL, KEY_DIV, KEY_1, KEY_2, KEY_3, KEY_PLUS, KEY_MINUS, KEY_0, 0xff }; static const uint8_t keylist_num[] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_PLUS, KEY_MINUS, KEY_MUL, KEY_DIV, KEY_LEFTP, KEY_RIGHTP, KEY_COMMA, KEY_POWER, KEY_DOT, KEY_FD, KEY_ARROW, 0xff }; static const char keylist_num_char[] = "0123456789+-x/(),^.|_"; const uint8_t *keycode_list; char character; int i; /* Get the appropriate key list. */ keycode_list = keylist_alpha; if (term_rdinfo.mode.shift == 1) keycode_list = keylist_num; /* Try to find the pressed key. */ i = -1; while (keycode_list[++i] != 0xff && keycode_list[i] != key_event.key); if (keycode_list[i] != key_event.key) return (0); /* handle mode then update the buffer */ if (term_rdinfo.mode.shift == 0) { character = 'a' + i; if (term_rdinfo.mode.alpha == 1) character = 'A' + i;; } else { character = keylist_num_char[i]; } term_buffer_insert(character); return (1); } //--- // primitive //--- int terminal_read(void *buffer, size_t nb) { key_event_t key; /* check obvious error */ if (buffer == NULL || nb == 0) return (0); /* initialize internal data */ memset(&term_rdinfo, 0x00, sizeof(term_rdinfo)); memset(buffer, 0x00, nb); /* save terminal information */ term_rdinfo.cursor.saved = terminal.buffer.cursor; term_rdinfo.cursor.x = terminal.cursor.x; term_rdinfo.cursor.y = terminal.cursor.y; term_rdinfo.buffer.data = buffer; term_rdinfo.buffer.size = 1; term_rdinfo.buffer.max = nb; /* start cursor blink timer */ if (terminal.private.timer.id >= 0) timer_start(terminal.private.timer.id); /* keyboard handling */ while (term_rdinfo.mode.exit == 0) { /* handle pressed keys */ key = getkey_opt(GETKEY_REP_ALL | GETKEY_MENU, NULL); if (term_key_handle_special(key) == 0) term_key_buffer_update(key); /* display */ term_display_all(); } /* stop the timer */ if (terminal.private.timer.id >= 0) timer_pause(terminal.private.timer.id); return (term_rdinfo.buffer.size); }