c - 如何在从 Linux 启动时将 NCurses 输出定向到串行终端?

标签 c linux ncurses curses

概览

我一直在使用 ncurses++ 库编写代码来显示菜单和屏幕。期望的结果是通过串行终端接口(interface)输出这些菜单和屏幕。

当前尝试

我可以通过调用使用基础 C ncurses 库成功地做到这一点。

if( (FDTERM = fopen("/dev/ttyS0", "r+")) != NULL )
{

  if(FDTERM == NULL)
  {
    fprintf(stderr, "Error opening device: %s.\n", ncurses_device); 
  }

  /* Set Screen */
  MY_SCREEN = newterm(NULL, FDTERM, FDTERM);

  if(MY_SCREEN != NULL)
  {
    /* Set the terminal */
    set_term(MY_SCREEN);
  }
}

为了让它在 c++ 中工作,我编写了一些 intercept.c 代码来覆盖 cursesw.cc 中对::initscr() 的调用实际调用的内容

#define ncurses_device  "/dev/ttyS0"

NCURSES_EXPORT(WINDOW *) initscr(void)
{
  WINDOW *result;

pthread_mutex_lock(&CUSTOM_LOCK);

if (!CUSTOM_INITIALIZED)
{
  CUSTOM_INITIALIZED = true;

  if( (FDTERM = fopen(ncurses_device, "r+")) != NULL )
  {

  if(FDTERM == NULL)
  {
    fprintf(stderr, "Error opening device: %s.\n", ncurses_device); 
  }

  /* Set Screen */
  MY_SCREEN = newterm(NULL, FDTERM, FDTERM);

  if(MY_SCREEN != NULL)
  {
    /* Set the terminal */
    set_term(MY_CDU_SCREEN);
  }

  /* def_shell_mode - done in newterm/_nc_setupscreen */
  def_prog_mode();
}
else
{
  CUSTOM_INITIALIZED = true;
  NCURSES_CONST char *name;
  if ((name = getenv("TERM")) == 0 || *name == '\0')
  {
    static char unknown_name[] = "unknown";
    name = unknown_name;
  }

  if (newterm(name, stdout, stdin) == 0)
  {
    fprintf(stderr, "Error opening terminal: %s.\n", name);
    result = NULL;
  }
 }
}
#if NCURSES_SP_FUNCS
#ifdef CURRENT_SCREEN
 NCURSES_SP_NAME(def_prog_mode) (CURRENT_SCREEN);
#else
 NCURSES_SP_NAME(def_prog_mode) (SP);
#endif
#else
 def_prog_mode();
#endif
 result = stdscr;

 pthread_mutex_unlock(&CUSTOM_LOCK);

 return Win(result);
}

intercept.c 允许使用定义的设备(如果可用)。它 还允许 initscr() 回退到使用当前终端的默认行为。

这在用于调试时有效,但我觉得必须有更好的方法来设置 NCurses 或环境以将 NCurses 输出定向到所需的串行端口。

上述解决方案现在在启动时执行代码时不起作用,因为没有可用的终端定义。

这正在开发以支持 RHEL 7 和 6。一些研究似乎指向使用 getty、agetty 或通过编辑 start-tty.conf 创建一个新的环境服务,如前所述(https://unix.stackexchange.com/a/318647)。

但另一个问题是将 NCurses++ 指向正确的环境。从我在 NCurses 源代码中看到的情况来看,::initscr() 似乎默认从 cursesw.cc 调用,这使得将 NCurses 指向新环境变得更加困难。

问题

如何设置 NCurses++ 输出到指定的 tty?

如何正确设置 NCurses 在系统启动时使用的环境?

更新 1:

更新代码以执行以下操作:

// Save the current stdin/stdout file descriptors
int saved_stdin = dup(fileno(stdin));
int saved_stdout = dup(fileno(stdout));

// Set the stdin/stdout to the desired device
freopen(ncurses_device, "w+", stdout);
freopen(ncurses_device, "r+", stdin);

// Initialize the NCursesMenu
NCursesMenu *m_pMenu =  new NCursesMenu(m_pMenuItems);

// Restore the saved_stdin/stdout to the correct locations
dup2(saved_stdin, STDIN_FILENO);
dup2(saved_stdout, STDOUT_FILENO);

// Close the saved_stdin/stdout file descriptors
close(saved_stdin);
close(saved_stdout);

这允许 NCurses 按定义复制当前文件* herenewterm 中,但是一旦 stdin/stdout FILE* 恢复为保存的文件描述符,操作就会丢失。如果设备仅指向新设备,则它适用于 NCurses,但所有调试/测试信息都不可见,因为它已被当前终端中的 NCurses 覆盖。

最佳答案

initscr 不对设备做任何假设:它使用当前输入/输出stdinstdout 初始化时(通过 newtermsetupterm,它会复制文件描述符)。

如果您的应用程序(或环境/脚本)将这些流设置为您想要连接的设备,那么对于 C++ 接口(interface)来说这应该足够了。 ncurses 不使用 C+ cout

关于c - 如何在从 Linux 启动时将 NCurses 输出定向到串行终端?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52636581/

相关文章:

c - 访问数组的奇数索引时 C 中的位移位错误

创建替换 stdin 的文件描述符(在 select() 中)

c++ - Ncurses 和 C++ 屏幕保护程序

python - 如何在Python中获取C数组

c - Visual Studio 与 GCC,关于 "' __cdecl' 属性指令被忽略 [-Wattributes]”

python - OS X UDP 发送错误 : 55 No buffer space available

linux - ./MakeOVPN.sh : line 12: [! -fDanielIphone.crt]:找不到命令

linux shell 日期问题

c++ - NCurses 中有获取窗口位置的函数吗?

c++ - 如何用ncurses画一条线?