maniac@arrakis.nevada.edu (ERIC SCHWERTFEGER) (12/02/89)
[] I have one quick question, and I need a very urgent answer, (Dec 4 is too late). I've got a program that runs from the CLI, and I need to detect when a key is struck, and what key was struck. The problem I'm having is that any key I hit is echoed to the window, which blocks window output, until I press return. I want a way around this, using standard C functions, that will work with Lattice 4.0, because this program is going to be ported over to a Unix environment to be turned in for a class project. BTW, the method I'm using now is getchar(). Eric J. Schwertfeger, UNLV maniac@arrakis.nevada.edu
duncant@mbunix.mitre.org (Thomson) (12/04/89)
In article <1083@unsvax.NEVADA.EDU> maniac@arrakis.nevada.edu.uucp (ERIC SCHWERTFEGER) writes: >)... I've got a program that runs from the CLI, and >I need to detect when a key is struck, and what key was struck. > The problem I'm having is that any key I hit is echoed to the >window, which blocks window output, until I press return. > I want a way around this, using standard C functions, that will >work with Lattice 4.0, because this program is going to be ported over >to a Unix environment to be turned in for a class project. > BTW, the method I'm using now is getchar(). I think the problem you are having is actually more accurately described as: input from the keyboard (stdin in this case) is done using line buffering. In this mode, an I/O operation is not completed until a return is pressed (allowing editing of the input line with the backspace key). Therefore your program is sitting there at the getchar() call, waiting for the I/O to complete. The solution SHOULD be to change the buffering mode from line buffering to no buffering, using the standard library function setvbuf(). Unfortunately, this doesn't work. It doesn`t work with a lot of compilers on a lot of systems actually. I'd be interested in hearing from someone close to the C language ANSI comittee if there is a reason for this. Am I interpreting the standard`s description of setvbuf incorrectly? The second problem you may have is you want to get rid of character echo. I'm not sure there is a way to do this in the ANSI C library. Anyone else know of a way? If you're not concerned about portability, you can solve all yourproblems by sending a message to the console handler which puts it into RAW mode. I have some code somewhere which does this. Let me know if you still need it. By the way, i think you can also do something like: FILE *keybd; keybd = fopen( "RAW:", "r" ); c = fgetc( keybd ); ... I tried this once, and it worked - what you're doing is using the console handler in it's raw mode. I'm not quite sure now whether "RAW" is exactly the right name though. (I'm now writing this message in my office using a PC (yuck) and I don't have any amiga manuals or code handy, which is why I'm a but fuzzy on the details) Duncan Thomson
andrewt@watsnew.waterloo.edu (Andrew Thomas) (12/07/89)
I don't know how to do it on the amiga, but here is a method which works on BSD, SunOS, Ultrix. I tried to reply by mail but it bounced. This code is guaranteed not at all. No claim is made to it either. Do what you will. ------------------- cbreak.c ----------------------- /* cbreak.c written by Andrew Thomas andrewt@watsnew.waterloo.edu If you have ideas on how to make this more portable, I am keen to hear them. I make no guarantees, no claims, no copyrights. */ #include <sgtty.h> #include <signal.h> #include <stdio.h> #include <sys/file.h> #include <sys/ioctl.h> /* WARNING: If this file is compiled with gcc (or any ansi compiler) you must privide the -traditional option, or modify the header files to adhere to ansi standard. */ /* The call you really want to use from here is the call to get_a_key(noecho,interrupt_status). If noecho is non-zero, then the keys will not be echoed as they are typed. Interrupt_status is explained in more detail later on. */ static int cbreak_on = 0; static int tty = 0; static int tty_set = 0; static int cbreak_int_status = 0; static struct sgttyb tty_desc; void cbreak(); void nocbreak(); void cbreak_ignoresignal () { } void cbreak_killsignal () { nocbreak (); exit (1); } void cbreak_stopsignal () { nocbreak (); kill (getpid(), SIGSTOP); if (cbreak_on) cbreak(cbreak_on-1); } /* interrupt_status tells the system what to do with SIGTSTP, SIGTERM and SIGINT interrupt status is one of 0, 1, or 2: 0: do nothing to alter the interrupts, or if interrupt status was changed before, make interrupts perform the default action. 1: make interrupts cause a clean exit, resetting the interrupt status on exit and reentry 2: ignore interrupts. */ void cbreak_open_tty (interrupt_status) int interrupt_status; { tty_set = 1; tty = fileno (stdin); if (ioctl (tty, TIOCGETP, &tty_desc) == -1) perror ("ioctl: TIOCGETP"); if (interrupt_status == 0 && cbreak_int_status != 0) { signal (SIGTSTP, SIG_DFL); signal (SIGTERM, SIG_DFL); signal (SIGINT, SIG_DFL); } else if (interrupt_status == 1) { signal (SIGTSTP, cbreak_stopsignal); signal (SIGTERM, cbreak_killsignal); signal (SIGINT, cbreak_killsignal); } else if (interrupt_status == 2) { signal (SIGTSTP, cbreak_ignoresignal); signal (SIGTERM, cbreak_ignoresignal); signal (SIGINT, cbreak_ignoresignal); } cbreak_int_status = interrupt_status; } /* noecho, if non-zero, causes the key stroke not to be echoed */ void cbreak (noecho, interrupt_status) int noecho, interrupt_status; { if (!tty_set || interrupt_status != cbreak_int_status) cbreak_open_tty (interrupt_status); tty_desc.sg_flags |= CBREAK; if (noecho) tty_desc.sg_flags &= ~ECHO; if (ioctl (tty, TIOCSETN, &tty_desc) == -1) perror ("cbreak: ioctl: TIOCSETN"); } void nocbreak () { if (!tty_set) cbreak_open_tty (cbreak_int_status); tty_desc.sg_flags &= ~CBREAK; tty_desc.sg_flags |= ECHO; if (ioctl (tty, TIOCSETN, &tty_desc) == -1) perror ("nocbreak: ioctl: TIOCSETN"); } /* get a keystroke in cbreak mode, echoed or not echoed, with actions on interrupts specified. Clear the stdin buffer first. This is a bit of a kluge. Suggestions welcome. */ char get_a_key (noecho, interrupt_status) int noecho, interrupt_status; { char x; while (stdin->_cnt > 0) if ((x=getchar()) != '\n') return (x); cbreak (noecho, interrupt_status); cbreak_on = 1+(noecho?1:0); x = getchar(); nocbreak (); cbreak_on = 0; return (x); } -------------------------------------------------- Hope this helps. -- Andrew Thomas andrewt@watsnew.waterloo.edu Systems Design Eng. University of Waterloo "If a million people do a stupid thing, it's still a stupid thing." - Opus