Snippet POSIX STDIN mode
From C
PoppaVic provided these two functions and a test, for switching between tty input modes, along with the following statement "Be advised: 'very' raw tends to require you run 'reset' on your terminal". (Note: MacOSX did not have this issue, and there is a new #ifndef that helps even there)
pfv_stdin_raw.h:
/* pfv_stdin_raw.h
* Set stdin to raw, (two types), or back to cooked.
* (c) 2002 PoppaVic #c @freenode.net
*
* This snippet is PD - don't blame me if it melts your system.
*/
#ifndef PFV_STDIN_RAW_H_
#define PFV_STDIN_RAW_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int pfv_stdin_raw(int very); /* zero or non-zero */
extern int pfv_stdin_cooked(void);
#ifdef __cplusplus
}
#endif
#endif /* PFV_STDIN_RAW_H_ */
pfv_stdin_raw.c:
/* pfv_stdin_raw.c
* Set stdin to raw, (two types), or back to cooked.
* (c) 2002 PoppaVic #c @freenode.net
*
* This snippet is PD - don't blame me if it melts your system.
*
* Compiling a test:
* gcc -DTEST_STDIN_RAW -o test pfv_stdin_raw.c
* ./test
*/
#include <stdio.h> /* perror() */
#include <errno.h> /* errno */
#include <unistd.h> /* these two: tcgetattr & friends */
#include <termios.h>
#include "pfv_stdin_raw.h"
static char loaded=0;
static struct termios t;
int pfv_stdin_raw(int very)
{ struct termios now;
if(!loaded)
{
if( tcgetattr(STDIN_FILENO, &t)<0 )
{
perror("tcgetattr");
return -1;
}
else
loaded=1;
}
memcpy(&now, &t, sizeof(struct termios) );
if(very)
{
/* The below is supposed to be equiv. to cfmakeraw( &now ); */
now.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
/* NOTE:
* Following is equiv, but commenting it OUT tests-out
* a whole lot more neatly!
*/
#ifndef TEST_STDIN_RAW
now.c_oflag &= ~OPOST;
#endif
now.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
now.c_cflag &= ~(CSIZE|PARENB);
now.c_cflag |= CS8;
if( tcsetattr(STDIN_FILENO, TCSANOW, &now)<0 )
{
perror("tcsetattr");
return -1;
}
}
else
{
now.c_lflag &= ~ICANON;
if( tcsetattr(STDIN_FILENO, TCSANOW, &now)<0 )
{
perror("tcsetattr");
return -1;
}
/*setbuf(stdin, NULL);*/
}
return 0;
}
int pfv_stdin_cooked(void)
{
if(!loaded)
{
errno=EPERM;
perror("already cooked");
return -1;
}
if( tcsetattr(STDIN_FILENO, TCSANOW, &t)<0 )
{
perror("tcsetattr");
return -1;
}
return 0;
}
#ifdef TEST_STDIN_RAW
#include <sys/poll.h> /* poll() */
#include <string.h> /* strerror() */
int main(int argc, char **argv)
{ char foo;
int cc;
struct pollfd incoming[1];
int ret, ret2;
incoming[0].fd= fileno(stdin);
incoming[0].events= POLLIN;
printf("Testing pfv_stdin_raw(%d): start typing!\n", argc>1);
pfv_stdin_raw(argc>1);
cc=0;
do
{
foo=EOF;
/* Human/console timespans: 2 seconds */
ret = poll(incoming, 1, 2000);
switch( ret )
{
case -1: /* Got an error/eof... */
fprintf(stderr, "%d=poll re=%04x(%d: %s)\n",
ret, incoming[0].revents, errno,
strerror(errno));
break;
case 1: /* Got readable activity... */
if (read(fileno(stdin), &foo, 1) == 1)
{
/* Kernel/Kbd timespans: 2 millisec */
ret2= poll(incoming, 1, 2);
fprintf(stderr, "\t(x%02x;'%c')",
foo, (foo < 32 ? '.' : foo) );
fprintf(stderr, "%s",
ret2==1 ? "" : "\n" );
cc++;
}
break;
default: /* Zero is 'timeout' */
break;
}
} while(foo!=EOF && foo!=0x04);
pfv_stdin_cooked();
}
#endif
