I’m building an interactive file explorer/manager and thus I’m putting the terminal in “raw” mode. I also set VMIN
to 0
effectively changing the minimum number of required bytes to zero before C’s read
function can return. In addition to that, I also set VTIME
to 1
. It ensures that read
will wait at least 1/10 of second (100ms) before returning. While VMIN
seems to work fine, VTIME
does not seem to have any effect.
Here’s the code:
lib LibC
VTIME = 17
end
def raw_mode!
LibC.tcgetattr(STDIN.fd, out orig_termios)
at_exit do
LibC.tcsetattr(STDIN.fd, LibC::TCSAFLUSH, pointerof(orig_termios))
end
raw = orig_termios
raw.c_iflag &= ~(LibC::BRKINT | LibC::ICRNL | LibC::INPCK | LibC::ISTRIP | LibC::IXON)
raw.c_oflag &= ~(LibC::OPOST)
raw.c_cflag |= (LibC::CS8)
raw.c_lflag &= ~(LibC::ECHO | LibC::ICANON | LibC::IEXTEN | LibC::ISIG)
raw.c_cc[LibC::VMIN] = 0
raw.c_cc[LibC::VTIME] = 1
LibC.tcsetattr(STDIN.fd, LibC::TCSAFLUSH, pointerof(raw))
yield
end
raw_mode! do
loop do
b = STDIN.read_byte
if b.nil?
puts "read timeout\r\n"
next
end
ch = b.chr
if ch.ascii_control?
puts "#{b}\r\n"
else
puts "#{b} (#{ch})\r\n"
end
exit if ch == 'q'
end
end
For comparsion purposes, here’s the equivalent C code that does respect VTIME
:
#include <ctype.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);
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);
printf("VMIN is %d\n", VMIN);
printf("VTIME is %d\n", VTIME);
raw.c_cc[VMIN] = 0;
raw.c_cc[VTIME] = 1;
tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
}
int main() {
enableRawMode();
while (1) {
char c = '\0';
read(STDIN_FILENO, &c, 1);
if (iscntrl(c)) {
printf("%d\r\n", c);
} else {
printf("%d ('%c')\r\n", c, c);
}
if (c == 'q') break;
}
return 0;
}
and here’s a man page referencing both VMIN
and VTIME
.