-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinux_conio.cpp
155 lines (125 loc) · 3.69 KB
/
linux_conio.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include "linux_conio.h"
#ifndef _WIN32
struct termios old_attributes, new_attributes;
int old_block_mode;
bool conio_mode = false;
bool should_enable_conio = false;
void enable_noblock() {
old_block_mode = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, old_block_mode | O_NONBLOCK);
}
void disable_noblock() {
fcntl(STDIN_FILENO, F_SETFL, old_block_mode);
}
void exit_handler(int s) {
should_enable_conio = conio_mode;
disable_conio_mode();
disable_noblock();
if (s == SIGTSTP) {
struct sigaction sig_handler;
sig_handler.sa_handler = SIG_DFL; // reset signal handler to default for SIGTSTP
sigemptyset(&sig_handler.sa_mask);
sig_handler.sa_flags = 0;
sigaction(SIGTSTP, &sig_handler, NULL);
raise(SIGTSTP); // Suspend the process
}
else {
exit(1); // Kill the process
}
}
void cont_handler(int s) {
if (should_enable_conio) {
should_enable_conio = false;
enable_conio_mode();
}
struct sigaction sig_handler;
sig_handler.sa_handler = exit_handler;
sigemptyset(&sig_handler.sa_mask);
sig_handler.sa_flags = 0;
sigaction(SIGTSTP, &sig_handler, NULL);
}
// We need to intercept various kill/suspend signals so that we can reset the console settings if needed on Linux (Some are not possible to intercept, like SIGKILL or SIGSTOP, but this will do for now)
void setup_signal_interceptor() {
struct sigaction sig_handler;
sig_handler.sa_handler = exit_handler;
sigemptyset(&sig_handler.sa_mask);
sig_handler.sa_flags = 0;
sigaction(SIGINT, &sig_handler, NULL);
sigaction(SIGTERM, &sig_handler, NULL);
sigaction(SIGQUIT, &sig_handler, NULL);
sigaction(SIGTSTP, &sig_handler, NULL);
struct sigaction sig_cont_handler;
sig_cont_handler.sa_handler = cont_handler;
sigemptyset(&sig_cont_handler.sa_mask);
sig_cont_handler.sa_flags = 0;
sigaction(SIGCONT, &sig_cont_handler, NULL);
}
// allow kbhit and getch on linux
void enable_conio_mode() {
if (conio_mode) {
return;
}
conio_mode = true;
tcgetattr(STDIN_FILENO, &old_attributes);
new_attributes = old_attributes;
new_attributes.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_attributes);
}
// allow kbhit and getch on linux
void disable_conio_mode() {
if (!conio_mode) {
return;
}
conio_mode = false;
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes);
}
// linux implementation of _getch()
int _getch() {
bool mode = conio_mode;
if (!mode) {
enable_conio_mode();
}
char c = getchar();
if (!mode) {
disable_conio_mode();
}
return c;
}
// linux implementation of _kbhit(), requires conio mode to be enabled
bool _kbhit() {
if (!conio_mode) {
return false;
}
enable_noblock();
int c = getchar();
disable_noblock();
// if the char returned from non-blocking getchar is not EOF, a character exists in stdin.
if (c != EOF) {
// put the character we read back onto the stdin stream
ungetc(c, stdin);
return true;
}
return false;
}
// Linux implementation of a non-blocking version of getch
int getch_noblock() {
enable_noblock();
int c = _getch();
disable_noblock();
return c;
}
#else
// Windows versions of the functions (Windows has _getch() and _kbhit() by default)
void setup_signal_interceptor() {}
void disable_conio_mode() {}
void enable_conio_mode() {}
// Windows implementation of a non-blocking getch
int getch_noblock() {
if (_kbhit()) {
return _getch();
}
else {
return EOF;
}
}
#endif