Open matthewfleming opened 7 years ago
Thanks, I was aware of this issue but didn't know how to fix it.
Setting O_NONBLOCK
does get it to stop blocking, but for me read()
still doesn't wait 0.1 seconds before timing out, it just returns 0
immediately. In the final version of the editor, this causes the arrow keys to not work, I guess because it's reading input faster than the terminal can send the arrow key escape sequence.
Unsetting FNDELAY
using fcntl()
as suggested here seems to make the arrow keys work, even though read()
still seems to return pretty much immediately instead of waiting 0.1 seconds.
I'm going to have to look into this more to find the proper solution. Or maybe someone who knows this stuff better will come along and help out...
You're right! I didn't notice that it stopped blocking entirely!
It seems that FNDELAY and O_NONBLOCK are basically the same thing just different standards: https://mail.python.org/pipermail/python-list/1999-May/013687.html
It's possible that VTIME just doesn't work in this environment? In any case I went with this so I can continue the tutorial:
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
struct termios orig_termios;
void disableRawMode() {
tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
}
void enableRawMode() {
tcgetattr(STDIN_FILENO, &orig_termios);
atexit(disableRawMode);
+ fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);
struct termios raw = orig_termios;
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
raw.c_oflag &= ~(OPOST);
raw.c_cflag |= (CS8);
raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
raw.c_cc[VMIN] = 0;
- raw.c_cc[VTIME] = 1;
+ raw.c_cc[VTIME] = 0;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
int main() {
enableRawMode();
while (1) {
char c = '\0';
read(STDIN_FILENO, &c, 1);
+ if(errno==EAGAIN) {
+ struct timespec ts = {0,100000000};
+ nanosleep(&ts, NULL);
+ }
if (isprint(c)) {
printf("%d ('%c')\r\n", c, c);
} else {
printf("%d\r\n", c);
}
if (c == 'q') {
break;
}
}
return 0;
}
Okay so I've continued along (I'm not bothering to sleep anymore - but this creates another problem at step 32 - we don't get the answer on STD_OUT immediately so we have to check for EAGAIN and continue without incrementing.
This doesn't create an infinite loop in practice because the answer (ending with R) does come eventually.
I'm not sure why the answer isn't immediately available - perhaps STDOUT isn't blocking now either? Maybe this explains some other problems that happen in O_NONBLOCK mode?
int getCursorPosition(int *rows, int *cols) {
char buf[32];
unsigned int i = 0;
if (write(STDOUT_FILENO, "\x1b[6n", 4) != 4) return -1;
char c;
while (i < sizeof(buf) - 1) {
- if (read(STDIN_FILENO, &buf[i], 1) != 1) break;
+ if (read(STDIN_FILENO, &buf[i], 1) != 1) {
+ if (errno == EAGAIN) continue;
+ break;
+ }
if (buf[i] == 'R') break;
i++;
}
buf[i] = '\0';
printf("\r\n&buf[1]: '%s'\r\n", &buf[1]);
editorReadKey();
return -1;
}
Hi!
Thanks for the tutorial! It's been handy refresher for my c skills.
Raw mode still blocks for me (Windows 10 / Bash on Ubuntu on Windows) because STDIN is set to block.
I was going to submit a pull request but then the steps.diff isn't really human editable. It's a 1 liner anyway!