按键后如何立即读取终端的输入缓冲区 [英] How to read terminal's input buffer immediately after keypress

查看:137
本文介绍了按键后如何立即读取终端的输入缓冲区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的c程序中读取箭头按键,并用其他字符串替换它们(立即在终端本身中).我正在尝试在UNIX终端中实现bash历史记录功能.我写了这段代码.

I want to read arrow keypresses in my c program and replace them(immediately in the terminal itself) by some other string. I am trying to implement the bash history functionality as in unix terminals. I wrote this code.

int
main(int argc, char *argv[])
{
    char c;
    char str[1024];
    int i = 0;
    while((c = fgetc(stdin)) != '\n'){
      if(((int)c) == 27){
        c=fgetc(stdin);
        c=fgetc(stdin);
        if (c == 'A')
        {
          printf("%c[A%c[2K",27, 27);
          printf("UP");
        }
      }
      str[i++] = c;
    }
    printf("\n");

  return 0;
}

但是,这不起作用,因为终端等待换行符或EOF将输入缓冲区发送到stdin.因此,我必须按Enter/Return键才能分析用户输入.

But, this doesn't work because terminals wait for a newline or EOF to send the input buffer to stdin. So, I have to press enter/return key to analyze the user input.

在此答案中,提到用户使用system ("/bin/stty raw");,但这代替了所有默认的终端行为(例如,退格键) ,删除等).

Here in this answer the user mentioned to use system ("/bin/stty raw"); but this replaces all the default terminal behaviours (e.g. backspace, delete etc).

那么,有什么方法可以直接读取/操作终端输入缓冲区并在检测到箭头键时调整缓冲区本身吗?

So, is there any way I can read/manipulate the terminals input buffer directly and tweak the buffer itself if arrow keypress is detected?

环境-Ubuntu(Linux)

更新1:是否有一种方法可以改变信号/中断(默认是按Enter键),从而使终端将存储的输入发送到缓冲区?这也可以帮助我实现相同的行为.

Update 1: Is there a method to change the signal/interrupt (default is pressing enter key) that makes the terminal send the stored input to buffer? This may also help me achieve the same behaviour.

最终密码:

通过检查strace bash

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>

#define ESCAPE '\33'
#define BACKSPACE '\177'
#define DELETE '~'

int main(){
    struct termios termios_p;
    struct termios termios_save;
    tcgetattr(0, &termios_p);
    termios_save = termios_p;

    termios_p.c_lflag &= ~(ICANON|ECHO);
    tcsetattr(0,TCSANOW, &termios_p);
    char buff;
    while(read(0, &buff, 1) >= 0){
        if(buff > 0){
            if(buff == ESCAPE){
                read(0, &buff, 1);
                read(0, &buff, 1);
                if(buff == 'A'){
                    write(2, "up", 2);
                }else if(buff == 'B'){
                    write(2, "down", 4);

                }else if(buff == 'C'){
                    write(2, "\33[C", 3);

                }else if(buff == 'D'){
                    write(2, "\10", 2);                    
                }
            }else if(buff == BACKSPACE){
                write(2, "\10\33[1P", 5);
            }else if(buff == DELETE){
                write(2, "\33[1P", 4);
            }else{
                write(2,&buff,1);
            }
            // write(2,&buff,1);
            if(buff == 'q'){
                break;
            }
        }
    }
    tcsetattr(0,TCSANOW, &termios_save);
    return 0;
}

推荐答案

似乎您正在寻找类似的东西.

It seems you are looking for something like this.

程序实际上等待用户输入.如果按下向上箭头键,程序将打印按下箭头键",然后退出.如果按下了其他任何按钮,它将等待用户完成键入的内容并打印出来,然后退出.

The program essentially waits for user input. If up arrow key is pressed, the program prints "Arrow key pressed" and then exits. If anything else is pressed, it waits for the user to complete what he is typing and prints it, then exits.

#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
  struct termios oldt, newt;
  char ch, command[20];
  int oldf;

  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~(ICANON | ECHO);
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
  fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

  while(1)
  {
    ch = getchar();
    if (ch == '\033')
    { printf("Arrow key\n"); ch=-1; break;}
    else if(ch == -1) // by default the function returns -1, as it is non blocking
    {
      continue;
    }
    else
    {
      break;
    }

  }
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  fcntl(STDIN_FILENO, F_SETFL, oldf);

   if(ch != EOF)
   {
      ungetc(ch,stdin);ith
      putchar(ch);
      scanf("%s",command);
      printf("\n%s\n",command);

      return 1;
    }

    return 0;
  }

这篇关于按键后如何立即读取终端的输入缓冲区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆