C++ 将终端设置为原始模式:仅在按下下一个键后显示字符

C++ 将终端设置为原始模式:仅在按下下一个键后显示字符,c++,c,linux,ssh,C++,C,Linux,Ssh,我正在学习如何编写基本SSH客户端的教程 我不希望ENTER键作为换行符在(本地)终端中回显。此外,我希望输入被读取和发送,一旦它准备好,而不是在输入已按下 使用下面的代码,我试图实现这一点 然而,问题是,在客户端终端中,每当按下一个键时,该字符在下一次按键后首先显示。这种行为的原因是什么 此功能确定是否已按下某个键: int kbhit() { struct timeval tv = {0L, 0L}; fd_set fds; FD_ZERO(&fds);

我正在学习如何编写基本SSH客户端的教程

我不希望ENTER键作为换行符在(本地)终端中回显。此外,我希望输入被读取和发送,一旦它准备好,而不是在输入已按下

使用下面的代码,我试图实现这一点

然而,问题是,在客户端终端中,每当按下一个键时,该字符在下一次按键后首先显示。这种行为的原因是什么

此功能确定是否已按下某个键:

int kbhit()
{
    struct timeval tv = {0L, 0L};
    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(0, &fds);
    return select(1, &fds, NULL, NULL, &tv);
}
从/向服务器读取/发送数据:

struct termios term_attr;
struct termios old_attr;

tcgetattr(STDIN_FILENO, &old_attr);
cfmakeraw(&term_attr);
tcsetattr(STDIN_FILENO, TCSANOW, &term_attr);

while (ssh_channel_is_open(channel) && !ssh_channel_is_eof(channel))
{
    nbytes = ssh_channel_read_nonblocking(channel, buff, sizeof(buff), 0);

    if (nbytes < 0)
    {
        return SSH_ERROR;
    }

    if (nbytes > 0)
    {
        nwritten = write(1, buff, nbytes);

        if (nwritten != nbytes)
        {
            return SSH_ERROR;
        }
    }

    if (!kbhit)
    {
        usleep(5000L);
        continue;
    }

    nbytes = read(0, buff, sizeof(buff));

    if (nbytes < 0)
    {
        return SSH_ERROR;
    }

    if (nbytes > 0)
    {
        nwritten = ssh_channel_write(channel, buff, nbytes);

        if (nwritten != nbytes)
        {
            return SSH_ERROR;
        }
    }
}

tcsetattr(STDIN_FILENO, TCSANOW, &old_attr);
struct termios term\u attr;
结构术语旧属性;
tcgetattr(标准文件号和旧文件号);
cfmakeraw(和术语属性);
tcsetattr(标准文件号、TCSANOW和术语属性);
而(ssh_通道是开放的(通道)&!ssh_通道是开放的(通道))
{
nbytes=ssh\u channel\u read\u nonblocking(channel,buff,sizeof(buff),0);
如果(n字节<0)
{
返回SSH_错误;
}
如果(n字节>0)
{
nwrited=write(1,buff,n字节);
如果(nwrited!=n字节)
{
返回SSH_错误;
}
}
如果(!kbhit)
{
usleep(5000L);
继续;
}
n字节=读取(0,buff,sizeof(buff));
如果(n字节<0)
{
返回SSH_错误;
}
如果(n字节>0)
{
nwrited=ssh\u channel\u write(channel,buff,n字节);
如果(nwrited!=n字节)
{
返回SSH_错误;
}
}
}
tcsetattr(标准文件号、TCSANOW和旧属性);

您的程序将所有时间都阻塞在
读取功能中。因此,它永远不会调用
ssh\u channel\u read\u nonblocking
,直到按下一个键

以下是流程:

  • 我按了一个键
  • 你把钥匙送到另一边去
  • 既然
    如果(!kbhit)
    为真(因为
    kbhit
    不为空),我们就转到
    读取
  • 另一方通过ssh通道向我们发送回显,但我们不会读取它,因为我们在stdin上的
    read
    中被阻塞
  • 点击下一个键,我们循环,调用
    ssh\u channel\u read\u nonblocking
    ,获取回音,然后回音

  • 也许您应该调用
    kbhit
    函数,而不是测试函数指针是否为false。

    您的程序将其所有时间都阻塞在
    read
    函数中。因此,它永远不会调用
    ssh\u channel\u read\u nonblocking
    ,直到按下一个键

    以下是流程:

  • 我按了一个键
  • 你把钥匙送到另一边去
  • 既然
    如果(!kbhit)
    为真(因为
    kbhit
    不为空),我们就转到
    读取
  • 另一方通过ssh通道向我们发送回显,但我们不会读取它,因为我们在stdin上的
    read
    中被阻塞
  • 点击下一个键,我们循环,调用
    ssh\u channel\u read\u nonblocking
    ,获取回音,然后回音
  • 也许您应该调用
    kbhit
    函数,而不是测试函数指针是否为false