in system/termcurses/tcurses_vt100.c [1131:1416]
static int tcurses_vt100_getkeycode(FAR struct termcurses_s *dev,
FAR int *specialkey,
FAR int *keymodifiers)
{
FAR struct tcurses_vt100_s *priv;
FAR 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 */
tv.tv_sec = 0;
tv.tv_usec = 1000;
/* Loop until we have a valid key code, taking escape sequences
* into account
*/
keycode = -1;
*keymodifiers = 0;
*specialkey = 0;
ismodifier = false;
keybuildcount = 0;
while (keycode == -1)
{
/* Test if keybuf has unprocessed bytes */
if (priv->keycount == 0)
{
/* Get next bytes from input stream */
priv->keycount = read(fd, priv->keybuf, sizeof(priv->keybuf)-1);
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];
if (ch == 0 && x + 1 == priv->keycount)
{
priv->keycount = 0;
return -1;
}
/* Test for escape sequence */
if (ch == '\x1b')
{
#ifdef CONFIG_SYSTEM_TERMCURSES_DEBUG_KEYCODES
printf("<0x%02X>", ch);
fflush(stdout);
#endif
/* Mark as ESC sequence */
esc_seq = true;
ctrl_seq = false;
buildkey[0] = ch;
keybuildcount = 1;
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' */
if (buildkey[keybuildcount - 1] == '1')
{
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;
buildkey[keybuildcount] = 0;
/* 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 */
buildkey[0] = ch;
keybuildcount = 1;
ctrl_seq = 1;
#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;
if (priv->keycount < 0)
{
/* Hmm, some bug. Better to simply ignore than to crash */
priv->keycount = 0;
}
if (priv->keycount != 0)
{
memmove(priv->keybuf, &priv->keybuf[x], priv->keycount);
}
}
return keycode;
}