Silvio Mayolo
Silvio Mayolo

Reputation: 70277

Detecting whether I can capture arrow keys via stdin

I am trying to create a basic REPL. If my program is run in a terminal that can support it, I use the termios getchar to read input character-by-character and respond to special keys, such as the arrow keys. However, if run in a terminal for which that does not make sense, I'd like to switch to good old-fashioned cin.getline.

The trouble is in detecting whether the terminal has the capabilities I'm looking for. Initially, I was thinking isatty would do the trick.

#include <cstdio>
#include <iostream>
#include <unistd.h>

int main() {
  bool tty = isatty(fileno(stdin));
  std::cout << "You are using a TTY: " << std::boolalpha << tty << std::endl;
  return 0;
}

This will correctly identify cases where stdin is a pipe or something like that. However, if I'm running a subshell inside Emacs (M-x shell, specifically), it still identifies as a TTY, even though Emacs captures arrow keys and other special characters and does its own thing with them. What C++ or POSIX functionality can I use that would correctly distinguish between a subshell being run within Emacs and a shell being run with full control inside an "ordinary" terminal?

I'm primarily looking for POSIX solutions here, but Windows-only answers are useful for posterity as well.


Footnote: Yes, I am aware of things like ncurses that handle all of this for me. I would like to do this without using such libraries, to improve my understanding of the terminal environment.

Upvotes: 2

Views: 138

Answers (1)

Davis Herring
Davis Herring

Reputation: 39838

This is the purpose of the TERM environment variable. You use (low-level) libraries like terminfo to understand (the implications of) the value of TERM, although recognizing Emacs’ value of “dumb” is easy enough.

Upvotes: 1

Related Questions