Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

CSC112 Spring 2016 Examples

2370 views
1
#include <iostream>
2
#include <unistd.h>
3
#include <termios.h>
4
#include <sys/ioctl.h>
5
#include <stdlib.h>
6
#include <sys/poll.h>
7
#include <exception>
8
#include "keystream.h"
9
10
//our lone default instance
11
KeyStream kin;
12
13
14
//this is a low level character buffer, it uses read
15
class ttyinbuf : public std::streambuf
16
{
17
public:
18
ttyinbuf()
19
{
20
if(!isatty(STDIN_FILENO)) {
21
throw std::runtime_error{"STDIN is not a tty!"};
22
}
23
24
//we initially start with no available input
25
setg(buf, buf+9, buf+9);
26
}
27
28
29
protected:
30
virtual int underflow()
31
{
32
//attempt to read a single character
33
if(read(STDIN_FILENO, buf+9, 1) <= 0)
34
return -1;
35
36
//make the character available
37
setg(buf, buf+9, buf + 10);
38
39
return buf[9];
40
}
41
42
43
private:
44
char buf[10];
45
};
46
47
48
//constructor & Destructor
49
KeyStream::KeyStream()
50
{
51
//set up our buffer to be stdin
52
this->rdbuf(new ttyinbuf);
53
54
//get the original termios
55
if(tcgetattr(STDIN_FILENO, &_originalTermios)==-1) {
56
throw std::runtime_error{"Termios tcgeattr failed."};
57
}
58
59
//the default state is cooked!
60
cookedMode();
61
}
62
63
64
KeyStream::~KeyStream()
65
{
66
//restore the original tty state
67
tcsetattr(STDIN_FILENO, TCSAFLUSH, &_originalTermios);
68
}
69
70
71
//macro modes
72
void
73
KeyStream::cookedMode()
74
{
75
_echo=true;
76
_special=true;
77
_signal=true;
78
_canonical=true;
79
setTermiosFlags();
80
}
81
82
83
void
84
KeyStream::rawMode()
85
{
86
_echo=false;
87
_special=false;
88
_signal=false;
89
_canonical=false;
90
setTermiosFlags();
91
}
92
93
94
void
95
KeyStream::cbreakMode()
96
{
97
_echo=false;
98
_canonical=false;
99
_signal=true;
100
_special=true;
101
setTermiosFlags();
102
}
103
104
105
//specific status flags
106
bool
107
KeyStream::echo()
108
{
109
return _echo;
110
}
111
112
113
void
114
KeyStream::echo(bool flag)
115
{
116
_echo = flag;
117
setTermiosFlags();
118
}
119
120
121
bool
122
KeyStream::canonical()
123
{
124
return _canonical;
125
}
126
127
128
void
129
KeyStream::canonical(bool flag)
130
{
131
_canonical = flag;
132
setTermiosFlags();
133
}
134
135
136
bool
137
KeyStream::signal()
138
{
139
return _signal;
140
}
141
142
143
void
144
KeyStream::signal(bool flag)
145
{
146
_signal = flag;
147
setTermiosFlags();
148
}
149
150
151
bool
152
KeyStream::special()
153
{
154
return _special;
155
}
156
157
158
void
159
KeyStream::special(bool flag)
160
{
161
_special = flag;
162
setTermiosFlags();
163
}
164
165
//extensions to the normal IO stuff
166
keycode
167
KeyStream::getKey()
168
{
169
keycode result=0x00;
170
char c;
171
172
//we may be getting more than one character!
173
c=get(); //get a character
174
result = c;
175
176
//if this is not an escape sequence, go ahead and return it
177
if(c != 0x1b || !hasInput()) {
178
return result;
179
}
180
181
//ok, so we have an escape sequence going!, get the second character
182
c = get(); //get the next character in the sequence
183
result = result << 8 | c; //add it to the result code
184
185
//If this is not one of our known sequences, then we
186
//stop here. (We also stop if there is nothing else to do)
187
if(!hasInput() || (c != 0x5b && c != 0x4f)) {
188
return result;
189
}
190
191
//still here? Let there be a third!
192
c = get();
193
result = result << 8 | c;
194
195
//now, there is only one known situation in which we have a fourth.
196
//look for it!
197
if(!hasInput() | !(c & 0x30)) {
198
return result;
199
}
200
201
//ok, 4, but that's it. NO MORE
202
c = get();
203
result = result << 8 | c;
204
205
return result;
206
}
207
208
209
bool
210
KeyStream::hasInput()
211
{
212
struct pollfd fds;
213
int pres;
214
215
fds.fd=STDIN_FILENO;
216
fds.events=POLLIN;
217
pres = poll(&fds, 1, 70);
218
219
return pres==1;
220
}
221
222
223
void
224
KeyStream::setTermiosFlags()
225
{
226
//start with the default mode for this tty
227
struct termios t=_originalTermios;
228
229
//tweakify!
230
231
//echo handling
232
if(_echo) {
233
//set the ECHO flag
234
t.c_lflag |= ECHO;
235
} else {
236
//clear the ECHO flag
237
t.c_lflag &= ~ECHO;
238
}
239
240
//canonical handling
241
if(_canonical) {
242
t.c_lflag |= ICANON;
243
//t.c_iflag |= ICRNL;
244
} else {
245
t.c_lflag &= ~ICANON;
246
//t.c_iflag &= ~ICRNL;
247
}
248
249
//singal handling
250
if(!_signal) {
251
t.c_lflag &= ~(ISIG | IEXTEN);
252
}
253
254
255
//special processing handling
256
if(!_special) {
257
t.c_iflag &= ~(BRKINT | INPCK | IGNBRK | ISTRIP | IGNCR | IXON | INLCR | PARMRK);
258
//t.c_oflag &= ~OPOST;
259
}
260
261
t.c_cc[VMIN] = 1;
262
t.c_cc[VTIME] = 0;
263
264
//set the ttye info
265
if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t) == -1)
266
throw std::runtime_error{"Termios tcsetattr failed."};
267
}
268
269