mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
examples/lvglterm: support physical keyboard input
Refactor the LVGL terminal into a shared core (lvglterm.c) plus two selectable input variants: the existing on-screen touch keyboard (lvglterm_touch.c) and a new physical keyboard variant (lvglterm_kbd.c) that reads key events from a /dev/kbdN device and streams them to the shell. The input source is chosen with a Kconfig choice (touch by default, keeping the previous behaviour). The keyboard variant reads its device from CONFIG_EXAMPLES_LVGLTERM_KBD_DEV (default /dev/kbd0), overridable by the first command-line argument, and scrolls the output with the Fn cursor keys. A font choice (UNSCII 8 or 16) is added for low-resolution displays. Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
This commit is contained in:
parent
c91abf2c8d
commit
59d3a0d0ae
7 changed files with 752 additions and 358 deletions
|
|
@ -21,6 +21,12 @@
|
|||
# ##############################################################################
|
||||
|
||||
if(CONFIG_EXAMPLES_LVGLTERM)
|
||||
if(CONFIG_EXAMPLES_LVGLTERM_INPUT_KBD)
|
||||
set(lvglterm_input lvglterm_kbd.c)
|
||||
else()
|
||||
set(lvglterm_input lvglterm_touch.c)
|
||||
endif()
|
||||
|
||||
nuttx_add_application(
|
||||
NAME
|
||||
lvglterm
|
||||
|
|
@ -31,5 +37,6 @@ if(CONFIG_EXAMPLES_LVGLTERM)
|
|||
MODULE
|
||||
${CONFIG_EXAMPLES_LVGLTERM}
|
||||
SRCS
|
||||
lvglterm.c)
|
||||
lvglterm.c
|
||||
${lvglterm_input})
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -12,6 +12,56 @@ menuconfig EXAMPLES_LVGLTERM
|
|||
|
||||
if EXAMPLES_LVGLTERM
|
||||
|
||||
choice
|
||||
prompt "LVGL Terminal input source"
|
||||
default EXAMPLES_LVGLTERM_INPUT_TOUCH
|
||||
---help---
|
||||
Select how the terminal receives keystrokes. Only one input source
|
||||
is built at a time.
|
||||
|
||||
config EXAMPLES_LVGLTERM_INPUT_TOUCH
|
||||
bool "On-screen keyboard (touch)"
|
||||
---help---
|
||||
Input comes from an on-screen LVGL keyboard operated by touch; a
|
||||
command line is typed and submitted with Enter. This is the default
|
||||
and matches the original behaviour.
|
||||
|
||||
config EXAMPLES_LVGLTERM_INPUT_KBD
|
||||
bool "Physical keyboard (/dev/kbdN)"
|
||||
depends on INPUT_KEYBOARD
|
||||
---help---
|
||||
Input comes from a physical keyboard registered as a /dev/kbdN
|
||||
device; keystrokes are streamed to the shell and the output fills
|
||||
the whole screen.
|
||||
|
||||
endchoice
|
||||
|
||||
config EXAMPLES_LVGLTERM_KBD_DEV
|
||||
string "Keyboard device path"
|
||||
default "/dev/kbd0"
|
||||
depends on EXAMPLES_LVGLTERM_INPUT_KBD
|
||||
---help---
|
||||
Keyboard device the terminal reads key events from. Can also be
|
||||
overridden at run time by passing the path as the first command-line
|
||||
argument (useful when more than one keyboard is present).
|
||||
|
||||
choice
|
||||
prompt "LVGL Terminal font"
|
||||
default EXAMPLES_LVGLTERM_FONT_UNSCII_16
|
||||
---help---
|
||||
Monospaced font used to render the terminal. Use the smaller UNSCII 8
|
||||
on low-resolution displays where UNSCII 16 shows too few columns.
|
||||
|
||||
config EXAMPLES_LVGLTERM_FONT_UNSCII_8
|
||||
bool "UNSCII 8 (small)"
|
||||
select LV_FONT_UNSCII_8
|
||||
|
||||
config EXAMPLES_LVGLTERM_FONT_UNSCII_16
|
||||
bool "UNSCII 16"
|
||||
select LV_FONT_UNSCII_16
|
||||
|
||||
endchoice
|
||||
|
||||
config EXAMPLES_LVGLTERM_PRIORITY
|
||||
int "lvglterm task priority"
|
||||
default 100
|
||||
|
|
|
|||
|
|
@ -27,8 +27,15 @@ PRIORITY = $(CONFIG_EXAMPLES_LVGLTERM_PRIORITY)
|
|||
STACKSIZE = $(CONFIG_EXAMPLES_LVGLTERM_STACKSIZE)
|
||||
MODULE = $(CONFIG_EXAMPLES_LVGLTERM)
|
||||
|
||||
# LVGL Terminal
|
||||
# LVGL Terminal. lvglterm.c holds the shared core; the input source is
|
||||
# selected at build time (on-screen keyboard for touch, /dev/kbdN otherwise).
|
||||
|
||||
MAINSRC = lvglterm.c
|
||||
|
||||
ifeq ($(CONFIG_EXAMPLES_LVGLTERM_INPUT_KBD),y)
|
||||
CSRCS = lvglterm_kbd.c
|
||||
else
|
||||
CSRCS = lvglterm_touch.c
|
||||
endif
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@
|
|||
/* Reference:
|
||||
* "NuttX RTOS for PinePhone: LVGL Terminal for NSH Shell"
|
||||
* https://lupyuen.github.io/articles/terminal
|
||||
*
|
||||
* Code shared by both input variants: it starts the NSH shell with its
|
||||
* standard streams redirected through pipes, renders the shell output in an
|
||||
* LVGL text area, and delegates the input source to the selected variant
|
||||
* (on-screen keyboard in lvglterm_touch.c, physical keyboard in
|
||||
* lvglterm_kbd.c).
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -35,12 +41,15 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <nuttx/debug.h>
|
||||
#include <poll.h>
|
||||
#include <spawn.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "lvglterm.h"
|
||||
|
||||
/* NSH Task requires posix_spawn() */
|
||||
|
||||
#ifndef CONFIG_LIBC_EXECFUNCS
|
||||
|
|
@ -53,10 +62,20 @@
|
|||
# error FIFO and Named Pipe Drivers should be enabled in the configuration
|
||||
#endif
|
||||
|
||||
/* NSH Output requires a Monospaced Font */
|
||||
/* NSH Output requires a Monospaced Font. The size is selectable so that
|
||||
* low-resolution displays can use the smaller UNSCII 8.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_LV_FONT_UNSCII_16
|
||||
# error LVGL Font UNSCII 16 should be enabled in the configuration
|
||||
#if defined(CONFIG_EXAMPLES_LVGLTERM_FONT_UNSCII_8)
|
||||
# ifndef CONFIG_LV_FONT_UNSCII_8
|
||||
# error LVGL Font UNSCII 8 should be enabled in the configuration
|
||||
# endif
|
||||
# define LVGLTERM_FONT lv_font_unscii_8
|
||||
#else
|
||||
# ifndef CONFIG_LV_FONT_UNSCII_16
|
||||
# error LVGL Font UNSCII 16 should be enabled in the configuration
|
||||
# endif
|
||||
# define LVGLTERM_FONT lv_font_unscii_16
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
|
|
@ -65,12 +84,12 @@
|
|||
|
||||
/* How often to poll for output from NSH Shell (milliseconds) */
|
||||
|
||||
#define TIMER_PERIOD_MS 100
|
||||
#define TIMER_PERIOD_MS 20
|
||||
|
||||
/* Read and Write Pipes for NSH stdin, stdout and stderr */
|
||||
/* Trim the output text area once it grows past this many characters */
|
||||
|
||||
#define READ_PIPE 0
|
||||
#define WRITE_PIPE 1
|
||||
#define TERM_MAXCHARS 4096
|
||||
#define TERM_KEEPCHARS 3072
|
||||
|
||||
/* NSH Task to be started */
|
||||
|
||||
|
|
@ -81,38 +100,34 @@
|
|||
****************************************************************************/
|
||||
|
||||
static int create_widgets(void);
|
||||
static void timer_callback(lv_timer_t * timer);
|
||||
static void input_callback(lv_event_t * e);
|
||||
static bool has_input(int fd);
|
||||
static void remove_escape_codes(char *buf, int len);
|
||||
static void timer_callback(lv_timer_t *timer);
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Pipe to NSH stdin, written by the selected input variant */
|
||||
|
||||
int g_nsh_stdin[2];
|
||||
|
||||
/* LVGL Column Container and NSH Output Text Area (shared with the variant) */
|
||||
|
||||
lv_obj_t *g_col;
|
||||
lv_obj_t *g_output;
|
||||
|
||||
/* LVGL Font Style for NSH Input and Output */
|
||||
|
||||
lv_style_t g_terminal_style;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Pipes for NSH Shell: stdin, stdout, stderr */
|
||||
/* Pipes for NSH stdout and stderr */
|
||||
|
||||
static int g_nsh_stdin[2];
|
||||
static int g_nsh_stdout[2];
|
||||
static int g_nsh_stderr[2];
|
||||
|
||||
/* LVGL Column Container for NSH Widgets */
|
||||
|
||||
static lv_obj_t *g_col;
|
||||
|
||||
/* LVGL Text Area Widgets for NSH Input and Output */
|
||||
|
||||
static lv_obj_t *g_input;
|
||||
static lv_obj_t *g_output;
|
||||
|
||||
/* LVGL Keyboard Widget for NSH Terminal */
|
||||
|
||||
static lv_obj_t *g_kb;
|
||||
|
||||
/* LVGL Font Style for NSH Input and Output */
|
||||
|
||||
static lv_style_t g_terminal_style;
|
||||
|
||||
/* LVGL Timer for polling NSH Output */
|
||||
|
||||
static lv_timer_t *g_timer;
|
||||
|
|
@ -124,73 +139,188 @@ static char * const g_nsh_argv[] =
|
|||
NSH_TASK, NULL
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_has_input
|
||||
*
|
||||
* Description:
|
||||
* Return true if the file descriptor has data to be read.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
bool lvglterm_has_input(int fd)
|
||||
{
|
||||
struct pollfd fdp;
|
||||
|
||||
fdp.fd = fd;
|
||||
fdp.events = POLLIN;
|
||||
return poll(&fdp, 1, 0) > 0 && (fdp.revents & POLLIN) != 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_add_output
|
||||
*
|
||||
* Description:
|
||||
* Append text to the NSH output text area, dropping VT100 escape sequences
|
||||
* and carriage returns, honouring backspace, and trimming the buffer once
|
||||
* it grows too large. Must run in the LVGL thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lvglterm_add_output(FAR const char *buf, int len)
|
||||
{
|
||||
char clean[64];
|
||||
int ci = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
char c = buf[i];
|
||||
|
||||
if (c == 0x1b) /* ESC: skip the escape sequence */
|
||||
{
|
||||
i++;
|
||||
if (i < len && buf[i] == '[')
|
||||
{
|
||||
for (i++; i < len; i++)
|
||||
{
|
||||
if ((buf[i] >= 'A' && buf[i] <= 'Z') ||
|
||||
(buf[i] >= 'a' && buf[i] <= 'z'))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\r') /* Drop carriage return */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 0x08 || c == 0x7f) /* Backspace/DEL: erase last character */
|
||||
{
|
||||
if (ci > 0)
|
||||
{
|
||||
clean[ci] = '\0';
|
||||
lv_textarea_add_text(g_output, clean);
|
||||
ci = 0;
|
||||
}
|
||||
|
||||
lv_textarea_delete_char(g_output);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n' || c == '\t' || (c >= 0x20 && c < 0x7f))
|
||||
{
|
||||
clean[ci++] = c;
|
||||
if (ci >= (int)sizeof(clean) - 1)
|
||||
{
|
||||
clean[ci] = '\0';
|
||||
lv_textarea_add_text(g_output, clean);
|
||||
ci = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ci > 0)
|
||||
{
|
||||
clean[ci] = '\0';
|
||||
lv_textarea_add_text(g_output, clean);
|
||||
}
|
||||
|
||||
/* Trim the text area if it has grown too large */
|
||||
|
||||
if ((int)strlen(lv_textarea_get_text(g_output)) > TERM_MAXCHARS)
|
||||
{
|
||||
FAR const char *txt = lv_textarea_get_text(g_output);
|
||||
int total = strlen(txt);
|
||||
lv_textarea_set_text(g_output, txt + (total - TERM_KEEPCHARS));
|
||||
lv_textarea_set_cursor_pos(g_output, LV_TEXTAREA_CURSOR_LAST);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: create_widgets
|
||||
*
|
||||
* Description:
|
||||
* Create the shared LVGL widgets: a column container and the NSH output
|
||||
* text area. The input source is added by the selected variant.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int create_widgets(void)
|
||||
{
|
||||
/* Set the Font Style for NSH Input and Output to a Monospaced Font */
|
||||
|
||||
lv_style_init(&g_terminal_style);
|
||||
lv_style_set_text_font(&g_terminal_style, &LVGLTERM_FONT);
|
||||
|
||||
/* Create an LVGL Container with Column Flex Direction */
|
||||
|
||||
g_col = lv_obj_create(lv_scr_act());
|
||||
DEBUGASSERT(g_col != NULL);
|
||||
lv_obj_set_size(g_col, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(g_col, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(g_col, 0, 0);
|
||||
|
||||
/* Create an LVGL Text Area Widget for NSH Output */
|
||||
|
||||
g_output = lv_textarea_create(g_col);
|
||||
DEBUGASSERT(g_output != NULL);
|
||||
lv_obj_add_style(g_output, &g_terminal_style, 0);
|
||||
lv_obj_set_width(g_output, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(g_output, 1);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: create_terminal
|
||||
*
|
||||
* Description:
|
||||
* Create the LVGL Terminal. Start the NSH Shell and redirect the NSH
|
||||
* stdin, stdout and stderr to the LVGL Widgets.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value is returned on any failure.
|
||||
* Start the NSH shell with its streams redirected to pipes, create the
|
||||
* shared widgets and the output-polling timer, and set up the input
|
||||
* variant.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int create_terminal(void)
|
||||
static int create_terminal(int argc, FAR char *argv[])
|
||||
{
|
||||
int ret;
|
||||
pid_t pid;
|
||||
|
||||
/* Create the pipes for NSH Shell: stdin, stdout and stderr */
|
||||
|
||||
ret = pipe(g_nsh_stdin);
|
||||
if (ret < 0)
|
||||
if (pipe(g_nsh_stdin) < 0 || pipe(g_nsh_stdout) < 0 ||
|
||||
pipe(g_nsh_stderr) < 0)
|
||||
{
|
||||
_err("stdin pipe failed: %d\n", errno);
|
||||
_err("pipe failed: %d\n", errno);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = pipe(g_nsh_stdout);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("stdout pipe failed: %d\n", errno);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
ret = pipe(g_nsh_stderr);
|
||||
if (ret < 0)
|
||||
{
|
||||
_err("stderr pipe failed: %d\n", errno);
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Close default stdin, stdout and stderr */
|
||||
/* Close default stdin, stdout and stderr and assign the new pipes */
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
|
||||
/* Assign the new pipes as stdin, stdout and stderr */
|
||||
|
||||
dup2(g_nsh_stdin[READ_PIPE], 0);
|
||||
dup2(g_nsh_stdout[WRITE_PIPE], 1);
|
||||
dup2(g_nsh_stderr[WRITE_PIPE], 2);
|
||||
|
||||
/* Start the NSH Shell and inherit stdin, stdout and stderr */
|
||||
|
||||
ret = posix_spawn(&pid, /* Returned Task ID */
|
||||
NSH_TASK, /* NSH Path */
|
||||
NULL, /* Inherit stdin, stdout and stderr */
|
||||
NULL, /* Default spawn attributes */
|
||||
g_nsh_argv, /* Arguments */
|
||||
NULL); /* No environment */
|
||||
ret = posix_spawn(&pid, NSH_TASK, NULL, NULL, g_nsh_argv, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
int errcode = errno;
|
||||
|
|
@ -200,12 +330,10 @@ static int create_terminal(void)
|
|||
|
||||
/* Create an LVGL Timer to poll for output from NSH Shell */
|
||||
|
||||
g_timer = lv_timer_create(timer_callback, /* Callback Function */
|
||||
TIMER_PERIOD_MS, /* Timer Period (millisec) */
|
||||
NULL); /* Callback Argument */
|
||||
g_timer = lv_timer_create(timer_callback, TIMER_PERIOD_MS, NULL);
|
||||
DEBUGASSERT(g_timer != NULL);
|
||||
|
||||
/* Create the LVGL Terminal Widgets */
|
||||
/* Create the shared widgets and the input source for the variant */
|
||||
|
||||
ret = create_widgets();
|
||||
if (ret < 0)
|
||||
|
|
@ -213,67 +341,7 @@ static int create_terminal(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: create_widgets
|
||||
*
|
||||
* Description:
|
||||
* Create the LVGL Widgets for LVGL Terminal.
|
||||
*
|
||||
* Input Parameters:
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value is returned on any failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int create_widgets(void)
|
||||
{
|
||||
/* Set the Font Style for NSH Input and Output to a Monospaced Font */
|
||||
|
||||
lv_style_init(&g_terminal_style);
|
||||
lv_style_set_text_font(&g_terminal_style, &lv_font_unscii_16);
|
||||
|
||||
/* Create an LVGL Container with Column Flex Direction */
|
||||
|
||||
g_col = lv_obj_create(lv_scr_act());
|
||||
DEBUGASSERT(g_col != NULL);
|
||||
lv_obj_set_size(g_col, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(g_col, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_all(g_col, 0, 0); /* No padding */
|
||||
|
||||
/* Create an LVGL Text Area Widget for NSH Output */
|
||||
|
||||
g_output = lv_textarea_create(g_col);
|
||||
DEBUGASSERT(g_output != NULL);
|
||||
lv_obj_add_style(g_output, &g_terminal_style, 0);
|
||||
lv_obj_set_width(g_output, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(g_output, 1); /* Fill the column */
|
||||
|
||||
/* Create an LVGL Text Area Widget for NSH Input */
|
||||
|
||||
g_input = lv_textarea_create(g_col);
|
||||
DEBUGASSERT(g_input != NULL);
|
||||
lv_obj_add_style(g_input, &g_terminal_style, 0);
|
||||
lv_obj_set_size(g_input, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
|
||||
/* Create an LVGL Keyboard Widget */
|
||||
|
||||
g_kb = lv_keyboard_create(g_col);
|
||||
DEBUGASSERT(g_kb != NULL);
|
||||
lv_obj_set_style_pad_all(g_kb, 0, 0); /* No padding */
|
||||
|
||||
/* Register the Callback Function for NSH Input */
|
||||
|
||||
lv_obj_add_event_cb(g_input, input_callback, LV_EVENT_ALL, NULL);
|
||||
|
||||
/* Set the Keyboard to populate the NSH Input Text Area */
|
||||
|
||||
lv_keyboard_set_textarea(g_kb, g_input);
|
||||
|
||||
lvglterm_input_create(argc, argv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -281,224 +349,37 @@ static int create_widgets(void)
|
|||
* Name: timer_callback
|
||||
*
|
||||
* Description:
|
||||
* Callback Function for LVGL Timer. Poll NSH stdout and stderr for output
|
||||
* and display the output.
|
||||
*
|
||||
* Input Parameters:
|
||||
* timer - LVGL Timer for the callback
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
* Poll NSH stdout and stderr for output and render it, then let the input
|
||||
* variant perform its periodic work. Runs in the LVGL thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void timer_callback(lv_timer_t *timer)
|
||||
{
|
||||
int ret;
|
||||
static char buf[64];
|
||||
|
||||
DEBUGASSERT(g_nsh_stdout[READ_PIPE] != 0);
|
||||
DEBUGASSERT(g_nsh_stderr[READ_PIPE] != 0);
|
||||
|
||||
/* Poll NSH stdout to check if there's output to be processed */
|
||||
|
||||
if (has_input(g_nsh_stdout[READ_PIPE]))
|
||||
{
|
||||
/* Read the output from NSH stdout */
|
||||
|
||||
ret = read(g_nsh_stdout[READ_PIPE], buf, sizeof(buf) - 1);
|
||||
if (ret > 0)
|
||||
{
|
||||
/* Add to NSH Output Text Area */
|
||||
|
||||
buf[ret] = 0;
|
||||
remove_escape_codes(buf, ret);
|
||||
|
||||
DEBUGASSERT(g_output != NULL);
|
||||
lv_textarea_add_text(g_output, buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Poll NSH stderr to check if there's output to be processed */
|
||||
|
||||
if (has_input(g_nsh_stderr[READ_PIPE]))
|
||||
{
|
||||
/* Read the output from NSH stderr */
|
||||
|
||||
ret = read(g_nsh_stderr[READ_PIPE], buf, sizeof(buf) - 1);
|
||||
if (ret > 0)
|
||||
{
|
||||
/* Add to NSH Output Text Area */
|
||||
|
||||
buf[ret] = 0;
|
||||
remove_escape_codes(buf, ret);
|
||||
|
||||
DEBUGASSERT(g_output != NULL);
|
||||
lv_textarea_add_text(g_output, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: input_callback
|
||||
*
|
||||
* Description:
|
||||
* Callback Function for NSH Input Text Area. If Enter Key was pressed,
|
||||
* send the NSH Input Command to NSH stdin.
|
||||
*
|
||||
* Input Parameters:
|
||||
* e - LVGL Event for the callback
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void input_callback(lv_event_t *e)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Decode the LVGL Event */
|
||||
/* Drain the input variant first (local echo, scroll) so that what the user
|
||||
* typed is rendered before the resulting shell output.
|
||||
*/
|
||||
|
||||
const lv_event_code_t code = lv_event_get_code(e);
|
||||
lvglterm_input_poll();
|
||||
|
||||
/* If NSH Input Text Area has changed, get the Key Pressed */
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED)
|
||||
if (lvglterm_has_input(g_nsh_stdout[READ_PIPE]))
|
||||
{
|
||||
/* Get the Button Index of the Keyboard Button Pressed */
|
||||
|
||||
const uint16_t id = lv_keyboard_get_selected_button(g_kb);
|
||||
|
||||
/* Get the Text of the Keyboard Button */
|
||||
|
||||
const char *key = lv_keyboard_get_button_text(g_kb, id);
|
||||
if (key == NULL)
|
||||
ret = read(g_nsh_stdout[READ_PIPE], buf, sizeof(buf));
|
||||
if (ret > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If Key Pressed is Enter, send the Command to NSH stdin */
|
||||
|
||||
if (key[0] == 0xef && key[1] == 0xa2 && key[2] == 0xa2)
|
||||
{
|
||||
/* Read the NSH Input */
|
||||
|
||||
const char *cmd;
|
||||
DEBUGASSERT(g_input != NULL);
|
||||
cmd = lv_textarea_get_text(g_input);
|
||||
if (cmd == NULL || cmd[0] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send the Command to NSH stdin */
|
||||
|
||||
DEBUGASSERT(g_nsh_stdin[WRITE_PIPE] != 0);
|
||||
ret = write(g_nsh_stdin[WRITE_PIPE], cmd, strlen(cmd));
|
||||
DEBUGASSERT(ret == strlen(cmd));
|
||||
|
||||
/* Erase the NSH Input */
|
||||
|
||||
lv_textarea_set_text(g_input, "");
|
||||
lvglterm_add_output(buf, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: has_input
|
||||
*
|
||||
* Description:
|
||||
* Return true if the File Descriptor has data to be read.
|
||||
*
|
||||
* Input Parameters:
|
||||
* fd - File Descriptor to be checked
|
||||
*
|
||||
* Returned Value:
|
||||
* True if File Descriptor has data to be read; False otherwise
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static bool has_input(int fd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Poll the File Descriptor for input */
|
||||
|
||||
struct pollfd fdp;
|
||||
fdp.fd = fd;
|
||||
fdp.events = POLLIN;
|
||||
ret = poll(&fdp, /* File Descriptors */
|
||||
1, /* Number of File Descriptors */
|
||||
0); /* Poll Timeout (Milliseconds) */
|
||||
|
||||
if (ret > 0)
|
||||
if (lvglterm_has_input(g_nsh_stderr[READ_PIPE]))
|
||||
{
|
||||
/* If poll is OK and there is input */
|
||||
|
||||
if ((fdp.revents & POLLIN) != 0)
|
||||
ret = read(g_nsh_stderr[READ_PIPE], buf, sizeof(buf));
|
||||
if (ret > 0)
|
||||
{
|
||||
/* Report that there is input */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Else report no input */
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
{
|
||||
/* If timeout, report no input */
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (ret < 0)
|
||||
{
|
||||
/* Handle error */
|
||||
|
||||
_err("poll failed: %d, fd=%d\n", ret, fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Never comes here */
|
||||
|
||||
DEBUGPANIC();
|
||||
return false;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: remove_escape_codes
|
||||
*
|
||||
* Description:
|
||||
* Remove ANSI Escape Codes from the string. Assumes that buf[len] is 0.
|
||||
*
|
||||
* Input Parameters:
|
||||
* buf - String to be processed
|
||||
* len - Length of string
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void remove_escape_codes(char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
/* Escape Code looks like 0x1b 0x5b 0x4b */
|
||||
|
||||
if (buf[i] == 0x1b)
|
||||
{
|
||||
/* Remove 3 bytes */
|
||||
|
||||
for (j = i; j + 2 < len; j++)
|
||||
{
|
||||
buf[j] = buf[j + 3];
|
||||
}
|
||||
lvglterm_add_output(buf, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -511,15 +392,10 @@ static void remove_escape_codes(char *buf, int len)
|
|||
* Name: main or lvglterm_main
|
||||
*
|
||||
* Description:
|
||||
* Start an LVGL Terminal that runs interactive commands with NSH Shell.
|
||||
* NSH Commands are entered through an LVGL Keyboard. NSH Output is
|
||||
* rendered in an LVGL Widget.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Standard argc and argv
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a positive, non-zero value on failure.
|
||||
* Start an LVGL Terminal that runs interactive commands with NSH.
|
||||
* NSH output is rendered in an LVGL text area; the input comes from an
|
||||
* on-screen keyboard (touch) or a physical keyboard, selected at build
|
||||
* time.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
|
@ -534,15 +410,10 @@ int main(int argc, FAR char *argv[])
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_BOARDCTL_FINALINIT
|
||||
/* Perform architecture-specific final-initialization (if configured) */
|
||||
|
||||
boardctl(BOARDIOC_FINALINIT, 0);
|
||||
#endif
|
||||
|
||||
/* LVGL initialization */
|
||||
|
||||
lv_init();
|
||||
|
||||
lv_nuttx_dsc_init(&info);
|
||||
|
||||
#ifdef CONFIG_LV_USE_NUTTX_LCD
|
||||
|
|
@ -550,23 +421,18 @@ int main(int argc, FAR char *argv[])
|
|||
#endif
|
||||
|
||||
lv_nuttx_init(&info, &result);
|
||||
|
||||
if (result.disp == NULL)
|
||||
{
|
||||
LV_LOG_ERROR("lv_demos initialization failure!");
|
||||
LV_LOG_ERROR("lv_nuttx_init failure!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create the LVGL Widgets */
|
||||
|
||||
ret = create_terminal();
|
||||
ret = create_terminal(argc, argv);
|
||||
if (ret < 0)
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Handle LVGL tasks */
|
||||
|
||||
#ifdef CONFIG_LV_USE_NUTTX_LIBUV
|
||||
lv_nuttx_uv_loop(&ui_loop, &result);
|
||||
#else
|
||||
|
|
@ -574,13 +440,10 @@ int main(int argc, FAR char *argv[])
|
|||
{
|
||||
uint32_t idle;
|
||||
idle = lv_timer_handler();
|
||||
|
||||
/* Minimum sleep of 1ms */
|
||||
|
||||
idle = idle ? idle : 1;
|
||||
usleep(idle * 1000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
75
examples/lvglterm/lvglterm.h
Normal file
75
examples/lvglterm/lvglterm.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/lvglterm/lvglterm.h
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __APPS_EXAMPLES_LVGLTERM_LVGLTERM_H
|
||||
#define __APPS_EXAMPLES_LVGLTERM_LVGLTERM_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <stdbool.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Read and Write ends of the NSH pipes */
|
||||
|
||||
#define READ_PIPE 0
|
||||
#define WRITE_PIPE 1
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* Shared state owned by the core (lvglterm.c). The input variant writes the
|
||||
* shell input to g_nsh_stdin, adds its widgets under g_col (styled with
|
||||
* g_terminal_style) and may render into g_output.
|
||||
*/
|
||||
|
||||
extern int g_nsh_stdin[2]; /* Input variant -> NSH stdin */
|
||||
extern lv_obj_t *g_col; /* Column container (widget parent) */
|
||||
extern lv_obj_t *g_output; /* NSH output text area */
|
||||
extern lv_style_t g_terminal_style; /* Monospaced font style */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/* Shared helpers provided by the core */
|
||||
|
||||
bool lvglterm_has_input(int fd);
|
||||
void lvglterm_add_output(FAR const char *buf, int len);
|
||||
|
||||
/* Provided by the selected input variant (lvglterm_touch.c or
|
||||
* lvglterm_kbd.c). lvglterm_input_create() sets up the input source under
|
||||
* g_col and wires it to g_nsh_stdin. lvglterm_input_poll() runs on every
|
||||
* LVGL timer tick (LVGL thread) for periodic work; it may be a no-op.
|
||||
*/
|
||||
|
||||
void lvglterm_input_create(int argc, FAR char *argv[]);
|
||||
void lvglterm_input_poll(void);
|
||||
|
||||
#endif /* __APPS_EXAMPLES_LVGLTERM_LVGLTERM_H */
|
||||
228
examples/lvglterm/lvglterm_kbd.c
Normal file
228
examples/lvglterm/lvglterm_kbd.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/lvglterm/lvglterm_kbd.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Physical-keyboard input variant of the LVGL terminal: a task reads key
|
||||
* events from a /dev/kbdN keyboard device and streams them to NSH; the shell
|
||||
* output fills the whole screen. Works on any board with a keyboard driver;
|
||||
* the device defaults to CONFIG_EXAMPLES_LVGLTERM_KBD_DEV and can be
|
||||
* overridden by the first command-line argument.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/input/keyboard.h>
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "lvglterm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Out-of-band key codes for the Fn + navigation cluster (cursor keys),
|
||||
* reported by keyboard drivers that follow this convention (for example the
|
||||
* M5Stack Cardputer). Up/Down scroll the terminal instead of going to the
|
||||
* shell; drivers that do not emit these codes keep normal behaviour.
|
||||
*/
|
||||
|
||||
#define KEY_UP 0x80
|
||||
#define KEY_DOWN 0x81
|
||||
#define KEY_LEFT 0x82
|
||||
#define KEY_RIGHT 0x83
|
||||
|
||||
#define SCROLL_STEP 24 /* Pixels scrolled per Up/Down keypress */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static int g_echo[2]; /* Keyboard task -> screen (local echo) */
|
||||
static volatile int g_scroll; /* Pending scroll (lines), applied by LVGL */
|
||||
static FAR const char *g_kbddev; /* Keyboard device path (/dev/kbdN) */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: kbd_task
|
||||
*
|
||||
* Description:
|
||||
* Read key presses from the keyboard device and forward them to NSH stdin
|
||||
* (and to the echo pipe so the user sees what is typed). The Fn Up/Down
|
||||
* keys are handled locally as scroll requests.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int kbd_task(int argc, FAR char *argv[])
|
||||
{
|
||||
struct keyboard_event_s evt;
|
||||
ssize_t nread;
|
||||
int kfd;
|
||||
char ch;
|
||||
|
||||
kfd = open(g_kbddev, O_RDONLY);
|
||||
if (kfd < 0)
|
||||
{
|
||||
gerr("ERROR: open %s failed: %d\n", g_kbddev, errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
nread = read(kfd, &evt, sizeof(evt));
|
||||
if (nread != (ssize_t)sizeof(evt))
|
||||
{
|
||||
if (nread <= 0)
|
||||
{
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (evt.type != KEYBOARD_PRESS)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Fn navigation keys are handled locally: Up/Down scroll the terminal
|
||||
* (applied by the LVGL thread) and are not sent to the shell.
|
||||
* Left/Right are reserved and simply swallowed for now.
|
||||
*/
|
||||
|
||||
if (evt.code >= KEY_UP && evt.code <= KEY_RIGHT)
|
||||
{
|
||||
if (evt.code == KEY_UP)
|
||||
{
|
||||
g_scroll -= 1;
|
||||
}
|
||||
else if (evt.code == KEY_DOWN)
|
||||
{
|
||||
g_scroll += 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ch = (char)evt.code;
|
||||
if (ch == '\r')
|
||||
{
|
||||
ch = '\n';
|
||||
}
|
||||
|
||||
/* Always feed the shell. Echo only printable characters and newline
|
||||
* locally; control keys such as backspace are echoed by the shell's
|
||||
* own line editor (via its stdout) to avoid handling them twice.
|
||||
*/
|
||||
|
||||
write(g_nsh_stdin[WRITE_PIPE], &ch, 1);
|
||||
|
||||
if (ch == '\n' || ((uint8_t)ch >= 0x20 && (uint8_t)ch < 0x7f))
|
||||
{
|
||||
write(g_echo[WRITE_PIPE], &ch, 1);
|
||||
}
|
||||
}
|
||||
|
||||
close(kfd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_input_create
|
||||
*
|
||||
* Description:
|
||||
* Resolve the keyboard device (first command-line argument, else the
|
||||
* configured default) and start the task that streams key presses to NSH.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lvglterm_input_create(int argc, FAR char *argv[])
|
||||
{
|
||||
g_kbddev = (argc > 1) ? argv[1] : CONFIG_EXAMPLES_LVGLTERM_KBD_DEV;
|
||||
|
||||
if (pipe(g_echo) < 0)
|
||||
{
|
||||
gerr("ERROR: echo pipe failed: %d\n", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The read end is polled by the LVGL timer and must not block */
|
||||
|
||||
fcntl(g_echo[READ_PIPE], F_SETFL,
|
||||
fcntl(g_echo[READ_PIPE], F_GETFL) | O_NONBLOCK);
|
||||
|
||||
task_create("lvgltermkbd", SCHED_PRIORITY_DEFAULT, 2048, kbd_task, NULL);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_input_poll
|
||||
*
|
||||
* Description:
|
||||
* Apply any pending scroll and drain the local echo pipe onto the screen.
|
||||
* Runs in the LVGL thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lvglterm_input_poll(void)
|
||||
{
|
||||
char buf[64];
|
||||
int n;
|
||||
int s;
|
||||
|
||||
/* Apply any pending scroll requested by the keyboard task (Up/Down).
|
||||
* A negative value scrolls up (towards older output), positive scrolls
|
||||
* down. Consume only what we read so concurrent keypresses are not lost.
|
||||
*/
|
||||
|
||||
s = g_scroll;
|
||||
if (s != 0)
|
||||
{
|
||||
g_scroll -= s;
|
||||
lv_obj_scroll_by(g_output, 0, -s * SCROLL_STEP, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
if (lvglterm_has_input(g_echo[READ_PIPE]))
|
||||
{
|
||||
n = read(g_echo[READ_PIPE], buf, sizeof(buf));
|
||||
if (n > 0)
|
||||
{
|
||||
lvglterm_add_output(buf, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
164
examples/lvglterm/lvglterm_touch.c
Normal file
164
examples/lvglterm/lvglterm_touch.c
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/****************************************************************************
|
||||
* apps/examples/lvglterm/lvglterm_touch.c
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Touch input variant of the LVGL terminal: an on-screen LVGL keyboard feeds
|
||||
* an input text area; pressing Enter sends the line to NSH stdin. This is
|
||||
* the original PinePhone behaviour and suits touchscreen boards.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <nuttx/debug.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "lvglterm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static void input_callback(lv_event_t *e);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
/* LVGL Text Area for NSH Input and the on-screen Keyboard Widget */
|
||||
|
||||
static lv_obj_t *g_input;
|
||||
static lv_obj_t *g_kb;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: input_callback
|
||||
*
|
||||
* Description:
|
||||
* Callback for the NSH input text area. When the on-screen keyboard Enter
|
||||
* key is pressed, send the input command to NSH stdin.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void input_callback(lv_event_t *e)
|
||||
{
|
||||
int ret;
|
||||
const lv_event_code_t code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED)
|
||||
{
|
||||
const uint16_t id = lv_keyboard_get_selected_button(g_kb);
|
||||
const char *key = lv_keyboard_get_button_text(g_kb, id);
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the key pressed is Enter, send the command to NSH stdin */
|
||||
|
||||
if (key[0] == 0xef && key[1] == 0xa2 && key[2] == 0xa2)
|
||||
{
|
||||
const char *cmd;
|
||||
int len;
|
||||
|
||||
DEBUGASSERT(g_input != NULL);
|
||||
cmd = lv_textarea_get_text(g_input);
|
||||
if (cmd == NULL || cmd[0] == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Echo the command on the output so the prompt line reads
|
||||
* "nsh> <command>", then send it to the shell.
|
||||
*/
|
||||
|
||||
len = strlen(cmd);
|
||||
lvglterm_add_output(cmd, len);
|
||||
if (cmd[len - 1] != '\n')
|
||||
{
|
||||
lvglterm_add_output("\n", 1);
|
||||
}
|
||||
|
||||
DEBUGASSERT(g_nsh_stdin[WRITE_PIPE] != 0);
|
||||
ret = write(g_nsh_stdin[WRITE_PIPE], cmd, len);
|
||||
DEBUGASSERT(ret == len);
|
||||
|
||||
lv_textarea_set_text(g_input, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_input_create
|
||||
*
|
||||
* Description:
|
||||
* Create the on-screen keyboard and input text area under the shared
|
||||
* column container.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lvglterm_input_create(int argc, FAR char *argv[])
|
||||
{
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
|
||||
/* Create an LVGL Text Area Widget for NSH Input */
|
||||
|
||||
g_input = lv_textarea_create(g_col);
|
||||
DEBUGASSERT(g_input != NULL);
|
||||
lv_obj_add_style(g_input, &g_terminal_style, 0);
|
||||
lv_obj_set_size(g_input, LV_PCT(100), LV_SIZE_CONTENT);
|
||||
|
||||
/* Create an LVGL Keyboard Widget */
|
||||
|
||||
g_kb = lv_keyboard_create(g_col);
|
||||
DEBUGASSERT(g_kb != NULL);
|
||||
lv_obj_set_style_pad_all(g_kb, 0, 0);
|
||||
|
||||
/* Wire the keyboard to the input text area */
|
||||
|
||||
lv_obj_add_event_cb(g_input, input_callback, LV_EVENT_ALL, NULL);
|
||||
lv_keyboard_set_textarea(g_kb, g_input);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: lvglterm_input_poll
|
||||
*
|
||||
* Description:
|
||||
* No periodic work is needed for the touch variant.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void lvglterm_input_poll(void)
|
||||
{
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue