oof icon indicating copy to clipboard operation
oof copied to clipboard

Query sequences

Open s9w opened this issue 2 years ago • 0 comments

There is a special VT sequence that "will emit their responses into the console input stream immediately after being recognized on the output stream". In particular this is about ESC [ 6 n - the "report cursor position" sequence. To utilize this, it's required to read input from the console, without the user pressing enter. Unfortunately, that is not part of the C++ standard.

Therefore I'd like to explore if it's possible to write this code for the three (?) major platforms. I've written the code below, which works for windows. If other devs could join in to make something happen for Linux/Mac, that would be awesome.

Some relevant SO threads:

  • https://stackoverflow.com/questions/421860/capture-characters-from-standard-input-without-waiting-for-enter-to-be-pressed
  • https://stackoverflow.com/questions/9547868/is-there-a-way-to-get-user-input-without-pressing-the-enter-key
#ifdef _WIN32
#include <conio.h>
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#endif

#include <tuple>
#include <iostream>
#include <string>

#ifdef _WIN32
inline auto enable_windows_vt_mode() -> void{
   HANDLE const handle = GetStdHandle(STD_OUTPUT_HANDLE);
   DWORD dwMode = 0;
   GetConsoleMode(handle, &dwMode);
   dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
   SetConsoleMode(handle, dwMode);
}
#endif

auto immediately_read_one_char() -> char {
#ifdef _WIN32
   return static_cast<char>(_getch());
#endif
}

auto get_pos() -> std::tuple<int, int> {
   const std::string cursor_position_sequence = "\x1b[6n";
   std::cout << cursor_position_sequence;
   // This will "emit their responses into the console input stream immediately
   // after being recognized on the output stream".
   // So that input will need to be read without a return press.
   // Example response: "\x1b[11;22R"

   std::string input{};
   do{
      input.resize(input.size() + 1);
      input.back() = immediately_read_one_char();
   } while (input.back() != 'R');
   const size_t sep_pos = input.find_first_of(';');
   constexpr size_t row_substr_start = 2; // After the ESC and [
   const std::string row_str = input.substr(row_substr_start, sep_pos - row_substr_start);
   const std::string column_str = input.substr(sep_pos+1, input.size() - sep_pos - 2);

   return {
      std::stoi(row_str) - 1,
      std::stoi(column_str) - 1
   };
}

int main() {
#ifdef _WIN32
   enable_windows_vt_mode();
#endif
   
   std::cout << "test123\ntest";
   const auto pos = get_pos();

   return 0;
}

s9w avatar Nov 23 '21 11:11 s9w