vxBoot/src/terminal/read.c

246 lines
6.1 KiB
C

#include "vxBoot/terminal.h"
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/timer.h>
#include <string.h>
/* 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);
}