免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
论坛 程序设计 C/C++ kbhit
最近访问板块 发新帖
查看: 3319 | 回复: 5
打印 上一主题 下一主题

kbhit [复制链接]

docom 该用户已被删除
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-04-08 20:53 |只看该作者 |倒序浏览
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
2 [报告]
发表于 2005-04-09 01:25 |只看该作者

kbhit

getchar()是blocking函数. 你要non-blocking函数.

window: kbhit()
unix: 这个函数simulator
http://www.pwilson.net/kbhit.html

/* ***************************************************************************
*
*          Copyright 1992-2005 by Pete Wilson All Rights Reserved
*           50 Staples Street : Lowell Massachusetts 01851 : USA
*        http://www.pwilson.net/   pete@pwilson.net   +1 978-454-4547
*
* This item is free software: you can redistribute it and/or modify it as
* long as you preserve this copyright notice. Pete Wilson prepared this item
* hoping it might be useful, but it has NO WARRANTY WHATEVER, not even any
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*************************************************************************** */

/* ***************************************************************************
*
*                          KBHIT.C
*
* Based on the work of W. Richard Stevens in "Advanced Programming in
*   the Unix Environment," Addison-Wesley; and of Floyd Davidson.
*
* Contains these functions:
*
*  To set the TTY mode:
*     tty_set_raw() Unix setup to read a character at a time.
*     tty_set_cooked() Unix setup to reverse tty_set_raw()
*
*  To read keyboard input:
*     kb_getc()      keyboard get character, NON-BLOCKING. If a char
*                      has been typed, return it. Else return 0.
*     kb_getc_w()    kb get char with wait: BLOCKING. Wait for a char
*                      to be typed and return it.
*
*  How to use:
*     tty_set_raw()  set the TTY mode to read one char at a time.
*     kb_getc()      read chars one by one.
*     tty_set_cooked() VERY IMPORTANT: restore cooked mode when done.
*
* Revision History:
*
*     DATE                  DESCRIPTION
* -----------    --------------------------------------------
* 12-jan-2002     new
* 20-aug-2002     cleanup
*
* Notes:
* -----------    --------------------------------------------
* 25-nov-2003     notate anomoly in some Unices: termattr.c_cc[VMIN] = 0;
*************************************************************************** */

#ifdef __cplusplus
  extern "C" {
#endif

#include <stdio.h>;
#include <stdlib.h>;
#include <string.h>;
#include <termios.h>;
#include <unistd.h>;
#include <errno.h>;

#ifndef STDIN_FILENO
  #define STDIN_FILENO 0
#endif

extern int errno;                 

static struct termios termattr, save_termattr;
static int ttysavefd = -1;
static enum
{
  RESET, RAW, CBREAK
} ttystate = RESET;

/* ***************************************************************************
*
* set_tty_raw(), put the user's TTY in one-character-at-a-time mode.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_raw(void)
{
  int i;

  i = tcgetattr (STDIN_FILENO, &termattr);
  if (i < 0)
  {
    printf("tcgetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
    perror ("";
    return -1;
  }
  save_termattr = termattr;

  termattr.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
  termattr.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
  termattr.c_cflag &= ~(CSIZE | PARENB);
  termattr.c_cflag |= CS8;
  termattr.c_oflag &= ~(OPOST);
   
  termattr.c_cc[VMIN] = 1;  /* or 0 for some Unices;  see note 1 */
  termattr.c_cc[VTIME] = 0;

  i = tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
  if (i < 0)
  {
    printf("tcsetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
    perror("";
    return -1;
  }
   
  ttystate = RAW;
  ttysavefd = STDIN_FILENO;

  return 0;
}

/* ***************************************************************************
*
* set_tty_cbreak(), put the user's TTY in cbreak mode.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_cbreak()
{
  int i;

  i = tcgetattr (STDIN_FILENO, &termattr);
  if (i < 0)
  {
    printf("tcgetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
    perror ("";
    return -1;
  }

  save_termattr = termattr;

  termattr.c_lflag &= ~(ECHO | ICANON);
  termattr.c_cc[VMIN] = 1;
  termattr.c_cc[VTIME] = 0;
      
  i = tcsetattr (STDIN_FILENO, TCSANOW, &termattr);
  if (i < 0)
  {
    printf("tcsetattr() returned %d for fildes=%d\n",i,STDIN_FILENO);
    perror ("";
    return -1;
  }
  ttystate = CBREAK;
  ttysavefd = STDIN_FILENO;

  return 0;
}

/* ***************************************************************************
*
* set_tty_cooked(), restore normal TTY mode. Very important to call
*   the function before exiting else the TTY won't be too usable.
* returns 0 on success, -1 on failure.
*
*************************************************************************** */
int
set_tty_cooked()
{
  int i;
  if (ttystate != CBREAK && ttystate != RAW)
  {
    return 0;
  }
  i = tcsetattr (STDIN_FILENO, TCSAFLUSH, &save_termattr);
  if (i < 0)
  {
    return -1;
  }
  ttystate = RESET;
  return 0;
}

/* ***************************************************************************
*
* kb_getc(), if there's a typed character waiting to be read,
*   return it; else return 0.
*
*************************************************************************** */
unsigned char
kb_getc(void)
{
  unsigned char ch;
  ssize_t size;

  size = read (STDIN_FILENO, &ch, 1);
  if (size == 0)
  {
    return 0;
  }
  else
  {
    return ch;
  }
}

/* ***************************************************************************
*
* kb_getc_w(), wait for a character to be typed and return it.
*
*************************************************************************** */
unsigned char
kb_getc_w(void)
{
  unsigned char ch;
  size_t size;

  while (1)
  {

    usleep(20000);        /* 1/50th second: thanks, Floyd! */

    size = read (STDIN_FILENO, &ch, 1);
    if (size >; 0)
    {
      break;
    }
  }
  return ch;
}


#define TEST
#ifdef TEST

void echo(unsigned char ch);

static enum
{
  CH_ONLY, CH_HEX
} how_echo = CH_ONLY;

int
main(int argc, char * argv[])
{
  unsigned char ch;

  printf("Test Unix single-character input.\n";

  set_tty_raw();         /* set up character-at-a-time */
  
  while (1)              /* wait here for a typed char */
  {
    usleep(20000);       /* 1/50th second: thanks, Floyd! */
    ch = kb_getc();      /* char typed by user? */
    if (0x03 == ch)      /* might be control-C */
    {
      set_tty_cooked();  /* control-C, restore normal TTY mode */
      return 1;          /* and get out */
    }
    echo(ch);            /* not control-C, echo it */
  }
}

void
echo(unsigned char ch)
{
  switch (how_echo)
  {
  case CH_HEX:
    printf("%c,0x%x  ",ch,ch);
    break;
  default:
  case CH_ONLY:
    printf("%c", ch);
    break;
  }

  fflush(stdout);      /* push it out */
}

#endif /* test */


#ifdef __cplusplus
}
#endif


/* ----- Notes -----

1. Some flavors of Unix need termattr.c_cc[VMIN] = 0 here else the read() in kb_getc() blocks:

-- MPC7400 G4 MAC running Yellowdog Linux with a 2.4.18 Kernel. Thanks to Jon Harrison.

----- */

论坛徽章:
0
3 [报告]
发表于 2005-04-09 15:24 |只看该作者

kbhit

好长阿
我觉得用一个select就可以解决5秒的问题
如果想直接接收到键盘字符而不用回车来确认
用一个tcsetattr也解决了

论坛徽章:
0
4 [报告]
发表于 2005-04-10 16:13 |只看该作者

kbhit

你不会再信号处理函数中发送一个自定义的控制字符给getchar(),然后判断一下,如果是你发送的控制字符,就说明是超时,。。。。。。。。

论坛徽章:
0
5 [报告]
发表于 2005-04-10 16:29 |只看该作者

kbhit

我觉得把signal放在alarm上面就行

论坛徽章:
0
6 [报告]
发表于 2005-04-20 01:28 |只看该作者

kbhit

原来不行的原因是即使超时,最后还是跑回getchar里面去,所以程序无论怎么超时都会停在哪里
不过在同一个进程内部用这种方式不好。例如在getchar的内部分配了一些资源,然后由于超时强行恢复堆栈跳出来,那之前已经分配的资源就没有人释放了。所以除非你确定timeout会跳过的代码里面不会导致资源泄漏,否则就不要在同一个进程内部用这种机制

#include <stdio.h>;
#include <stdlib.h>;
#include <sys/types.h>;
#include <signal.h>;
#include <setjmp.h>;

#define TIMEOUT 5
void sigProcess(int);
static jmp_buf env;
main(void)
{
    int ret ;
    printf("The program is about to get a character from the keyboard:\n");
    alarm(TIMEOUT);
    signal(SIGALRM,sigProcess);

    if ((ret=setjmp(env))==0){
            getchar();
            alarm(0) ; //注意保护
            printf("haha\n");
            return 0 ;
    }
    alarm(0) ;//这是一个好习惯
    printf("ret=%d\n",ret);
}

void sigProcess(int signo)
{
    signal(SIGALRM,SIG_DFL);
    printf("In the signal process function: TIMEOUT\n");
    longjmp(env, 5);
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP