text: #define Uses_TKeys
  #define Uses_TEvent
  #include <tvision/tv.h>
  
  #include <internal/codepage.h>
  #include <internal/strings.h>
  #include <internal/getenv.h>
  #include <internal/utf8.h>
  #include <array>
  
  /* The Turbo Vision library has all its characters encoded in code page 437.
   * While Unicode support is not added, it's better to just translate them
   * with a lookup table. The following table allows translating the characters
   * stored by Turbo Vision into the corresponding UTF-8 mulibyte characters.
   * Taken from https://en.wikipedia.org/wiki/Code_page_437 */
  
  static const TStringView cp437toUtf8[256] = {
      "\0", "☺", "☻", "♥", "♦", "♣", "♠", "•", "◘", "○", "◙", "♂", "♀", "♪", "♫", "☼",
      "►", "◄", "↕", "‼", "¶", "§", "▬", "↨", "↑", "↓", "→", "←", "∟", "↔", "▲", "▼",
      " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
      "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
      "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
      "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
      "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
      "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "⌂",
      "Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å",
      "É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "₧", "ƒ",
      "á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "⌐", "¬", "½", "¼", "¡", "«", "»",
      "░", "▒", "▓", "│", "┤", "╡", "╢", "╖", "╕", "╣", "║", "╗", "╝", "╜", "╛", "┐",
      "└", "┴", "┬", "├", "─", "┼", "╞", "╟", "╚", "╔", "╩", "╦", "╠", "═", "╬", "╧",
      "╨", "╤", "╥", "╙", "╘", "╒", "╓", "╫", "╪", "┘", "┌", "█", "▄", "▌", "▐", "▀",
      "α", "ß", "Γ", "π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "∞", "φ", "ε", "∩",
      "≡", "±", "≥", "≤", "⌠", "⌡", "÷", "≈", "°", "∙", "·", "√", "ⁿ", "²", "■", " "
  };
  
  static const std::array<uint32_t, 256> cp437toUtf8Int = make_utf8int<256>(cp437toUtf8);
  
  static const TStringView cp850toUtf8[256] = {
      "\0", "☺", "☻", "♥", "♦", "♣", "♠", "•", "◘", "○", "◙", "♂", "♀", "♪", "♫", "☼",
      "►", "◄", "↕", "‼", "¶", "§", "▬", "↨", "↑", "↓", "→", "←", "∟", "↔", "▲", "▼",
      " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/",
      "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?",
      "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
      "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_",
      "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
      "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "⌂",
      "Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å",
      "É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "ø", "£", "Ø", "×", "ƒ",
      "á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "®", "¬", "½", "¼", "¡", "«", "»",
      "░", "▒", "▓", "│", "┤", "Á", "Â", "À", "©", "╣", "║", "╗", "╝", "¢", "¥", "┐",
      "└", "┴", "┬", "├", "─", "┼", "ã", "Ã", "╚", "╔", "╩", "╦", "╠", "═", "╬", "¤",
      "ð", "Ð", "Ê", "Ë", "È", "ı", "Í", "Î", "Ï", "┘", "┌", "█", "▄", "¦", "Ì", "▀",
      "Ó", "ß", "Ô", "Ò", "õ", "Õ", "µ", "þ", "Þ", "Ú", "Û", "Ù", "ý", "Ý", "¯", "´",
      "-", "±", "‗", "¾", "¶", "§", "÷", "¸", "°", "¨", "·", "¹", "³", "²", "■", " "
      // Note that <last row, first column> should be soft hyphen ("\u00AD"), but
      // it is often represented as a regular hyphen.
  };
  
  static const std::array<uint32_t, 256> cp850toUtf8Int = make_utf8int<256>(cp850toUtf8);
  
  static std::unordered_map<uint32_t, char> initMap(const TStringView toUtf8[256])
  {
      using namespace detail;
      std::unordered_map<uint32_t, char> map;
      for (size_t i = 0; i < 256; ++i)
          map.emplace(string_as_int<uint32_t>(toUtf8[i]), char(i));
      return map;
  }
  
  CpTranslator::CpTable::CpTable( TStringView cp,
                                  const TStringView toUtf8[256],
                                  const std::array<uint32_t, 256> &toUtf8Int ) :
      cp(cp),
      toUtf8Int(toUtf8Int.data()),
      fromUtf8(initMap(toUtf8))
  {
  }
  
  const CpTranslator::CpTable CpTranslator::tables[] = {
      { "437", cp437toUtf8, cp437toUtf8Int },
      { "850", cp850toUtf8, cp850toUtf8Int }
  };
  
  const CpTranslator::CpTable *CpTranslator::activeTable;
  CpTranslator CpTranslator::instance;
  
  CpTranslator::CpTranslator() {
      // Set the active codepage. 437 is the default.
      use(getEnv<TStringView>("TVISION_CODEPAGE", "437"));
  }
  
  char CpTranslator::fromUtf8(TStringView s)
  {
      using namespace detail;
      auto it = activeTable->fromUtf8.find(string_as_int<uint32_t>(s));
      if (it != activeTable->fromUtf8.end())
          return it->second;
      return 0;
  }
  