2021-09-25 16:02:50 +02:00
|
|
|
#include "vxBoot/terminal.h"
|
|
|
|
|
|
|
|
#include <gint/keyboard.h>
|
|
|
|
#include <gint/display.h>
|
|
|
|
#include <gint/timer.h>
|
2021-12-18 13:52:13 +01:00
|
|
|
#include <gint/cpu.h>
|
2021-09-25 16:02:50 +02:00
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
2021-12-18 13:52:13 +01:00
|
|
|
static int __lock = 0;
|
|
|
|
|
|
|
|
/* ugly workaround to avoid race condition with the timer */
|
|
|
|
cpu_atomic_start();
|
|
|
|
if (__lock != 0) {
|
|
|
|
cpu_atomic_end();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
__lock = 1;
|
|
|
|
cpu_atomic_end();
|
|
|
|
|
2021-09-25 16:02:50 +02:00
|
|
|
/* 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);
|
2021-12-18 13:52:13 +01:00
|
|
|
|
|
|
|
/* workaround end */
|
|
|
|
__lock = 0;
|
2021-09-25 16:02:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//---
|
|
|
|
// 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 */
|
2021-12-18 13:52:13 +01:00
|
|
|
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1) {
|
2021-09-25 16:02:50 +02:00
|
|
|
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 */
|
2021-12-18 13:52:13 +01:00
|
|
|
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1) {
|
2021-09-25 16:02:50 +02:00
|
|
|
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:
|
2021-12-18 13:52:13 +01:00
|
|
|
if (term_rdinfo.buffer.cursor < (int)term_rdinfo.buffer.size - 1)
|
2021-09-25 16:02:50 +02:00
|
|
|
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 */
|
2021-12-18 13:52:13 +01:00
|
|
|
term_rdinfo.cursor.visible = 1;
|
2021-09-25 16:02:50 +02:00
|
|
|
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);
|
2021-12-18 13:52:13 +01:00
|
|
|
else
|
|
|
|
term_display_all(); // force-display the cursor
|
2021-09-25 16:02:50 +02:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|