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

Posted

技术标签:

【中文标题】将终端设置为原始模式:仅在按下下一个键后才显示字符【英文标题】:Setting terminal to raw mode: Character is displayed only after next key pressed 【发布时间】:2017-07-27 11:10:35 【问题描述】:

我正在学习如何编写基本 SSH 客户端的教程 http://api.libssh.org/master/libssh_tutor_shell.html

我不希望在(本地)终端中回显 ENTER 键作为换行符。另外,我希望输入在准备好后立即被读取和发送,而不是在按下 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);

【问题讨论】:

【参考方案1】:

您的程序在read 函数中花费了所有时间。所以它永远不会调用ssh_channel_read_nonblocking,直到按下一个键。

流程如下:

    我按了一个键。 您将该密钥发送到另一端。 由于if (!kbhit) 为真(因为kbhit 不为NULL),所以我们转到read。 另一方通过 ssh 通道向我们发送回显,但我们不会读取它,因为我们在标准输入上的 read 中被阻止。 你按下下一个键,我们循环,调用ssh_channel_read_nonblocking,得到回显,回显。

也许你应该调用kbhit函数而不是测试函数指针是否为假。

【讨论】:

以上是关于将终端设置为原始模式:仅在按下下一个键后才显示字符的主要内容,如果未能解决你的问题,请参考以下文章

Windows 7 上的 WPF 应用程序只有在按下 CTRL 键后才能正常响应

STM32F4程序只有在按下复位按钮后才会运行

JTable keypressed 事件仅在按下的第一个键时触发

将焦点设置在 Popup 的 textInput 控件上

didDeselectRowAtIndexPath 仅在按下另一个单元格后调用[重复]

子视图的 viewDidAppear