HelenOS sources
This source file includes following definitions.
- tinput_console_set_lpos
- tinput_new
- tinput_destroy
- tinput_display_prompt
- tinput_display_tail
- tinput_get_str
- tinput_position_caret
- tinput_update_origin_coord
- tinput_update_origin
- tinput_jump_after
- tinput_display
- tinput_insert_char
- tinput_insert_string
- tinput_backspace
- tinput_delete
- tinput_seek_cell
- tinput_seek_word
- tinput_seek_vertical
- tinput_seek_scrpos
- tinput_seek_max
- tinput_pre_seek
- tinput_post_seek
- tinput_history_insert
- tinput_set_str
- tinput_sel_get_bounds
- tinput_sel_active
- tinput_sel_all
- tinput_sel_delete
- tinput_sel_copy_to_cb
- tinput_paste_from_cb
- tinput_history_seek
- compl_cmp
- common_pref_len
- tinput_show_completions
- tinput_text_complete
- tinput_init
- tinput_set_prompt
- tinput_set_compl_ops
- tinput_key_press
- tinput_key_release
- tinput_pos
- tinput_resize
- tinput_read_i
- tinput_read
- tinput_key_ctrl
- tinput_key_ctrl_shift
- tinput_key_shift
- tinput_key_unmod
#include <stdio.h>
#include <stdlib.h>
#include <str.h>
#include <io/console.h>
#include <io/keycode.h>
#include <io/style.h>
#include <io/color.h>
#include <vfs/vfs.h>
#include <clipboard.h>
#include <macros.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>
#include <tinput.h>
#define LIN_TO_COL(ti, lpos) ((lpos) % ((ti)->con_cols))
#define LIN_TO_ROW(ti, lpos) ((lpos) / ((ti)->con_cols))
#define LIN_POS(ti, col, row) ((col) + (row) * (ti)->con_cols)
typedef enum {
seek_backward = -1,
seek_forward = 1
} seek_dir_t;
static void tinput_update_origin(tinput_t *);
static void tinput_init(tinput_t *);
static void tinput_insert_string(tinput_t *, const char *);
static void tinput_sel_get_bounds(tinput_t *, size_t *, size_t *);
static bool tinput_sel_active(tinput_t *);
static void tinput_sel_all(tinput_t *);
static void tinput_sel_delete(tinput_t *);
static void tinput_key_ctrl(tinput_t *, kbd_event_t *);
static void tinput_key_shift(tinput_t *, kbd_event_t *);
static void tinput_key_ctrl_shift(tinput_t *, kbd_event_t *);
static void tinput_key_unmod(tinput_t *, kbd_event_t *);
static void tinput_pre_seek(tinput_t *, bool);
static void tinput_post_seek(tinput_t *, bool);
static void tinput_console_set_lpos(tinput_t *ti, unsigned lpos)
{
unsigned col = LIN_TO_COL(ti, lpos);
unsigned row = LIN_TO_ROW(ti, lpos);
assert(col < ti->con_cols);
assert(row < ti->con_rows);
console_set_pos(ti->console, col, row);
}
tinput_t *tinput_new(void)
{
tinput_t *ti;
ti = calloc(1, sizeof(tinput_t));
if (ti == NULL)
return NULL;
tinput_init(ti);
return ti;
}
void tinput_destroy(tinput_t *ti)
{
if (ti->prompt != NULL)
free(ti->prompt);
free(ti);
}
static void tinput_display_prompt(tinput_t *ti)
{
tinput_console_set_lpos(ti, ti->prompt_coord);
console_set_style(ti->console, STYLE_EMPHASIS);
printf("%s", ti->prompt);
console_flush(ti->console);
console_set_style(ti->console, STYLE_NORMAL);
}
static void tinput_display_tail(tinput_t *ti, size_t start, size_t pad)
{
char32_t stash;
size_t sa;
size_t sb;
tinput_sel_get_bounds(ti, &sa, &sb);
assert(sa <= sb);
tinput_console_set_lpos(ti, ti->text_coord + start);
console_set_style(ti->console, STYLE_NORMAL);
sa = max(start, sa);
sb = max(start, sb);
if (start < sa) {
stash = ti->buffer[sa];
ti->buffer[sa] = L'\0';
printf("%ls", &ti->buffer[start]);
ti->buffer[sa] = stash;
}
if (sa < sb) {
console_flush(ti->console);
console_set_style(ti->console, STYLE_SELECTED);
stash = ti->buffer[sb];
ti->buffer[sb] = L'\0';
printf("%ls", &ti->buffer[sa]);
ti->buffer[sb] = stash;
console_flush(ti->console);
console_set_style(ti->console, STYLE_NORMAL);
}
if (sb < ti->nc) {
ti->buffer[ti->nc] = L'\0';
printf("%ls", &ti->buffer[sb]);
}
for (; pad > 0; pad--)
putuchar(' ');
console_flush(ti->console);
}
static char *tinput_get_str(tinput_t *ti)
{
return wstr_to_astr(ti->buffer);
}
static void tinput_position_caret(tinput_t *ti)
{
tinput_update_origin(ti);
tinput_console_set_lpos(ti, ti->text_coord + ti->pos);
}
static void tinput_update_origin_coord(tinput_t *ti, unsigned end_coord)
{
unsigned end_row = LIN_TO_ROW(ti, end_coord);
unsigned scroll_rows;
if (end_row >= ti->con_rows) {
scroll_rows = end_row - ti->con_rows + 1;
ti->text_coord -= ti->con_cols * scroll_rows;
ti->prompt_coord -= ti->con_cols * scroll_rows;
}
}
static void tinput_update_origin(tinput_t *ti)
{
tinput_update_origin_coord(ti, ti->text_coord + ti->nc);
}
static void tinput_jump_after(tinput_t *ti)
{
tinput_console_set_lpos(ti, ti->text_coord + ti->nc);
console_flush(ti->console);
putuchar('\n');
}
static errno_t tinput_display(tinput_t *ti)
{
sysarg_t col0, row0;
if (console_get_pos(ti->console, &col0, &row0) != EOK)
return EIO;
ti->prompt_coord = row0 * ti->con_cols + col0;
ti->text_coord = ti->prompt_coord;
tinput_display_prompt(ti);
tinput_update_origin_coord(ti, ti->prompt_coord + str_width(ti->prompt));
ti->text_coord = ti->prompt_coord + str_length(ti->prompt);
tinput_display_tail(ti, 0, 0);
tinput_update_origin(ti);
tinput_position_caret(ti);
return EOK;
}
static void tinput_insert_char(tinput_t *ti, char32_t c)
{
if (ti->nc == INPUT_MAX_SIZE)
return;
unsigned prompt_len = ti->text_coord - ti->prompt_coord;
if (prompt_len + ti->nc + 1 >= ti->con_cols * ti->con_rows)
return;
size_t i;
for (i = ti->nc; i > ti->pos; i--)
ti->buffer[i] = ti->buffer[i - 1];
ti->buffer[ti->pos] = c;
ti->pos += 1;
ti->nc += 1;
ti->buffer[ti->nc] = '\0';
ti->sel_start = ti->pos;
tinput_display_tail(ti, ti->pos - 1, 0);
tinput_position_caret(ti);
}
static void tinput_insert_string(tinput_t *ti, const char *str)
{
size_t ilen = min(str_length(str), INPUT_MAX_SIZE - ti->nc);
if (ilen == 0)
return;
unsigned new_width = LIN_TO_COL(ti, ti->text_coord) + ti->nc + ilen;
unsigned new_height = (new_width / ti->con_cols) + 1;
if (new_height >= ti->con_rows) {
return;
}
if (ti->nc > 0) {
size_t i;
for (i = ti->nc; i > ti->pos; i--)
ti->buffer[i + ilen - 1] = ti->buffer[i - 1];
}
size_t off = 0;
size_t i = 0;
while (i < ilen) {
char32_t c = str_decode(str, &off, STR_NO_LIMIT);
if (c == '\0')
break;
if (c < 32)
c = 32;
ti->buffer[ti->pos + i] = c;
i++;
}
ti->pos += ilen;
ti->nc += ilen;
ti->buffer[ti->nc] = '\0';
ti->sel_start = ti->pos;
tinput_display_tail(ti, ti->pos - ilen, 0);
tinput_position_caret(ti);
}
static void tinput_backspace(tinput_t *ti)
{
if (tinput_sel_active(ti)) {
tinput_sel_delete(ti);
return;
}
if (ti->pos == 0)
return;
size_t i;
for (i = ti->pos; i < ti->nc; i++)
ti->buffer[i - 1] = ti->buffer[i];
ti->pos -= 1;
ti->nc -= 1;
ti->buffer[ti->nc] = '\0';
ti->sel_start = ti->pos;
tinput_display_tail(ti, ti->pos, 1);
tinput_position_caret(ti);
}
static void tinput_delete(tinput_t *ti)
{
if (tinput_sel_active(ti)) {
tinput_sel_delete(ti);
return;
}
if (ti->pos == ti->nc)
return;
ti->pos += 1;
ti->sel_start = ti->pos;
tinput_backspace(ti);
}
static void tinput_seek_cell(tinput_t *ti, seek_dir_t dir, bool shift_held)
{
tinput_pre_seek(ti, shift_held);
if (dir == seek_forward) {
if (ti->pos < ti->nc)
ti->pos += 1;
} else {
if (ti->pos > 0)
ti->pos -= 1;
}
tinput_post_seek(ti, shift_held);
}
static void tinput_seek_word(tinput_t *ti, seek_dir_t dir, bool shift_held)
{
tinput_pre_seek(ti, shift_held);
if (dir == seek_forward) {
if (ti->pos == ti->nc)
return;
while (true) {
ti->pos += 1;
if (ti->pos == ti->nc)
break;
if ((ti->buffer[ti->pos - 1] == ' ') &&
(ti->buffer[ti->pos] != ' '))
break;
}
} else {
if (ti->pos == 0)
return;
while (true) {
ti->pos -= 1;
if (ti->pos == 0)
break;
if (ti->buffer[ti->pos - 1] == ' ' &&
ti->buffer[ti->pos] != ' ')
break;
}
}
tinput_post_seek(ti, shift_held);
}
static void tinput_seek_vertical(tinput_t *ti, seek_dir_t dir, bool shift_held)
{
tinput_pre_seek(ti, shift_held);
if (dir == seek_forward) {
if (ti->pos + ti->con_cols <= ti->nc)
ti->pos = ti->pos + ti->con_cols;
} else {
if (ti->pos >= ti->con_cols)
ti->pos = ti->pos - ti->con_cols;
}
tinput_post_seek(ti, shift_held);
}
static void tinput_seek_scrpos(tinput_t *ti, int col, int line, bool shift_held)
{
unsigned lpos;
tinput_pre_seek(ti, shift_held);
lpos = LIN_POS(ti, col, line);
if (lpos > ti->text_coord)
ti->pos = lpos - ti->text_coord;
else
ti->pos = 0;
if (ti->pos > ti->nc)
ti->pos = ti->nc;
tinput_post_seek(ti, shift_held);
}
static void tinput_seek_max(tinput_t *ti, seek_dir_t dir, bool shift_held)
{
tinput_pre_seek(ti, shift_held);
if (dir == seek_backward)
ti->pos = 0;
else
ti->pos = ti->nc;
tinput_post_seek(ti, shift_held);
}
static void tinput_pre_seek(tinput_t *ti, bool shift_held)
{
if ((tinput_sel_active(ti)) && (!shift_held)) {
ti->sel_start = ti->pos;
tinput_display_tail(ti, 0, 0);
tinput_position_caret(ti);
}
}
static void tinput_post_seek(tinput_t *ti, bool shift_held)
{
if (shift_held) {
tinput_display_tail(ti, 0, 0);
} else {
ti->sel_start = ti->pos;
}
tinput_position_caret(ti);
}
static void tinput_history_insert(tinput_t *ti, char *str)
{
if (ti->hnum < HISTORY_LEN) {
ti->hnum += 1;
} else {
if (ti->history[HISTORY_LEN] != NULL)
free(ti->history[HISTORY_LEN]);
}
size_t i;
for (i = ti->hnum; i > 1; i--)
ti->history[i] = ti->history[i - 1];
ti->history[1] = str_dup(str);
if (ti->history[0] != NULL) {
free(ti->history[0]);
ti->history[0] = NULL;
}
}
static void tinput_set_str(tinput_t *ti, const char *str)
{
str_to_wstr(ti->buffer, INPUT_MAX_SIZE, str);
ti->nc = wstr_length(ti->buffer);
ti->pos = ti->nc;
ti->sel_start = ti->pos;
}
static void tinput_sel_get_bounds(tinput_t *ti, size_t *sa, size_t *sb)
{
if (ti->sel_start < ti->pos) {
*sa = ti->sel_start;
*sb = ti->pos;
} else {
*sa = ti->pos;
*sb = ti->sel_start;
}
}
static bool tinput_sel_active(tinput_t *ti)
{
return (ti->sel_start != ti->pos);
}
static void tinput_sel_all(tinput_t *ti)
{
ti->sel_start = 0;
ti->pos = ti->nc;
tinput_display_tail(ti, 0, 0);
tinput_position_caret(ti);
}
static void tinput_sel_delete(tinput_t *ti)
{
size_t sa;
size_t sb;
tinput_sel_get_bounds(ti, &sa, &sb);
if (sa == sb)
return;
memmove(ti->buffer + sa, ti->buffer + sb,
(ti->nc - sb) * sizeof(char32_t));
ti->pos = ti->sel_start = sa;
ti->nc -= (sb - sa);
ti->buffer[ti->nc] = '\0';
tinput_display_tail(ti, sa, sb - sa);
tinput_position_caret(ti);
}
static void tinput_sel_copy_to_cb(tinput_t *ti)
{
size_t sa;
size_t sb;
tinput_sel_get_bounds(ti, &sa, &sb);
char *str;
if (sb < ti->nc) {
char32_t tmp_c = ti->buffer[sb];
ti->buffer[sb] = '\0';
str = wstr_to_astr(ti->buffer + sa);
ti->buffer[sb] = tmp_c;
} else
str = wstr_to_astr(ti->buffer + sa);
if (str == NULL)
goto error;
if (clipboard_put_str(str) != EOK)
goto error;
free(str);
return;
error:
return;
}
static void tinput_paste_from_cb(tinput_t *ti)
{
char *str;
errno_t rc = clipboard_get_str(&str);
if ((rc != EOK) || (str == NULL)) {
return;
}
tinput_insert_string(ti, str);
free(str);
}
static void tinput_history_seek(tinput_t *ti, int offs)
{
if (offs >= 0) {
if (ti->hpos + offs > ti->hnum)
return;
} else {
if (ti->hpos < (size_t) -offs)
return;
}
if (ti->history[ti->hpos] != NULL) {
free(ti->history[ti->hpos]);
ti->history[ti->hpos] = NULL;
}
ti->history[ti->hpos] = tinput_get_str(ti);
ti->hpos += offs;
int pad = (int) ti->nc - str_length(ti->history[ti->hpos]);
if (pad < 0)
pad = 0;
tinput_set_str(ti, ti->history[ti->hpos]);
tinput_display_tail(ti, 0, pad);
tinput_update_origin(ti);
tinput_position_caret(ti);
}
static int compl_cmp(const void *va, const void *vb)
{
const char *a = *(const char **) va;
const char *b = *(const char **) vb;
return str_cmp(a, b);
}
static size_t common_pref_len(const char *a, const char *b)
{
size_t i;
size_t a_off, b_off;
char32_t ca, cb;
i = 0;
a_off = 0;
b_off = 0;
while (true) {
ca = str_decode(a, &a_off, STR_NO_LIMIT);
cb = str_decode(b, &b_off, STR_NO_LIMIT);
if (ca == '\0' || cb == '\0' || ca != cb)
break;
++i;
}
return i;
}
static void tinput_show_completions(tinput_t *ti, char **compl, size_t cnum)
{
unsigned int i;
size_t max_width = 0;
for (i = 0; i < cnum; i++)
max_width = max(max_width, str_width(compl[i]));
unsigned int cols = max(1, (ti->con_cols + 1) / (max_width + 1));
unsigned int padding = 0;
if (cols * max_width + (cols - 1) < ti->con_cols) {
padding = ti->con_cols - cols * max_width - (cols - 1);
}
unsigned int col_width = max_width + padding / cols;
unsigned int rows = cnum / cols + ((cnum % cols) != 0);
unsigned int row, col;
for (row = 0; row < rows; row++) {
unsigned int display_col = 0;
for (col = 0; col < cols; col++) {
size_t compl_idx = col * rows + row;
if (compl_idx >= cnum)
break;
if (col) {
printf(" ");
display_col++;
}
printf("%s", compl[compl_idx]);
size_t compl_width = str_width(compl[compl_idx]);
display_col += compl_width;
if (col < cols - 1) {
for (i = compl_width; i < col_width; i++) {
printf(" ");
display_col++;
}
}
}
if ((display_col % ti->con_cols) > 0)
printf("\n");
}
fflush(stdout);
}
static void tinput_text_complete(tinput_t *ti)
{
void *state;
size_t cstart;
char *ctmp;
char **compl;
size_t compl_len;
size_t cnum;
size_t i;
errno_t rc;
if (ti->compl_ops == NULL)
return;
rc = (*ti->compl_ops->init)(ti->buffer, ti->pos, &cstart, &state);
if (rc != EOK)
return;
cnum = 0;
compl_len = 1;
compl = malloc(compl_len * sizeof(char *));
if (compl == NULL) {
printf("Error: Out of memory.\n");
return;
}
while (true) {
rc = (*ti->compl_ops->get_next)(state, &ctmp);
if (rc != EOK)
break;
if (cnum >= compl_len) {
compl_len = 2 * compl_len;
char **temp = realloc(compl, compl_len * sizeof(char *));
if (temp == NULL) {
free(compl);
printf("Error: Out of memory.\n");
break;
}
compl = temp;
}
compl[cnum] = str_dup(ctmp);
if (compl[cnum] == NULL) {
printf("Error: Out of memory.\n");
break;
}
cnum++;
}
(*ti->compl_ops->fini)(state);
if (cnum > 1) {
size_t cplen;
cplen = str_length(compl[0]);
for (i = 1; i < cnum; i++)
cplen = min(cplen, common_pref_len(compl[0], compl[i]));
size_t istart = str_lsize(compl[0], ti->pos - cstart);
if (cplen > istart) {
char *cpref = str_ndup(compl[0] + istart,
str_lsize(compl[0], cplen - istart));
tinput_insert_string(ti, cpref);
free(cpref);
} else {
qsort(compl, cnum, sizeof(char *), compl_cmp);
tinput_jump_after(ti);
tinput_show_completions(ti, compl, cnum);
tinput_display(ti);
}
} else if (cnum == 1) {
size_t istart = str_lsize(compl[0], ti->pos - cstart);
tinput_insert_string(ti, compl[0] + istart);
}
for (i = 0; i < cnum; i++)
free(compl[i]);
free(compl);
}
static void tinput_init(tinput_t *ti)
{
ti->console = console_init(stdin, stdout);
ti->hnum = 0;
ti->hpos = 0;
ti->history[0] = NULL;
}
errno_t tinput_set_prompt(tinput_t *ti, const char *prompt)
{
if (ti->prompt != NULL)
free(ti->prompt);
ti->prompt = str_dup(prompt);
if (ti->prompt == NULL)
return ENOMEM;
return EOK;
}
void tinput_set_compl_ops(tinput_t *ti, tinput_compl_ops_t *compl_ops)
{
ti->compl_ops = compl_ops;
}
static void tinput_key_press(tinput_t *ti, kbd_event_t *kev)
{
if (kev->key == KC_LSHIFT)
ti->lshift_held = true;
if (kev->key == KC_RSHIFT)
ti->rshift_held = true;
if (((kev->mods & KM_CTRL) != 0) &&
((kev->mods & (KM_ALT | KM_SHIFT)) == 0))
tinput_key_ctrl(ti, kev);
if (((kev->mods & KM_SHIFT) != 0) &&
((kev->mods & (KM_CTRL | KM_ALT)) == 0))
tinput_key_shift(ti, kev);
if (((kev->mods & KM_CTRL) != 0) &&
((kev->mods & KM_SHIFT) != 0) &&
((kev->mods & KM_ALT) == 0))
tinput_key_ctrl_shift(ti, kev);
if ((kev->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0)
tinput_key_unmod(ti, kev);
if (((kev->mods & (KM_CTRL | KM_ALT)) == 0) && kev->c >= ' ') {
tinput_sel_delete(ti);
tinput_insert_char(ti, kev->c);
}
}
static void tinput_key_release(tinput_t *ti, kbd_event_t *kev)
{
if (kev->key == KC_LSHIFT)
ti->lshift_held = false;
if (kev->key == KC_RSHIFT)
ti->rshift_held = false;
}
static void tinput_pos(tinput_t *ti, pos_event_t *ev)
{
if (ev->type == POS_PRESS) {
tinput_seek_scrpos(ti, ev->hpos, ev->vpos,
ti->lshift_held || ti->rshift_held);
}
}
static errno_t tinput_resize(tinput_t *ti)
{
assert(ti->prompt_coord % ti->con_cols == 0);
errno_t rc = console_get_size(ti->console, &ti->con_cols, &ti->con_rows);
if (rc != EOK)
return rc;
sysarg_t col, row;
rc = console_get_pos(ti->console, &col, &row);
if (rc != EOK)
return rc;
assert(ti->prompt_coord <= ti->text_coord);
unsigned prompt_len = ti->text_coord - ti->prompt_coord;
size_t new_caret_coord = row * ti->con_cols + col;
if (prompt_len <= new_caret_coord && ti->pos <= new_caret_coord - prompt_len) {
ti->text_coord = new_caret_coord - ti->pos;
ti->prompt_coord = ti->text_coord - prompt_len;
unsigned prompt_col = ti->prompt_coord % ti->con_cols;
if (prompt_col != 0) {
fprintf(stderr, "Unexpected prompt position after resize.\n");
ti->prompt_coord -= prompt_col;
ti->text_coord -= prompt_col;
console_cursor_visibility(ti->console, false);
tinput_display_prompt(ti);
tinput_display_tail(ti, 0, prompt_col);
tinput_position_caret(ti);
console_cursor_visibility(ti->console, true);
}
assert(ti->prompt_coord % ti->con_cols == 0);
} else {
console_clear(ti->console);
ti->nc = min(ti->nc, ti->con_cols * ti->con_rows - prompt_len - 1);
ti->pos = min(ti->pos, ti->nc);
ti->sel_start = min(ti->sel_start, ti->nc);
ti->prompt_coord = 0;
ti->text_coord = prompt_len;
console_cursor_visibility(ti->console, false);
tinput_display_prompt(ti);
tinput_display_tail(ti, 0, 0);
tinput_position_caret(ti);
console_cursor_visibility(ti->console, true);
}
assert(ti->nc + ti->text_coord < ti->con_cols * ti->con_rows);
return EOK;
}
errno_t tinput_read_i(tinput_t *ti, const char *istr, char **dstr)
{
errno_t rc;
console_flush(ti->console);
if (console_get_size(ti->console, &ti->con_cols, &ti->con_rows) != EOK)
return EIO;
tinput_set_str(ti, istr);
ti->sel_start = 0;
ti->done = false;
ti->exit_clui = false;
if (tinput_display(ti) != EOK)
return EIO;
while (!ti->done) {
console_flush(ti->console);
cons_event_t ev;
rc = console_get_event(ti->console, &ev);
if (rc != EOK)
return EIO;
switch (ev.type) {
case CEV_KEY:
if (ev.ev.key.type == KEY_PRESS)
tinput_key_press(ti, &ev.ev.key);
else
tinput_key_release(ti, &ev.ev.key);
break;
case CEV_POS:
tinput_pos(ti, &ev.ev.pos);
break;
case CEV_RESIZE:
tinput_resize(ti);
break;
}
}
if (ti->exit_clui)
return ENOENT;
ti->pos = ti->nc;
tinput_position_caret(ti);
putchar('\n');
char *str = tinput_get_str(ti);
if (str_cmp(str, "") != 0)
tinput_history_insert(ti, str);
ti->hpos = 0;
*dstr = str;
return EOK;
}
errno_t tinput_read(tinput_t *ti, char **dstr)
{
return tinput_read_i(ti, "", dstr);
}
static void tinput_key_ctrl(tinput_t *ti, kbd_event_t *ev)
{
switch (ev->key) {
case KC_LEFT:
tinput_seek_word(ti, seek_backward, false);
break;
case KC_RIGHT:
tinput_seek_word(ti, seek_forward, false);
break;
case KC_UP:
tinput_seek_vertical(ti, seek_backward, false);
break;
case KC_DOWN:
tinput_seek_vertical(ti, seek_forward, false);
break;
case KC_X:
tinput_sel_copy_to_cb(ti);
tinput_sel_delete(ti);
break;
case KC_C:
tinput_sel_copy_to_cb(ti);
break;
case KC_V:
tinput_sel_delete(ti);
tinput_paste_from_cb(ti);
break;
case KC_A:
tinput_sel_all(ti);
break;
case KC_Q:
ti->done = true;
ti->exit_clui = true;
break;
default:
break;
}
}
static void tinput_key_ctrl_shift(tinput_t *ti, kbd_event_t *ev)
{
switch (ev->key) {
case KC_LEFT:
tinput_seek_word(ti, seek_backward, true);
break;
case KC_RIGHT:
tinput_seek_word(ti, seek_forward, true);
break;
case KC_UP:
tinput_seek_vertical(ti, seek_backward, true);
break;
case KC_DOWN:
tinput_seek_vertical(ti, seek_forward, true);
break;
default:
break;
}
}
static void tinput_key_shift(tinput_t *ti, kbd_event_t *ev)
{
switch (ev->key) {
case KC_LEFT:
tinput_seek_cell(ti, seek_backward, true);
break;
case KC_RIGHT:
tinput_seek_cell(ti, seek_forward, true);
break;
case KC_UP:
tinput_seek_vertical(ti, seek_backward, true);
break;
case KC_DOWN:
tinput_seek_vertical(ti, seek_forward, true);
break;
case KC_HOME:
tinput_seek_max(ti, seek_backward, true);
break;
case KC_END:
tinput_seek_max(ti, seek_forward, true);
break;
default:
break;
}
}
static void tinput_key_unmod(tinput_t *ti, kbd_event_t *ev)
{
switch (ev->key) {
case KC_ENTER:
case KC_NENTER:
ti->done = true;
break;
case KC_BACKSPACE:
tinput_backspace(ti);
break;
case KC_DELETE:
tinput_delete(ti);
break;
case KC_LEFT:
tinput_seek_cell(ti, seek_backward, false);
break;
case KC_RIGHT:
tinput_seek_cell(ti, seek_forward, false);
break;
case KC_HOME:
tinput_seek_max(ti, seek_backward, false);
break;
case KC_END:
tinput_seek_max(ti, seek_forward, false);
break;
case KC_UP:
tinput_history_seek(ti, 1);
break;
case KC_DOWN:
tinput_history_seek(ti, -1);
break;
case KC_TAB:
tinput_text_complete(ti);
break;
default:
break;
}
}
HelenOS homepage, sources at GitHub