2019-01-05 19:40:26 +01:00
|
|
|
/************************************************************************************
|
2021-06-10 18:40:35 +02:00
|
|
|
* apps/system/termcurses/tcurses_vt100.c
|
2019-01-05 19:40:26 +01:00
|
|
|
*
|
2021-06-10 13:17:16 +02:00
|
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
|
|
* this work for additional information regarding copyright ownership. The
|
|
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
|
|
* "License"); you may not use this file except in compliance with the
|
|
|
|
* License. You may obtain a copy of the License at
|
2019-01-05 19:40:26 +01:00
|
|
|
*
|
2021-06-10 13:17:16 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2019-01-05 19:40:26 +01:00
|
|
|
*
|
2021-06-10 13:17:16 +02:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
2019-01-05 19:40:26 +01:00
|
|
|
*
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Included Files
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/select.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "tcurses_priv.h"
|
|
|
|
#include "graphics/curses.h"
|
|
|
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Pre-processor Definitions
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
#define KEY_DOWN 0x102 /* Down arrow key */
|
|
|
|
#define KEY_UP 0x103 /* Up arrow key */
|
|
|
|
#define KEY_LEFT 0x104 /* Left arrow key */
|
|
|
|
#define KEY_RIGHT 0x105 /* Right arrow key */
|
|
|
|
#define KEY_HOME 0x106 /* home key */
|
|
|
|
#define KEY_F0 0x108 /* function keys; 64 reserved */
|
|
|
|
|
|
|
|
#ifdef CONFIG_TERMINFO_INCLUDE_NAME
|
|
|
|
#define TINFO_ENTRY(n, d, c) n, d, c
|
|
|
|
#else
|
|
|
|
#define TINFO_ENTRY(n, d, c) d, c
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Private Types
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
struct tcurses_vt100_s
|
|
|
|
{
|
|
|
|
struct termcurses_dev_s dev; /* The parent TermCurses struct */
|
|
|
|
|
|
|
|
/* Other control variables go here */
|
|
|
|
|
|
|
|
int in_fd;
|
|
|
|
int out_fd;
|
|
|
|
int keycount;
|
|
|
|
char keybuf[16];
|
|
|
|
};
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static FAR struct termcurses_s *tcurses_vt100_initialize(int in_fd, int out_fd);
|
|
|
|
static int tcurses_vt100_clear(FAR struct termcurses_s *dev, int type);
|
|
|
|
static int tcurses_vt100_move(FAR struct termcurses_s *dev, int type, int col,
|
|
|
|
int row);
|
|
|
|
static int tcurses_vt100_getwinsize(FAR struct termcurses_s *dev,
|
|
|
|
FAR struct winsize *winsz);
|
|
|
|
static int tcurses_vt100_setcolors(FAR struct termcurses_s *dev,
|
|
|
|
FAR struct termcurses_colors_s *colors);
|
|
|
|
static int tcurses_vt100_setattributes(FAR struct termcurses_s *dev,
|
|
|
|
unsigned long attrib);
|
|
|
|
static int tcurses_vt100_getkeycode(FAR struct termcurses_s *dev,
|
|
|
|
FAR int *specialkey, FAR int *keymodifers);
|
2019-01-08 15:21:39 +01:00
|
|
|
static bool tcurses_vt100_checkkey(FAR struct termcurses_s *dev);
|
2021-08-22 13:50:50 +02:00
|
|
|
static int tcurses_vt100_terminate(FAR struct termcurses_s *dev);
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Private Data
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static const struct termcurses_ops_s g_vt100_ops =
|
|
|
|
{
|
|
|
|
tcurses_vt100_initialize, /* Initialize operator */
|
|
|
|
tcurses_vt100_clear,
|
|
|
|
tcurses_vt100_move,
|
|
|
|
tcurses_vt100_getwinsize,
|
|
|
|
tcurses_vt100_setcolors,
|
|
|
|
tcurses_vt100_setattributes,
|
2019-01-08 15:21:39 +01:00
|
|
|
tcurses_vt100_getkeycode,
|
2021-08-22 13:50:50 +02:00
|
|
|
tcurses_vt100_checkkey,
|
|
|
|
tcurses_vt100_terminate
|
2019-01-05 19:40:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/* VT100 terminal codes */
|
|
|
|
|
|
|
|
static const char *g_clrscr = "\033[2J"; /* Clear screen */
|
|
|
|
static const char *g_clreos = "\033[J"; /* Clear to end of screen */
|
|
|
|
static const char *g_clreol = "\033[K"; /* Clear to end of line */
|
|
|
|
|
|
|
|
static const char *g_movecurs = "\033[%d;%dH"; /* Move cursor to x,y */
|
|
|
|
static const char *g_getwinsize = "\x1b[s\x1b[999;999H\x1b[6n\x1bu";
|
|
|
|
static const char *g_setfgcolor = "\x1b[38;5;%dm";
|
|
|
|
static const char *g_setbgcolor = "\x1b[48;5;%dm";
|
|
|
|
static const char *g_showcursor = "\x1b[?25h";
|
|
|
|
static const char *g_hidecursor = "\x1b[?25l";
|
|
|
|
static const char *g_setbold = "\x1b[1";
|
|
|
|
static const char *g_setnobold = "\x1b[22";
|
|
|
|
static const char *g_setblink = ";5";
|
|
|
|
static const char *g_setnoblink = ";25";
|
|
|
|
static const char *g_setunderline = ";4";
|
|
|
|
static const char *g_setnounderline = ";24";
|
|
|
|
|
2021-08-22 13:50:50 +02:00
|
|
|
/* Set default background and foreground colors. */
|
|
|
|
|
|
|
|
static const char *g_setdefcolors = "\x1b[39;m\x1b[49;m";
|
|
|
|
|
2019-01-05 19:40:26 +01:00
|
|
|
struct keycodes_s
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_TERMCURSES_INCLUDE_TERMINFO_NAME
|
|
|
|
const char *terminfo_name;
|
|
|
|
#endif
|
|
|
|
const char *def;
|
|
|
|
int keycode;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const uint16_t g_key_modifiers[][2] =
|
|
|
|
{
|
2021-06-10 18:40:35 +02:00
|
|
|
{
|
|
|
|
KEY_PPAGE | (PDC_KEY_MODIFIER_ALT << 12), ALT_PGDN
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_NPAGE | (PDC_KEY_MODIFIER_ALT << 12), ALT_PGUP
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_UP | (PDC_KEY_MODIFIER_SHIFT << 12), KEY_SUP
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_DOWN | (PDC_KEY_MODIFIER_SHIFT << 12), KEY_SDOWN
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_LEFT | (PDC_KEY_MODIFIER_SHIFT << 12), KEY_SLEFT
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_RIGHT | (PDC_KEY_MODIFIER_SHIFT << 12), KEY_SRIGHT
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_UP | (PDC_KEY_MODIFIER_CONTROL << 12), CTL_UP
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_DOWN | (PDC_KEY_MODIFIER_CONTROL << 12), CTL_DOWN
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_LEFT | (PDC_KEY_MODIFIER_CONTROL << 12), CTL_LEFT
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_RIGHT | (PDC_KEY_MODIFIER_CONTROL << 12), CTL_RIGHT
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_DC | (PDC_KEY_MODIFIER_SHIFT << 12), KEY_SDC
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_DC | (PDC_KEY_MODIFIER_ALT << 12), ALT_DEL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_DC | (PDC_KEY_MODIFIER_CONTROL << 12), CTL_DEL
|
|
|
|
},
|
|
|
|
{
|
|
|
|
KEY_IC | (PDC_KEY_MODIFIER_ALT << 12), ALT_INS
|
|
|
|
}
|
2019-01-05 19:40:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static const int g_key_modifier_count =
|
|
|
|
sizeof(g_key_modifiers) / (sizeof(uint16_t)*2);
|
|
|
|
|
|
|
|
static const struct keycodes_s g_esc_keycodes[] =
|
|
|
|
{
|
|
|
|
/* terminfo pdcurses
|
2021-06-10 18:40:35 +02:00
|
|
|
* name definition key code
|
|
|
|
*/
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcuu1", "[A", KEY_UP)
|
|
|
|
}, /* Up Arrow */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcud1", "[B", KEY_DOWN)
|
|
|
|
}, /* Down Arrow */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcuf1", "[C", KEY_RIGHT)
|
|
|
|
}, /* Right Arrow */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcub1", "[D", KEY_LEFT)
|
|
|
|
}, /* Left Arrow */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("knp", "[6~", KEY_NPAGE)
|
|
|
|
}, /* Next Page Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kpp", "[5~", KEY_PPAGE)
|
|
|
|
}, /* Prev Page Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("khom", "OH", KEY_HOME)
|
|
|
|
}, /* Home Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kend", "OF", KEY_END)
|
|
|
|
}, /* Home Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcab1", "b", ALT_LEFT)
|
|
|
|
}, /* Alt Left arrow Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kcaf1", "f", ALT_RIGHT)
|
|
|
|
}, /* Alt Right arrow Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kprt", "[25~", KEY_PRINT)
|
|
|
|
}, /* Print-screen Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kdc", "[3~", KEY_DC)
|
|
|
|
}, /* Delete char key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kic", "[2~", KEY_IC)
|
|
|
|
}, /* Insert Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kacr", "\x1a", ALT_ENTER)
|
|
|
|
}, /* ALT-Enter Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kTAB", "[Z", KEY_STAB)
|
|
|
|
}, /* SHIFT-tab Key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf1", "OP", KEY_F(1))
|
|
|
|
}, /* F1 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf2", "OQ", KEY_F(2))
|
|
|
|
}, /* F2 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf3", "OR", KEY_F(3))
|
|
|
|
}, /* F3 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf4", "OS", KEY_F(4))
|
|
|
|
}, /* F4 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf5", "[15~", KEY_F(5))
|
|
|
|
}, /* F5 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf6", "[17~", KEY_F(6))
|
|
|
|
}, /* F6 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf7", "[18~", KEY_F(7))
|
|
|
|
}, /* F7 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf8", "[19~", KEY_F(8))
|
|
|
|
}, /* F8 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf9", "[20~", KEY_F(9))
|
|
|
|
}, /* F9 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf10", "[21~", KEY_F(10))
|
|
|
|
}, /* F10 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf11", "[22~", KEY_F(11))
|
|
|
|
}, /* F11 Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("kf12", "[24~", KEY_F(12))
|
|
|
|
}, /* F12 Key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Oq", KEY_C1)
|
|
|
|
}, /* Lower left PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Or", KEY_C2)
|
|
|
|
}, /* Lower middle PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Os", KEY_C3)
|
|
|
|
}, /* Lower right PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Ot", KEY_B1)
|
|
|
|
}, /* Middle left PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Ou", KEY_B2)
|
|
|
|
}, /* Middle middle PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Ov", KEY_B3)
|
|
|
|
}, /* Middle right PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Ow", KEY_A1)
|
|
|
|
}, /* Upper left PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Ox", KEY_A2)
|
|
|
|
}, /* Upper middle PAD Key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "Oy", KEY_A3)
|
|
|
|
}, /* Upper right PAD Key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "a", ALT_A)
|
|
|
|
}, /* ALT-A key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "b", ALT_B)
|
|
|
|
}, /* ALT-B key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "c", ALT_C)
|
|
|
|
}, /* ALT-C key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "d", ALT_D)
|
|
|
|
}, /* ALT-D key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "e", ALT_E)
|
|
|
|
}, /* ALT-E key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "f", ALT_F)
|
|
|
|
}, /* ALT-F key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "g", ALT_G)
|
|
|
|
}, /* ALT-G key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "h", ALT_H)
|
|
|
|
}, /* ALT-H key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "i", ALT_I)
|
|
|
|
}, /* ALT-I key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "j", ALT_J)
|
|
|
|
}, /* ALT-J key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "k", ALT_K)
|
|
|
|
}, /* ALT-K key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "l", ALT_L)
|
|
|
|
}, /* ALT-L key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "m", ALT_M)
|
|
|
|
}, /* ALT-M key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "n", ALT_N)
|
|
|
|
}, /* ALT-N key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "o", ALT_O)
|
|
|
|
}, /* ALT-O key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "p", ALT_P)
|
|
|
|
}, /* ALT-P key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "q", ALT_Q)
|
|
|
|
}, /* ALT-Q key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "r", ALT_R)
|
|
|
|
}, /* ALT-R key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "s", ALT_S)
|
|
|
|
}, /* ALT-S key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "t", ALT_T)
|
|
|
|
}, /* ALT-T key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "u", ALT_U)
|
|
|
|
}, /* ALT-U key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "v", ALT_V)
|
|
|
|
}, /* ALT-V key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "w", ALT_W)
|
|
|
|
}, /* ALT-W key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "x", ALT_X)
|
|
|
|
}, /* ALT-X key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "y", ALT_Y)
|
|
|
|
}, /* ALT-Y key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "z", ALT_Z)
|
|
|
|
}, /* ALT-Z key */
|
|
|
|
|
|
|
|
{ TINFO_ENTRY("", "0", ALT_0)
|
|
|
|
}, /* ALT-0 key */
|
|
|
|
{ TINFO_ENTRY("", "1", ALT_1)
|
|
|
|
}, /* ALT-1 key */
|
|
|
|
{ TINFO_ENTRY("", "2", ALT_2)
|
|
|
|
}, /* ALT-2 key */
|
|
|
|
{ TINFO_ENTRY("", "3", ALT_3)
|
|
|
|
}, /* ALT-3 key */
|
|
|
|
{ TINFO_ENTRY("", "4", ALT_4)
|
|
|
|
}, /* ALT-4 key */
|
|
|
|
{ TINFO_ENTRY("", "5", ALT_5)
|
|
|
|
}, /* ALT-5 key */
|
|
|
|
{ TINFO_ENTRY("", "6", ALT_6)
|
|
|
|
}, /* ALT-6 key */
|
|
|
|
{ TINFO_ENTRY("", "7", ALT_7)
|
|
|
|
}, /* ALT-7 key */
|
|
|
|
{ TINFO_ENTRY("", "8", ALT_8)
|
|
|
|
}, /* ALT-8 key */
|
|
|
|
{ TINFO_ENTRY("", "9", ALT_9)
|
|
|
|
}, /* ALT-9 key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "-", ALT_MINUS)
|
|
|
|
}, /* ALT-- key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "+", ALT_PLUS)
|
|
|
|
}, /* ALT-+ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "=", ALT_EQUAL)
|
|
|
|
}, /* ALT-= key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ",", ALT_COMMA)
|
|
|
|
}, /* ALT-, key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ".", ALT_PERIOD)
|
|
|
|
}, /* ALT-. key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "/", ALT_FSLASH)
|
|
|
|
}, /* ALT-/ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\\", ALT_BSLASH)
|
|
|
|
}, /* ALT-\ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "]", ALT_RBRACKET)
|
|
|
|
}, /* ALT-] key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ";", ALT_SEMICOLON)
|
|
|
|
}, /* ALT-; key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", " ", ALT_SPACE)
|
|
|
|
}, /* ALT-space key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "'", ALT_TICK)
|
|
|
|
}, /* ALT-' key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "?", ALT_QUESTION)
|
|
|
|
}, /* ALT-space key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ":", ALT_COLON)
|
|
|
|
}, /* ALT-' key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\"", ALT_QUOTE)
|
|
|
|
}, /* ALT-" key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "{", ALT_LBRACE)
|
|
|
|
}, /* ALT-{ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "}", ALT_RBRACE)
|
|
|
|
}, /* ALT-} key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "<", ALT_LESS)
|
|
|
|
}, /* ALT-< key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ">", ALT_GREATER)
|
|
|
|
}, /* ALT-> key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "_", ALT_UNDERSCORE)
|
|
|
|
}, /* ALT-_ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "|", ALT_VBAR)
|
|
|
|
}, /* ALT-| key */
|
|
|
|
|
|
|
|
{ TINFO_ENTRY("", "!", ALT_EXCL)
|
|
|
|
}, /* ALT-! key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "@", ALT_AT)
|
|
|
|
}, /* ALT-@ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "#", ALT_POUND)
|
|
|
|
}, /* ALT-# key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "%", ALT_DOLLAR)
|
|
|
|
}, /* ALT-$ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "^", ALT_PERCENT)
|
|
|
|
}, /* ALT-% key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "&", ALT_CARET)
|
|
|
|
}, /* ALT-^ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "&", ALT_AMP)
|
|
|
|
}, /* ALT-& key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "*", ALT_STAR)
|
|
|
|
}, /* ALT-* key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "(", ALT_LPAREN)
|
|
|
|
}, /* ALT-( key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", ")", ALT_RPAREN)
|
|
|
|
}, /* ALT-) key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY(NULL, NULL, -1)
|
|
|
|
}
|
2019-01-05 19:40:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_VT100_OSX_ALT_CODES
|
|
|
|
static const struct keycodes_s g_ctrl_keycodes[] =
|
|
|
|
{
|
2021-06-10 18:40:35 +02:00
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\xa5", ALT_A)
|
|
|
|
}, /* ALT-A key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x88\xab", ALT_B)
|
|
|
|
}, /* ALT-B key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\xa7", ALT_C)
|
|
|
|
}, /* ALT-C key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x88\x82", ALT_D)
|
|
|
|
}, /* ALT-D key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xb4", ALT_E)
|
|
|
|
}, /* ALT-E key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc6\x92", ALT_F)
|
|
|
|
}, /* ALT-F key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xa9", ALT_G)
|
|
|
|
}, /* ALT-G key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcb\x99", ALT_H)
|
|
|
|
}, /* ALT-H key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcb\x86", ALT_I)
|
|
|
|
}, /* ALT-I key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x88\x86", ALT_J)
|
|
|
|
}, /* ALT-J key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcb\x9a", ALT_K)
|
|
|
|
}, /* ALT-K key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xac", ALT_L)
|
|
|
|
}, /* ALT-L key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xb5", ALT_M)
|
|
|
|
}, /* ALT-M key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcb\x9c", ALT_N)
|
|
|
|
}, /* ALT-N key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\xb8", ALT_O)
|
|
|
|
}, /* ALT-O key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcf\x80", ALT_P)
|
|
|
|
}, /* ALT-P key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc5\x93", ALT_Q)
|
|
|
|
}, /* ALT-Q key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xae", ALT_R)
|
|
|
|
}, /* ALT-R key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\x9f", ALT_S)
|
|
|
|
}, /* ALT-S key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\xa0", ALT_T)
|
|
|
|
}, /* ALT-T key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xa8", ALT_U)
|
|
|
|
}, /* ALT-U key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x88\x9a", ALT_V)
|
|
|
|
}, /* ALT-V key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x88\x91", ALT_W)
|
|
|
|
}, /* ALT-W key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x89\x88", ALT_X)
|
|
|
|
}, /* ALT-X key */
|
|
|
|
|
|
|
|
/* {
|
|
|
|
* TINFO_ENTRY("", "\xe2\x89\x88", ALT_Y)
|
|
|
|
* },
|
|
|
|
*/ /* ALT-Y key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xce\xa9", ALT_Z)
|
|
|
|
}, /* ALT-Z key */
|
|
|
|
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xba", ALT_0)
|
|
|
|
}, /* ALT-0 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xa1", ALT_1)
|
|
|
|
}, /* ALT-1 key */
|
|
|
|
{ TINFO_ENTRY("", "\xe2\x84\xa2", ALT_2)
|
|
|
|
}, /* ALT-2 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xa3", ALT_3)
|
|
|
|
}, /* ALT-3 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xa2", ALT_4)
|
|
|
|
}, /* ALT-4 key */
|
|
|
|
{ TINFO_ENTRY("", "\xe2\x88\x9e", ALT_5)
|
|
|
|
}, /* ALT-5 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xa7", ALT_6)
|
|
|
|
}, /* ALT-6 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xb6", ALT_7)
|
|
|
|
}, /* ALT-7 key */
|
|
|
|
{ TINFO_ENTRY("", "\xe2\x80\xa2", ALT_8)
|
|
|
|
}, /* ALT-8 key */
|
|
|
|
{ TINFO_ENTRY("", "\xc2\xaa", ALT_9)
|
|
|
|
}, /* ALT-9 key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x93", ALT_MINUS)
|
|
|
|
}, /* ALT-- key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xb1", ALT_PLUS)
|
|
|
|
}, /* ALT-+ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x89\xa0", ALT_EQUAL)
|
|
|
|
}, /* ALT-= key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x89\xa4", ALT_COMMA)
|
|
|
|
}, /* ALT-, key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x89\xa5", ALT_PERIOD)
|
|
|
|
}, /* ALT-. key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\xb7", ALT_FSLASH)
|
|
|
|
}, /* ALT-/ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xab", ALT_BSLASH)
|
|
|
|
}, /* ALT-\ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x9c", ALT_LBRACKET)
|
|
|
|
}, /* ALT-[ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x98", ALT_RBRACKET)
|
|
|
|
}, /* ALT-] key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\xa6", ALT_SEMICOLON)
|
|
|
|
}, /* ALT-; key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xa0", ALT_SPACE)
|
|
|
|
}, /* ALT-space key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\xa6", ALT_TICK)
|
|
|
|
}, /* ALT-' key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xbf", ALT_QUESTION)
|
|
|
|
}, /* ALT-space key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\x9a", ALT_COLON)
|
|
|
|
}, /* ALT-' key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc3\x86", ALT_QUOTE)
|
|
|
|
}, /* ALT-" key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x9d", ALT_LBRACE)
|
|
|
|
}, /* ALT-{ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x99", ALT_RBRACE)
|
|
|
|
}, /* ALT-} key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xaf", ALT_LESS)
|
|
|
|
}, /* ALT-< key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xcb\x98", ALT_GREATER)
|
|
|
|
}, /* ALT-> key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x94", ALT_UNDERSCORE)
|
|
|
|
}, /* ALT-_ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xbb", ALT_VBAR)
|
|
|
|
}, /* ALT-| key */
|
|
|
|
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x81\x84", ALT_EXCL)
|
|
|
|
}, /* ALT-! key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x82\xac", ALT_AT)
|
|
|
|
}, /* ALT-@ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\xb9", ALT_POUND)
|
|
|
|
}, /* ALT-# key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\xba", ALT_DOLLAR)
|
|
|
|
}, /* ALT-$ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xef\xac\x81", ALT_PERCENT)
|
|
|
|
}, /* ALT-% key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xef\xac\x82", ALT_CARET)
|
|
|
|
}, /* ALT-^ key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\xa1", ALT_AMP)
|
|
|
|
}, /* ALT-& key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xb0", ALT_STAR)
|
|
|
|
}, /* ALT-* key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xc2\xb7", ALT_LPAREN)
|
|
|
|
}, /* ALT-( key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY("", "\xe2\x80\x9a", ALT_RPAREN)
|
|
|
|
}, /* ALT-) key */
|
|
|
|
{
|
|
|
|
TINFO_ENTRY(NULL, NULL, -1)
|
|
|
|
}
|
2019-01-05 19:40:26 +01:00
|
|
|
};
|
2020-01-31 16:18:05 +01:00
|
|
|
#endif /* CONFIG_SYSTEM_TERMCURSES_VT100_OSX_ALT_CODES */
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Public Data
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
struct termcurses_dev_s g_vt100_tcurs =
|
|
|
|
{
|
|
|
|
&g_vt100_ops, /* Operations pointer */
|
|
|
|
NULL, /* Next pointer */
|
|
|
|
"vt100, vt102, ansi" /* List of supported terminals */
|
|
|
|
};
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Clear screen / line operations
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static int tcurses_vt100_clear(FAR struct termcurses_s *dev, int type)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int ret = -ENOSYS;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* Perform operation based on type */
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case TCURS_CLEAR_SCREEN:
|
|
|
|
ret = write(fd, g_clrscr, strlen(g_clrscr));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TCURS_CLEAR_LINE:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TCURS_CLEAR_EOS:
|
|
|
|
ret = write(fd, g_clrscr, strlen(g_clreos));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TCURS_CLEAR_EOL:
|
|
|
|
ret = write(fd, g_clrscr, strlen(g_clreol));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If data written successfully, return OK */
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
ret = OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Move cursor operations
|
|
|
|
************************************************************************************/
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
static int tcurses_vt100_move(FAR struct termcurses_s *dev, int type,
|
|
|
|
int col, int row)
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int ret = -ENOSYS;
|
|
|
|
int fd;
|
2022-03-06 13:01:14 +01:00
|
|
|
char str[32];
|
2019-01-05 19:40:26 +01:00
|
|
|
|
2019-01-05 20:52:51 +01:00
|
|
|
priv = (FAR struct tcurses_vt100_s *)dev;
|
2019-01-05 19:40:26 +01:00
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* Perform operation based on type */
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case TCURS_MOVE_YX:
|
2022-03-06 13:01:14 +01:00
|
|
|
snprintf(str, sizeof(str), g_movecurs, row + 1, col + 1);
|
2019-01-05 19:40:26 +01:00
|
|
|
ret = write(fd, str, strlen(str));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If bytes written, return OK */
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
ret = OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Calculates an ANSI 256 color index based on the 24-bit RGB value given.
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static uint8_t tcurses_vt100_getcolorindex(int red, int green, int blue)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
int g;
|
|
|
|
int b;
|
|
|
|
int index;
|
2019-01-17 15:58:11 +01:00
|
|
|
const uint8_t rgbvals[6] =
|
|
|
|
{
|
|
|
|
0, 95, 135, 175, 215, 255
|
|
|
|
};
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
/* Test for colors 0-7 */
|
|
|
|
|
|
|
|
if (red == 0 && green == 0 && blue == 0)
|
|
|
|
{
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (red == 0 || red == 0xc0)
|
|
|
|
{
|
|
|
|
index = red == 0xc0 ? COLOR_RED : 0;
|
|
|
|
if (green == 0 || green == 0xc0)
|
|
|
|
{
|
|
|
|
index |= (green == 0xc0) ? COLOR_GREEN : 0;
|
|
|
|
if (blue == 0 || blue == 0xc0)
|
|
|
|
{
|
|
|
|
index |= (blue == 0xc0) ? COLOR_BLUE : 0;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test for colors 8-15 */
|
|
|
|
|
|
|
|
if (red == 0x40 || red == 0xff)
|
|
|
|
{
|
|
|
|
index = red == 0xff ? COLOR_RED : 0;
|
|
|
|
if (green == 0x40 || green == 0xff)
|
|
|
|
{
|
|
|
|
index |= (green == 0xff) ? COLOR_GREEN : 0;
|
|
|
|
if (blue == 0x40 || blue == 0xff)
|
|
|
|
{
|
|
|
|
index |= (blue == 0xff) ? COLOR_BLUE : 0;
|
|
|
|
return index + 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test for grayscale colors */
|
|
|
|
|
|
|
|
if (red == green && green == blue)
|
|
|
|
{
|
|
|
|
index = 232 + red / 11;
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Must be on the 216 color (6x6x6) color cube */
|
|
|
|
|
|
|
|
for (r = 0; r < 5 && red > (rgbvals[r] + rgbvals[r + 1]) / 2; )
|
|
|
|
{
|
|
|
|
/* Nothing to do except increment */
|
|
|
|
|
|
|
|
r++;
|
|
|
|
}
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
for (g = 0; g < 5 && green > (rgbvals[g] + rgbvals[g + 1]) / 2; )
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
|
|
|
/* Nothing to do except increment */
|
|
|
|
|
|
|
|
g++;
|
|
|
|
}
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
for (b = 0; b < 5 && blue > (rgbvals[b] + rgbvals[b + 1]) / 2; )
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
|
|
|
/* Nothing to do except increment */
|
|
|
|
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 16 + r * 36 + g * 6 + b;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Set fg / bg colors
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static int tcurses_vt100_setcolors(FAR struct termcurses_s *dev,
|
|
|
|
FAR struct termcurses_colors_s *colors)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int ret = -ENOSYS;
|
|
|
|
int fd;
|
|
|
|
char str[48];
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* Test if FG color to be set */
|
|
|
|
|
|
|
|
if ((colors->color_mask & TCURS_COLOR_FG) != 0)
|
|
|
|
{
|
|
|
|
sprintf(str, g_setfgcolor,
|
|
|
|
tcurses_vt100_getcolorindex(colors->fg_red, colors->fg_green,
|
|
|
|
colors->fg_blue));
|
|
|
|
ret = write(fd, str, strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test if BG color to be set */
|
|
|
|
|
|
|
|
if ((colors->color_mask & TCURS_COLOR_BG) != 0)
|
|
|
|
{
|
|
|
|
if (colors->bg_red != 0 || colors->bg_green != 0 || colors->bg_blue != 0)
|
|
|
|
{
|
|
|
|
colors->bg_red = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(str, g_setbgcolor,
|
|
|
|
tcurses_vt100_getcolorindex(colors->bg_red, colors->bg_green,
|
|
|
|
colors->bg_blue));
|
|
|
|
ret = write(fd, str, strlen(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If bytes written, return OK */
|
|
|
|
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
ret = OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Get windows size from terminal emulator connected to serial port
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static int tcurses_vt100_getwinsize(FAR struct termcurses_s *dev,
|
|
|
|
FAR struct winsize *winsz)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int ret = -ENOSYS;
|
|
|
|
int fd;
|
|
|
|
char resp[64];
|
|
|
|
int flags;
|
|
|
|
int delay;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* First try the TIOCGWINSZ ioctl */
|
|
|
|
|
|
|
|
ret = ioctl(fd, TIOCGWINSZ, (unsigned long) winsz);
|
|
|
|
if (ret == OK)
|
|
|
|
{
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write command to get window size */
|
|
|
|
|
|
|
|
ret = write(fd, g_getwinsize, strlen(g_getwinsize));
|
|
|
|
if (ret <= 0)
|
|
|
|
{
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Perform a non-blocking read to get return data */
|
|
|
|
|
|
|
|
flags = fcntl(fd, F_GETFL);
|
|
|
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
|
|
|
|
delay = 0;
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
/* Loop to allow non-blocking read time to receive data */
|
|
|
|
|
|
|
|
while (delay < 50)
|
|
|
|
{
|
|
|
|
/* Perform a read */
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
ret = read(fd, &resp[len], sizeof(resp) - len);
|
2019-01-05 19:40:26 +01:00
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
len += ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test for completion of read */
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
if (len > 0 && resp[len - 1] == 'R')
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
|
|
|
/* Get the terminal size from the response */
|
|
|
|
|
|
|
|
if (resp[0] == '\x1b' && resp[1] == '[')
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
resp[len] = 0;
|
|
|
|
x = 2;
|
|
|
|
while (resp[x] != ';' && resp[x] != 0)
|
|
|
|
{
|
|
|
|
x++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch = resp[x];
|
|
|
|
resp[x] = 0;
|
|
|
|
winsz->ws_row = atoi(&resp[2]);
|
|
|
|
if (ch == ';')
|
|
|
|
{
|
2021-06-10 18:40:35 +02:00
|
|
|
winsz->ws_col = atoi(&resp[x + 1]);
|
2019-01-05 19:40:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Change back to original block/non-block mode */
|
|
|
|
|
|
|
|
fcntl(fd, F_SETFL, flags);
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sleep a bit to allow data to arrive */
|
|
|
|
|
|
|
|
usleep(1000);
|
|
|
|
delay++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fcntl(fd, F_SETFL, flags);
|
|
|
|
return -ENOSYS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Set display attributes
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static int tcurses_vt100_setattributes(FAR struct termcurses_s *dev,
|
|
|
|
unsigned long attrib)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
2019-01-17 15:58:11 +01:00
|
|
|
int ret;
|
|
|
|
int fd;
|
2019-01-05 19:40:26 +01:00
|
|
|
char str[48];
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* Test for cursor hide */
|
|
|
|
|
|
|
|
if (attrib & TCURS_ATTRIB_CURS_HIDE)
|
|
|
|
{
|
|
|
|
/* Send sequence to hide the cursor */
|
|
|
|
|
|
|
|
ret = write(fd, g_hidecursor, strlen(g_hidecursor));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrib & TCURS_ATTRIB_CURS_SHOW)
|
|
|
|
{
|
|
|
|
/* Send sequence to hide the cursor */
|
|
|
|
|
|
|
|
ret = write(fd, g_showcursor, strlen(g_showcursor));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build attribute string */
|
|
|
|
|
|
|
|
if (attrib & TCURS_ATTRIB_BOLD)
|
|
|
|
{
|
|
|
|
strcpy(str, g_setbold);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(str, g_setnobold);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrib & TCURS_ATTRIB_BLINK)
|
|
|
|
{
|
|
|
|
strcat(str, g_setblink);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcat(str, g_setnoblink);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attrib & TCURS_ATTRIB_UNDERLINE)
|
|
|
|
{
|
|
|
|
strcat(str, g_setunderline);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcat(str, g_setnounderline);
|
|
|
|
}
|
|
|
|
|
|
|
|
strcat(str, "m");
|
|
|
|
|
|
|
|
ret = write(fd, str, strlen(str));
|
|
|
|
|
|
|
|
/* If bytes written, return OK */
|
|
|
|
|
|
|
|
ret = (ret > 0) ? OK : -ENOSYS;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Get keycode from the terminal, translating special escape sequences into
|
|
|
|
* special key values.
|
|
|
|
*
|
|
|
|
************************************************************************************/
|
|
|
|
|
2021-06-10 18:40:35 +02:00
|
|
|
static int tcurses_vt100_getkeycode(FAR struct termcurses_s *dev,
|
|
|
|
FAR int *specialkey,
|
2019-01-05 19:40:26 +01:00
|
|
|
FAR int *keymodifiers)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
const struct keycodes_s *pkeycodes;
|
|
|
|
int ret;
|
|
|
|
int fd;
|
|
|
|
bool esc_seq = false;
|
|
|
|
bool ctrl_seq = false;
|
|
|
|
bool ismodifier;
|
|
|
|
int keycode;
|
|
|
|
int k;
|
|
|
|
int x;
|
|
|
|
int start;
|
|
|
|
fd_set rfds;
|
|
|
|
struct timeval tv;
|
|
|
|
char ch;
|
|
|
|
char buildkey[16];
|
|
|
|
int keybuildcount;
|
|
|
|
static const char modtable[7] =
|
|
|
|
{
|
|
|
|
PDC_KEY_MODIFIER_SHIFT,
|
|
|
|
PDC_KEY_MODIFIER_ALT,
|
|
|
|
PDC_KEY_MODIFIER_ALT | PDC_KEY_MODIFIER_SHIFT,
|
|
|
|
PDC_KEY_MODIFIER_CONTROL,
|
|
|
|
PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_SHIFT,
|
|
|
|
PDC_KEY_MODIFIER_ALT | PDC_KEY_MODIFIER_CONTROL,
|
|
|
|
PDC_KEY_MODIFIER_ALT | PDC_KEY_MODIFIER_CONTROL | PDC_KEY_MODIFIER_SHIFT
|
|
|
|
};
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->in_fd;
|
|
|
|
|
|
|
|
/* Watch stdin (fd 0) to see when it has input. */
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(0, &rfds);
|
|
|
|
|
|
|
|
/* Wait up to 1000us for next character after ESC */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = 1000;
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
/* Loop until we have a valid key code, taking escape sequences into account */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
keycode = -1;
|
2019-01-05 19:40:26 +01:00
|
|
|
*keymodifiers = 0;
|
2019-01-17 15:39:29 +01:00
|
|
|
*specialkey = 0;
|
|
|
|
ismodifier = false;
|
2019-01-17 16:13:00 +01:00
|
|
|
keybuildcount = 0;
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
while (keycode == -1)
|
|
|
|
{
|
|
|
|
/* Test if keybuf has unprocessed bytes */
|
|
|
|
|
|
|
|
if (priv->keycount == 0)
|
|
|
|
{
|
|
|
|
/* Get next bytes from input stream */
|
|
|
|
|
2019-01-08 15:21:39 +01:00
|
|
|
priv->keycount = read(fd, priv->keybuf, sizeof(priv->keybuf)-1);
|
2019-01-05 19:40:26 +01:00
|
|
|
if (priv->keycount <= 0)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->keybuf[priv->keycount] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop for all bytes received */
|
|
|
|
|
|
|
|
for (x = 0; x < priv->keycount && keycode == -1; x++)
|
|
|
|
{
|
|
|
|
ch = priv->keybuf[x];
|
2019-01-11 14:41:04 +01:00
|
|
|
if (ch == 0 && x + 1 == priv->keycount)
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
2019-01-11 14:41:04 +01:00
|
|
|
priv->keycount = 0;
|
|
|
|
return -1;
|
2019-01-05 19:40:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Test for escape sequence */
|
|
|
|
|
|
|
|
if (ch == '\x1b')
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_DEBUG_KEYCODES
|
|
|
|
printf("<0x%02X>", ch);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Mark as ESC sequence */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
esc_seq = true;
|
|
|
|
ctrl_seq = false;
|
|
|
|
buildkey[0] = ch;
|
2019-01-05 19:40:26 +01:00
|
|
|
keybuildcount = 1;
|
2019-01-17 15:39:29 +01:00
|
|
|
|
2019-01-05 19:40:26 +01:00
|
|
|
if (x + 1 != priv->keycount)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test for other characters in the queue. If there are more
|
|
|
|
* characters waiting, then simply continue the loop to process
|
|
|
|
* them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
priv->keycount = 0;
|
|
|
|
ret = select(1, &rfds, NULL, NULL, &tv);
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more characters waiting in the queue. Must be ESC key. */
|
|
|
|
|
|
|
|
return '\x1b';
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (esc_seq || ctrl_seq)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_DEBUG_KEYCODES
|
|
|
|
if (ch >= 33 && ch <= '~')
|
|
|
|
{
|
|
|
|
printf("%c", ch);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf("<0x%02X>", ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Check if this is a key modifier code */
|
|
|
|
|
|
|
|
if (ismodifier)
|
|
|
|
{
|
|
|
|
/* Test if previous char was '1' */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
if (buildkey[keybuildcount - 1] == '1')
|
2019-01-05 19:40:26 +01:00
|
|
|
{
|
|
|
|
buildkey[--keybuildcount] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear ismodifier attribute */
|
|
|
|
|
|
|
|
ismodifier = false;
|
|
|
|
if (ch < '2' || ch > '8')
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the key modifier code */
|
|
|
|
|
|
|
|
*keymodifiers = modtable[ch - '2'];
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (ch == ';')
|
|
|
|
{
|
|
|
|
/* Mark next character as key modifier code */
|
|
|
|
|
|
|
|
ismodifier = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add character to the buildkey */
|
|
|
|
|
|
|
|
buildkey[keybuildcount++] = ch;
|
2019-01-17 15:39:29 +01:00
|
|
|
buildkey[keybuildcount] = 0;
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
/* If there are more bytes in the sequence, then
|
|
|
|
* process them prior to searching the keycode
|
|
|
|
* array to save time.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (x + 1 != priv->keycount && priv->keybuf[x + 1] != '\x1b')
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search either ESC or CTRL keycode table */
|
|
|
|
|
|
|
|
pkeycodes = g_esc_keycodes;
|
|
|
|
start = 1;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_VT100_OSX_ALT_CODES
|
|
|
|
if (buildkey[0] != '\x1b')
|
|
|
|
{
|
|
|
|
pkeycodes = g_ctrl_keycodes;
|
|
|
|
start = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Test for match with known key definitions */
|
|
|
|
|
|
|
|
for (k = 0; pkeycodes[k].def != NULL; k++)
|
|
|
|
{
|
|
|
|
if (strcmp(&buildkey[start], pkeycodes[k].def) == 0)
|
|
|
|
{
|
|
|
|
/* Special key code found! */
|
|
|
|
|
|
|
|
keycode = pkeycodes[k].keycode;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we found a keymodifier, then check for key code
|
|
|
|
* substitutions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (pkeycodes[k].def != NULL && *keymodifiers != 0)
|
|
|
|
{
|
|
|
|
uint16_t searchval = (*keymodifiers << 12) | keycode;
|
|
|
|
|
|
|
|
/* Search the modifier table */
|
|
|
|
|
|
|
|
for (k = 0; k < g_key_modifier_count; k++)
|
|
|
|
{
|
|
|
|
/* Test next entry in table for match */
|
|
|
|
|
|
|
|
if (searchval == g_key_modifiers[k][0])
|
|
|
|
{
|
|
|
|
/* Update to new keycode */
|
|
|
|
|
|
|
|
keycode = g_key_modifiers[k][1];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (ch == 127)
|
|
|
|
{
|
|
|
|
/* Return as CTRL-H */
|
|
|
|
|
|
|
|
keycode = 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ((ch >= ' ' && ch <= '~') || (ch >= 1 && ch <= 26))
|
|
|
|
{
|
|
|
|
/* Return normal ASCII or CTRL-x key */
|
|
|
|
|
|
|
|
keycode = ch;
|
|
|
|
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_DEBUG_KEYCODES
|
|
|
|
printf("%c", ch);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* It is a special control code */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
buildkey[0] = ch;
|
2019-01-05 19:40:26 +01:00
|
|
|
keybuildcount = 1;
|
2019-01-17 15:39:29 +01:00
|
|
|
ctrl_seq = 1;
|
2019-01-05 19:40:26 +01:00
|
|
|
|
|
|
|
#ifdef CONFIG_SYSTEM_TERMCURSES_DEBUG_KEYCODES
|
|
|
|
/* Print all bytes in ctrl seq */
|
|
|
|
|
|
|
|
printf("<0x%02X>", ch);
|
|
|
|
fflush(stdout);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update keycount and keybuf */
|
|
|
|
|
|
|
|
priv->keycount -= x;
|
2019-01-17 01:22:16 +01:00
|
|
|
if (priv->keycount < 0)
|
|
|
|
{
|
|
|
|
/* Hmm, some bug. Better to simply ignore than to crash */
|
|
|
|
|
|
|
|
priv->keycount = 0;
|
|
|
|
}
|
|
|
|
|
2019-01-05 19:40:26 +01:00
|
|
|
if (priv->keycount != 0)
|
|
|
|
{
|
|
|
|
memmove(priv->keybuf, &priv->keybuf[x], priv->keycount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return keycode;
|
|
|
|
}
|
|
|
|
|
2019-01-08 15:21:39 +01:00
|
|
|
/************************************************************************************
|
|
|
|
* Check if a key is cached for processing.
|
|
|
|
*
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static bool tcurses_vt100_checkkey(FAR struct termcurses_s *dev)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int ret;
|
|
|
|
int fd;
|
|
|
|
fd_set rfds;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->in_fd;
|
|
|
|
|
|
|
|
/* Test for queued characters */
|
|
|
|
|
|
|
|
if (priv->keycount > 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Watch stdin (fd 0) to see when it has input. */
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_SET(fd, &rfds);
|
|
|
|
|
|
|
|
/* Wait up to 1000us for next character after ESC */
|
|
|
|
|
2019-01-17 15:39:29 +01:00
|
|
|
tv.tv_sec = 0;
|
2019-01-08 15:21:39 +01:00
|
|
|
tv.tv_usec = 0;
|
|
|
|
|
|
|
|
ret = select(1, &rfds, NULL, NULL, &tv);
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-01-05 19:40:26 +01:00
|
|
|
/************************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Name: tcurses_vt100_initialize
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Initialize a specific instance of the VT100 TermCurses handler and bind it to
|
|
|
|
* a specific file descriptor pair (input/output ... typically stdin / stdout).
|
|
|
|
*
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
FAR struct termcurses_s *tcurses_vt100_initialize(int in_fd, int out_fd)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
|
|
|
|
/* Allocate a new device structure */
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *)zalloc(sizeof(struct tcurses_vt100_s));
|
|
|
|
if (priv == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Populate the device context */
|
|
|
|
|
|
|
|
priv->dev.ops = &g_vt100_ops;
|
|
|
|
priv->dev.name = g_vt100_tcurs.name;
|
|
|
|
priv->dev.next = NULL;
|
|
|
|
priv->in_fd = in_fd;
|
|
|
|
priv->out_fd = out_fd;
|
|
|
|
priv->keycount = 0;
|
|
|
|
|
|
|
|
return (FAR struct termcurses_s *) priv;
|
|
|
|
}
|
2021-08-22 13:50:50 +02:00
|
|
|
|
|
|
|
/************************************************************************************
|
|
|
|
* Name: tcurses_vt100_terminate
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Terminates a specific instance of the VT100 TermCurses handler.
|
|
|
|
*
|
|
|
|
************************************************************************************/
|
|
|
|
|
|
|
|
static int tcurses_vt100_terminate(FAR struct termcurses_s *dev)
|
|
|
|
{
|
|
|
|
FAR struct tcurses_vt100_s *priv;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
priv = (FAR struct tcurses_vt100_s *) dev;
|
|
|
|
fd = priv->out_fd;
|
|
|
|
|
|
|
|
/* Set default foreground and background colors.
|
|
|
|
* (Ignore the return result.)
|
|
|
|
*/
|
|
|
|
|
|
|
|
write(fd, g_setdefcolors, strlen(g_setdefcolors));
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|