Linux 的 kbhit()[和 getch()] 的问题 [英] Problem with kbhit()[and getch()] for Linux

查看:32
本文介绍了Linux 的 kbhit()[和 getch()] 的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

while(ch != 'q'){printf("循环
");睡眠(1);如果(kbhit()){ch = readch();printf("你点击了 %c
",ch);}}

此代码为我提供了一个类似 getch() 的阻塞功能.我正在尝试使用此代码来捕获向上向下箭头键.

添加:尝试捕获向上箭头的关键代码给了我 3 个字符 27、91 和 65.使用 if/else 我正在尝试模式匹配,但我只得到 2 个字符.按下下一个键时捕获下一个.

我想使用 getchar() 捕获完整的单词,同时始终寻找某些键(esc、del 等).

解决方案

这个例子可以帮助:

raw.c - 原始模式演示

/* 原始模式演示 *//* 准确查看从终端传输的内容.去做这个我们必须更加小心.*/#include <stdio.h>#include <signal.h>#include <termios.h>#include <stdlib.h>#include <unistd.h>结构 termios oldtermios;int ttyraw(int fd){/* 设置终端模式如下:非规范模式 - 关闭 ICANON.关闭信号生成 (ISIG)包括 BREAK 字符 (BRKINT).关闭任何可能的输入预处理 (IEXTEN).关闭 ECHO 模式.禁用输入上的 CR 到 NL 映射.禁用输入奇偶校验检测 (INPCK).禁用输入上第八位的剥离 (ISTRIP).禁用流量控制 (IXON).使用八位字符 (CS8).禁用奇偶校验 (PARENB).禁用任何依赖于实现的输出处理 (OPOST).一次输入一个字节(MIN=1,TIME=0).*/结构termios newtermios;if(tcgetattr(fd, &oldtermios) < 0)返回(-1);newtermios = oldtermios;newtermios.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);/* 好吧,为什么是 IEXTEN?如果 IEXTEN 打开,则 DISCARD 字符被识别并且不传递给进程.这字符导致输出暂停,直到另一个收到丢弃.用于作业控制的 DSUSP 字符,删除任何特殊含义的 LNEXT 字符以下字符、REPRINT 字符和一些其他人也属于这一类.*/newtermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);/* 如果输入字符以错误的奇偶校验到达,则 INPCK被检查.如果设置了此标志,则检查 IGNPAR查看是否应忽略具有奇偶校验错误的输入字节.如果它不应该被忽略,那么 PARMRK 会确定什么进程将实际看到的字符序列.当我们关闭 IXON 时,可以读取开始和停止字符.*/newtermios.c_cflag &= ~(CSIZE | PARENB);/* CSIZE 是一个掩码,用于确定每个字节的位数.PARENB 启用对输入和奇偶校验生成的奇偶校验关于输出.*/newtermios.c_cflag |= CS8;/* 为每个字符设置 8 位.*/newtermios.c_oflag &= ~(OPOST);/* 这包括将制表符扩展到空格等内容.*/newtermios.c_cc[VMIN] = 1;newtermios.c_cc[VTIME] = 0;/* 你告诉我为什么 TCSAFLUSH.*/if(tcsetattr(fd, TCSAFLUSH, &newtermios) < 0)返回(-1);返回(0);}int ttyreset(int fd){if(tcsetattr(fd, TCSAFLUSH, &oldtermios) < 0)返回(-1);返回(0);}无效 sigcatch(int sig){ttyreset(0);退出(0);}主函数(){诠释我;字符 c;/* 捕捉最流行的信号.*/if((int) 信号(SIGINT,sigcatch) < 0){错误(信号");退出(1);}if((int)信号(SIGQUIT,sigcatch) < 0){错误(信号");退出(1);}if((int) 信号(SIGTERM,sigcatch) < 0){错误(信号");退出(1);}/* 在标准输入上设置原始模式.*/如果(ttyraw(0)<0){fprintf(stderr,"无法进入原始模式.
");退出(1);}而( (i = 读取(0, &c, 1)) == 1){if( (c &= 255) == 0177)/* ASCII 删除 */休息;printf("%o

", c);}如果(ttyreset(0)<0){fprintf(stderr, "无法重置终端!
");退出(-1);}如果(我<0){fprintf(stderr,"读取错误.
");退出(-1);}返回0;}

(退格停止演示,origin)p>

while(ch != 'q') 
{
  printf("looping
");
  sleep(1);
  if(kbhit()) 
   {
    ch = readch();
    printf("you hit %c
",ch);
   }
}

This code gives me a blocking getch() like functionality. I am trying to use this code to capture up down arrow keys.

Added: Trying to capture key codes of up arrow gives me 3 chars 27, 91 and 65. Using if/else I am trying pattern matching but I only get 2 chars. Next one is captured when next key is pressed.

I want to capture full words using getchar() while always looking for certain keys all the time(esc, del etc.).

解决方案

This example could help:

raw.c - raw mode demonstration

/* Raw mode demo */
/* See exactly what is being transmitted from the terminal. To do this
   we have to be more careful. */

#include <stdio.h>
#include <signal.h>
#include <termios.h>
#include <stdlib.h>
#include <unistd.h>

struct termios oldtermios;

int ttyraw(int fd)
{
    /* Set terminal mode as follows:
       Noncanonical mode - turn off ICANON.
       Turn off signal-generation (ISIG)
        including BREAK character (BRKINT).
       Turn off any possible preprocessing of input (IEXTEN).
       Turn ECHO mode off.
       Disable CR-to-NL mapping on input.
       Disable input parity detection (INPCK).
       Disable stripping of eighth bit on input (ISTRIP).
       Disable flow control (IXON).
       Use eight bit characters (CS8).
       Disable parity checking (PARENB).
       Disable any implementation-dependent output processing (OPOST).
       One byte at a time input (MIN=1, TIME=0).
    */
    struct termios newtermios;
    if(tcgetattr(fd, &oldtermios) < 0)
        return(-1);
    newtermios = oldtermios;

    newtermios.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
    /* OK, why IEXTEN? If IEXTEN is on, the DISCARD character
       is recognized and is not passed to the process. This 
       character causes output to be suspended until another
       DISCARD is received. The DSUSP character for job control,
       the LNEXT character that removes any special meaning of
       the following character, the REPRINT character, and some
       others are also in this category.
    */

    newtermios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
    /* If an input character arrives with the wrong parity, then INPCK
       is checked. If this flag is set, then IGNPAR is checked
       to see if input bytes with parity errors should be ignored.
       If it shouldn't be ignored, then PARMRK determines what
       character sequence the process will actually see.

       When we turn off IXON, the start and stop characters can be read.
    */

    newtermios.c_cflag &= ~(CSIZE | PARENB);
    /* CSIZE is a mask that determines the number of bits per byte.
       PARENB enables parity checking on input and parity generation
       on output.
    */

    newtermios.c_cflag |= CS8;
    /* Set 8 bits per character. */

    newtermios.c_oflag &= ~(OPOST);
    /* This includes things like expanding tabs to spaces. */

    newtermios.c_cc[VMIN] = 1;
    newtermios.c_cc[VTIME] = 0;

    /* You tell me why TCSAFLUSH. */
    if(tcsetattr(fd, TCSAFLUSH, &newtermios) < 0)
        return(-1);
    return(0);
}

int ttyreset(int fd)
{
    if(tcsetattr(fd, TCSAFLUSH, &oldtermios) < 0)
        return(-1);

    return(0);
}

void sigcatch(int sig)
{
    ttyreset(0);
    exit(0);
}

int main()
{
    int i;
    char c;

    /* Catch the most popular signals. */
    if((int) signal(SIGINT,sigcatch) < 0)
    {
        perror("signal");
        exit(1);
    }
    if((int)signal(SIGQUIT,sigcatch) < 0)
    {
        perror("signal");
        exit(1);
    }
    if((int) signal(SIGTERM,sigcatch) < 0)
    {
        perror("signal");
        exit(1);
    }

    /* Set raw mode on stdin. */
    if(ttyraw(0) < 0)
    {
        fprintf(stderr,"Can't go to raw mode.
");
        exit(1);
    }

    while( (i = read(0, &c, 1)) == 1)
    {
        if( (c &= 255) == 0177) /* ASCII DELETE */
            break;
        printf( "%o

", c);
    }

    if(ttyreset(0) < 0)
    {
        fprintf(stderr, "Cannot reset terminal!
");
        exit(-1);
    }

    if( i < 0)
    {
        fprintf(stderr,"Read error.
");
        exit(-1);
    }

    return 0;
}

(backspace to stop the demo, origin)

这篇关于Linux 的 kbhit()[和 getch()] 的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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