CSC112 Spring 2016 Examples
#include <iostream>1#include <unistd.h>2#include <termios.h>3#include <sys/ioctl.h>4#include <stdlib.h>5#include <sys/poll.h>6#include "keystream.h"78//our lone default instance9KeyStream kin;101112//this is a low level character buffer, it uses read13class ttyinbuf : public std::streambuf14{15public:16ttyinbuf()17{18//we initially start with no available input19setg(&buf, &buf, &buf);20}212223protected:24virtual int underflow()25{26//read a single character27read(STDIN_FILENO, &buf, 1);2829//make the character available30setg(&buf, &buf, &buf + 1);31}323334private:35char buf;36};373839//constructor & Destructor40KeyStream::KeyStream()41{42//set up our buffer to be stdin43this->rdbuf(new ttyinbuf);4445//get the original termios46tcgetattr(STDIN_FILENO, &_originalTermios);4748//the default state is cooked!49cookedMode();50}515253KeyStream::~KeyStream()54{55//restore the original tty state56tcsetattr(STDIN_FILENO, TCSAFLUSH, &_originalTermios);57}585960//macro modes61void62KeyStream::cookedMode()63{64_echo=true;65_special=true;66_signal=true;67_canonical=true;68setTermiosFlags();69}707172void73KeyStream::rawMode()74{75_echo=false;76_special=false;77_signal=false;78_canonical=false;79setTermiosFlags();80}818283void84KeyStream::cbreakMode()85{86_echo=false;87_canonical=false;88_signal=true;89_special=true;90setTermiosFlags();91}929394//specific status flags95bool96KeyStream::echo()97{98return _echo;99}100101102void103KeyStream::echo(bool flag)104{105_echo = flag;106setTermiosFlags();107}108109110bool111KeyStream::canonical()112{113return _canonical;114}115116117void118KeyStream::canonical(bool flag)119{120_canonical = flag;121setTermiosFlags();122}123124125bool126KeyStream::signal()127{128return _signal;129}130131132void133KeyStream::signal(bool flag)134{135_signal = flag;136setTermiosFlags();137}138139140bool141KeyStream::special()142{143return _special;144}145146147void148KeyStream::special(bool flag)149{150_special = flag;151setTermiosFlags();152}153154//extensions to the normal IO stuff155keycode156KeyStream::getKey()157{158keycode result=0x00;159char c;160161//we may be getting more than one character!162c=get(); //get a character163result = c;164165//if this is not an escape sequence, go ahead and return it166if(c != 0x1b || !hasInput()) {167return result;168}169170//ok, so we have an escape sequence going!, get the second character171c = get(); //get the next character in the sequence172result = result << 8 | c; //add it to the result code173174//If this is not one of our known sequences, then we175//stop here. (We also stop if there is nothing else to do)176if(!hasInput() || (c != 0x5b && c != 0x4f)) {177return result;178}179180//still here? Let there be a third!181c = get();182result = result << 8 | c;183184//now, there is only one known situation in which we have a fourth.185//look for it!186if(!hasInput() | !(c & 0x30)) {187return result;188}189190//ok, 4, but that's it. NO MORE191c = get();192result = result << 8 | c;193194return result;195}196197198bool199KeyStream::hasInput()200{201struct pollfd fds;202int pres;203204fds.fd=STDIN_FILENO;205fds.events=POLLIN;206pres = poll(&fds, 1, 70);207208return pres==1;209}210211212void213KeyStream::setTermiosFlags()214{215struct termios t;216217//get the current termios218if(tcgetattr(STDIN_FILENO, &t) == -1) {219return; //TODO Exception Handling220}221222223//echo handling224if(_echo) {225//set the ECHO flag226t.c_lflag |= ECHO;227} else {228//clear the ECHO flag229t.c_lflag &= ~ECHO;230}231232//canonical handling233if(_canonical) {234t.c_lflag |= ICANON;235t.c_iflag |= ICRNL;236} else {237t.c_lflag &= ~ICANON;238t.c_iflag &= ~ICRNL;239}240241//singal handling242if(_signal) {243t.c_lflag |= ISIG | IEXTEN;244} else {245t.c_lflag &= ~(ISIG | IEXTEN);246}247248249//special processing handling250if(_special) {251t.c_iflag |= BRKINT | INPCK | IGNBRK | ISTRIP | IGNCR | IXON | INLCR | PARMRK;252//t.c_oflag |= OPOST;253} else {254t.c_iflag &= ~(BRKINT | INPCK | IGNBRK | ISTRIP | IGNCR | IXON | INLCR | PARMRK);255//t.c_oflag &= ~OPOST;256}257258t.c_cc[VMIN] = 1;259t.c_cc[VTIME] = 0;260261//set the ttye info262if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) == -1)263return; //TODO exception handling264}265266267