📄 kbhit.txt
字号:
Date: Sat, 4 May 1996 00:23:30 +0200 (MET DST)From: Jens M Andreasen <jens-and@dsv.su.se>To: Steve Summit <scs@eskimo.com>Subject: Re: comp.lang.c Answers to Frequently Asked Questions (FAQ List) In-Reply-To: <1996May01.0302.scs.0001@eskimo.com> Message-ID: <Pine.ULT.3.91.960504001243.21030A-100000@mars.dsv.su.se>Hej SteveBefore I loose my account I will pass on this list of solutions to "kbhit"that I once received in personal email. You will recognize the beginning ...// Jens M Andreasen-------------------------------------------------------------------Here's some stuff I've been collecting on this general subject.I used to send it out in response to this question when it showedup in comp.lang.c, but I've stopped reading that group.The comp.lang.c Frequently Answered Questions list says, in part:Section 16. System Dependencies16.1: How can I read a single character from the keyboard without waiting for a newline?A: Contrary to popular belief and many people's wishes, this is not a C-related question. (Nor are closely-related questions concerning the echo of keyboard input.) The delivery of characters from a "keyboard" to a C program is a function of the operating system in use, and has not been standardized by the C language. Some versions of curses have a cbreak() function which does what you want. If you're specifically trying to read a short password without echo, you might try getpass(). Under Unix, use ioctl to play with the terminal driver modes (CBREAK or RAW under "classic" versions; ICANON, c_cc[VMIN] and c_cc[VTIME] under System V or Posix systems). Under MS-DOS, use getch(). Under VMS, try the Screen Management (SMG$) routines, or curses, or issue low-level $QIO's with the IO$_READVBLK (and perhaps IO$M_NOECHO) function codes to ask for one character at a time. Under other operating systems, you're on your own. Beware that some operating systems make this sort of thing impossible, because character collection into input lines is done by peripheral processors not under direct control of the CPU running your program.NOTE--> Operating system specific questions are not appropriate forNOTE--> comp.lang.c . Many common questions are answered inNOTE--> frequently-asked questions postings in such groups asNOTE--> comp.unix.questions and comp.os.msdos.programmer . Note thatNOTE--> the answers are often not unique even across different variantsNOTE--> of a system; bear in mind when answering system-specificNOTE--> questions that the answer that applies to your system may notNOTE--> apply to everyone else's. References: PCS Sec. 10 pp. 128-9, Sec. 10.1 pp. 130-1.16.2: How can I find out if there are characters available for reading (and if so, how many)? Alternatively, how can I do a read that will not block if there are no characters available?A: These, too, are entirely operating-system-specific. Some versions of curses have a nodelay() function. Depending on your system, you may also be able to use "nonblocking I/O", or a system call named "select", or the FIONREAD ioctl, or kbhit(), or rdchk(), or the O_NDELAY option to open() or fcntl().The comp.unix.questions Frequently Answered Posting says:With the variety of Unix systems in the world, it's hard to guaranteethat these answers will work everywhere. Read your local manual pagesbefore trying anything suggested here. If you have suggestions orcorrections for any of these answers, please send them to totmatimar@nff.ncl.omron.co.jp.1) How do I read characters from a terminal without requiring the user to hit RETURN? Check out cbreak mode in BSD, ~ICANON mode in SysV. If you don't want to tackle setting the terminal parameters yourself (using the "ioctl(2)" system call) you can let the stty program do the work - but this is slow and inefficient, and you should change the code to do it right some time: #include <stdio.h> main() { int c; printf("Hit any character to continue\n"); /* * ioctl() would be better here; only lazy * programmers do it this way: */ system("/bin/stty cbreak"); /* or "stty raw" */ c = getchar(); system("/bin/stty -cbreak"); printf("Thank you for typing %c.\n", c); exit(0); } You might like to check out the documentation for the "curses" library of portable screen functions. Often if you're interested in single-character I/O like this, you're also interested in doing some sort of screen display control, and the curses library provides various portable routines for both functions.The comp.so.msdos.programmer Frequently Answered Questions posting says:Q301. How can I read a character without echoing it to the screen, and without waiting for the user to press the Enter key? The C compilers from Microsoft and Borland offer getch (or getche to echo the character); Turbo Pascal has ReadKey. In other programming languages, load 8 in register AH and execute INT 21; AL is returned with the character from standard input (possibly redirected). If you don't want to allow redirection, or you want to capture Ctrl-C and other special keys, use INT 16 with AH=10; this will return the scan code in AH and ASCII code (if possible) in AL, except that AL=E0 with AH nonzero indicates one of the grey "extended" keys was pressed. (If your BIOS doesn't support the extended keyboard, use INT 16 function 0 not 10.)Q302. How can I find out whether a character has been typed, without waiting for one? In Turbo Pascal, use KeyPressed. Both Microsoft C and Turbo C offer the kbhit( ) function. All of these tell you whether a key has been pressed. If no key has been pressed, they return that information to your program. If a keystroke is waiting, they tell your program that but leave the key in the input buffer. You can use the BIOS call, INT 16 function 01 or 11, to check whether an actual keystroke is waiting; or the DOS call, INT 21 function 0B, to check for a keystroke from stdin (subject to redirection). See Ralf Brown's interrupt list.And here's some more info:On a PC, Microsoft C provides a routine called getch(). I believeTurbo C provides a similar routine. See your runtime librarydocumentation for details. Here is an example:#include <conio.h>main() { int c; printf("control-c to exit\n"); for(;;) { c = getch(); printf("%02x\n", c); }}Under unix, you can use curses. Read the man page for curses fordetails. Here is an example:/*** on a Sun, compile this as** /usr/5bin/cc -o progname progname.c -lcurses*/#include <curses.h>main() { int c; initscr(); cbreak(); noecho(); for(;;) { c = getch(); wprintw(stdscr, "%02x\n", c); if (c == 3) break; } endwin(); exit(0);}Also under unix, you can use ioctl. Read the man pages for ioctl andtermio for details. Here is an example:#include <stdio.h>#include <sys/termio.h>#define ON 0#define OFF 1#define READ 2#define FALSE 0 == 1#define TRUE !FALSE#define ETX 0x03#define EOT 0x04main(){ int c; hitkey(ON); while((c = hitkey(READ)) > 0) { printf("%02x\n", c); if (c == ETX || c == EOT) break; } printf("\n"); hitkey(OFF); exit(0);}int hitkey(select)int select;{ static int last = OFF; static struct termio org; struct termio tmp; char c; int rv = TRUE; int fd = fileno(stdin); if (last == select) { return(rv); } switch(select) { case ON: ioctl(fd, TCGETA, &org); ioctl(fd, TCGETA, &tmp); tmp.c_lflag = 0; tmp.c_cc[VMIN] = 1; tmp.c_cc[VTIME] = 0; ioctl(fd, TCSETA, &tmp); last = ON; break; case OFF: ioctl(fd, TCSETA, &org); last = OFF; break; case READ: if ((rv = read(fd, &c, 1)) == 1); rv = c; break; default: fprintf(stderr, "Invalid call to hitkey()"); exit(1); } return(rv);}and here's some more code someone posted:Article 25002 of comp.lang.c:Path: mdisea!uw-coco!uw-beaver!cs.ubc.ca!destroyer!sol.ctr.columbia.edu!spool.mu.edu!olivea!uunet!munnari.oz.au!comp.vuw.ac.nz!waikato.ac.nz!aukuni.ac.nz!cs18.cs.aukuni.ac.nz!pgut1From: pgut1@cs.aukuni.ac.nz (Peter Gutmann)Newsgroups: comp.lang.cSubject: Re: getch() replacementMessage-ID: <1992Nov26.032122.8593@cs.aukuni.ac.nz>Date: 26 Nov 92 03:21:22 GMTReferences: <kT6suB1w165w@cibbs.UUCP>Organization: Computer Science Dept. University of AucklandLines: 111In <kT6suB1w165w@cibbs.UUCP> root@cibbs.UUCP writes:>I am working with Borland C++ 3.1 and I am looking for a replacement for>Borland's getch() function. I would like this replacement to grab the input>from STDIN without having to press return. So far, I have had no luck.>Many posts back someone posted that in UNIX this can be done with the IOCTL>setup. DOS of course has an entirely different set of functions for this>command (I have explored that anvenue).(I'm replying here rather than via email since I've seen requests for thisseveral times in the past).The following code will do what you want - note that you'll need a seperateversion of the code for pretty well every version of Unix you're going touse it under (isn't "standard" Unix wonderful?)./* Get an input character, no echo */ #if defined( POSIX ) || defined( SVR4 ) || defined( IRIX ) #include <termios.h> int getch( void ) { struct termios ttyInfo; FD ttyFD = ERROR; char ch; /* Flush all pending output */ fflush( stdout ); /* Turn echo off */ if( isatty( STDERR ) && ( ttyFD = hopen( ttyname( STDERR ), O_RDWR ) ) != ERROR ) { tcgetattr( ttyFD, &ttyInfo );#ifdef IRIX ttyInfo.c_lflag &= ~ECHO; ttyInfo.c_lflag &= ~ICANON;#else ttyInfo.c_lflags &= ~ECHO; ttyInfo.c_lflags |= CBREAK;#endif /* IRIX */ tcsetattr( ttyFD, TCSANOW, &ttyInfo ); } /* Get the character */ read( ttyFD, &ch, 1 ); /* Turn echo on again if it was off */ if( ttyFD != ERROR ) { tcgetattr( ttyFD, &ttyInfo );#ifdef IRIX ttyInfo.c_lflag |= ECHO; ttyInfo.c_lflag |= ICANON;#else ttyInfo.c_lflags |= ECHO; ttyInfo.c_lflags &= ~CBREAK;#endif /* IRIX */ tcsetattr( ttyFD, TCSANOW, &ttyInfo ); } return( ch ); } #else #include <sgtty.h> int getch( void ) { struct sgttyb ttyInfo; FD ttyFD = ERROR; char ch; /* Flush all pending output */ fflush( stdout ); /* Turn echo off */ if( isatty( STDERR ) && ( ttyFD = hopen( ttyname( STDERR ), O_RDWR ) ) != ERROR ) { gtty( ttyFD, &ttyInfo ); ttyInfo.sg_flags &= ~ECHO; ttyInfo.sg_flags |= CBREAK; stty( ttyFD, &ttyInfo ); } /* Get the character */ read( ttyFD, &ch, 1 ); /* Turn echo on again if it was off */ if( ttyFD != ERROR ) { gtty( ttyFD, &ttyInfo ); ttyInfo.sg_flags |= ECHO; ttyInfo.sg_flags &= ~CBREAK; stty( ttyFD, &ttyInfo ); } return( ch ); }#endif /* POSIX || SVR4 || IRIX */--pgut1@cs.aukuni.ac.nz || gutmann_p@kosmos.wcc.govt.nz || peterg@kcbbs.gen.nz || peter@nacjack.gen.nz (In order of preference)Warning! Something large, scaly, and with fangs a foot long lives between <yoursite>and <mysite>. Every now and then it kills and eats messages. If you don'treceive a reply within a week, try resending...Article 26728 of comp.lang.c:Newsgroups: comp.lang.cPath: mdisea!uw-coco!uw-beaver!micro-heart-of-gold.mit.edu!news.bbn.com!usc!zaphod.mps.ohio-state.edu!saimiri.primate.wisc.edu!ames!kum.kaist.ac.kr!usenetFrom: typhoon@stcon2.kaist.ac.kr (Han Yun-Su)Subject: Re: Unix equivalent to DOS kbhit() function?Message-ID: <1992Dec29.073337.2693@kum.kaist.ac.kr>Sender: usenet@kum.kaist.ac.kr (news)Organization: KAIST in Seoul, KoreaX-Newsreader: Tin 1.1 PL3Date: Tue, 29 Dec 92 07:33:37 GMTLines: 67I wrote 'kbhit()' function for UNIX.It's very simple..Here's example source.Save this article as 'kbhit.c', delete headers and signature..Compile with -lcurses -ltermcap options, that is,cc kbhit.c -o kbhit -lcurses -ltermcapand..type kbhit !test some characters..(This works totaly fine for my SUN)Er..sorry.. I'm not good at english..:)I can speak C more fluently than english..hehe :)But my major is NOT Computer Science but Life Science. If you find better idea than this one, Please let me know.Good Luck!/* ---- Cut Here ---- */#include <sgtty.h>#include <curses.h>kbhit(){ static unsigned i; ioctl(0, FIONREAD, &i); return i;}main(){ unsigned long count = 0L; int c = ' '; int i = 0; initscr(); /* initialize curses functions */ crmode(); /* cbreak mode */ noecho(); /* do not echo pressed character */ mvprintw(0, 0, "Press \'q\' to quit\n"); refresh(); while (c != 'q') { count++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -