bool
 StreamReaderUnix::ReadInput(size_t& nRead, InputData& in) {
   int c = ReadRawCharacter();
   in.SetModifier(InputData::kModNone);
   if (c == -1) {
     in.SetExtended(InputData::kEIEOF);
   } else if (c == 0x1b) {
     // Only try to process CSI if Esc does not have a meaning
     // by itself.
     if (GetContext()->GetKeyBinding()->IsEscCommandEnabled()
         || !ProcessCSI(in)) {
       in.SetExtended(InputData::kEIEsc);
     }
   } else if (isprint(c)) {
     in.SetRaw(c);
   } else if (c < 32 || c == (char)127 /* ^?, DEL on MacOS */) {
     if (c == 13) {
       in.SetExtended(InputData::kEIEnter);
     } else {
       in.SetRaw(c);
       in.SetModifier(InputData::kModCtrl);
     }
   } else {
     // woohoo, what's that?!
     in.SetRaw(c);
   }
   ++nRead;
   return true;
 }
  bool
  StreamReaderUnix::ProcessCSI(InputData& in) {
    static ExtKeyMap gExtKeyMap;
    if (gExtKeyMap.empty()) {
      // Gnome xterm
      gExtKeyMap['[']['A'] = InputData::kEIUp;
      gExtKeyMap['[']['B'] = InputData::kEIDown;
      gExtKeyMap['[']['C'] = InputData::kEIRight;
      gExtKeyMap['[']['D'] = InputData::kEILeft;
      gExtKeyMap['[']['F'] = InputData::kEIEnd; // Savannah 83478
      gExtKeyMap['[']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['[']['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['1']['~'] = InputData::kEIHome;
      gExtKeyMap['[']['2']['~'] = InputData::kEIIns;
      gExtKeyMap['[']['3']['~'] = InputData::kEIDel;
      gExtKeyMap['[']['4']['~'] = InputData::kEIEnd;
      gExtKeyMap['[']['5']['~'] = InputData::kEIPgUp;
      gExtKeyMap['[']['6']['~'] = InputData::kEIPgDown;
      gExtKeyMap['[']['1'][';']['5']['A'].Set(InputData::kEIUp,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['B'].Set(InputData::kEIDown,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['C'].Set(InputData::kEIRight,
                                         InputData::kModCtrl);
      gExtKeyMap['[']['1'][';']['5']['D'].Set(InputData::kEILeft,
                                         InputData::kModCtrl);

      // MacOS
      gExtKeyMap['O']['A'] = InputData::kEIUp;
      gExtKeyMap['O']['B'] = InputData::kEIDown;
      gExtKeyMap['O']['C'] = InputData::kEIRight;
      gExtKeyMap['O']['D'] = InputData::kEILeft;
      gExtKeyMap['O']['F'] = InputData::kEIEnd;
      gExtKeyMap['O']['H'] = InputData::kEIHome;
      gExtKeyMap['[']['5']['C'].Set(InputData::kEIRight, InputData::kModCtrl);
      gExtKeyMap['[']['5']['D'].Set(InputData::kEILeft, InputData::kModCtrl);
    }

    InputData::EExtendedInput ret = InputData::kEIUninitialized;
    char mod = 0;
    Rewind rwd(fReadAheadBuffer, ret);
    ExtKeyMap* EKM = &gExtKeyMap;
    while (EKM) {
      if (EKM->haveExtInp()) {
        ret = EKM->getExtInp();
        mod = EKM->getMod();
        EKM = 0;
      } else {
        char c1 = ReadRawCharacter();
        rwd.push(c1);
        EKM = EKM->find(c1);
      }
    }
    in.SetExtended(ret);
    in.SetModifier(mod);
    return ret != InputData::kEIUninitialized;
  }
bool
StreamReaderWin::ReadInput(size_t& nRead, InputData& in) {
    DWORD NRead = 0;
    in.SetModifier(InputData::kModNone);
    char C;
    if (fIsConsole) {
        INPUT_RECORD buf;
        if (!::ReadConsoleInput(fIn, &buf, 1, &NRead)) {
            HandleError("reading console input");
            return false;
        }

        switch (buf.EventType) {
        case KEY_EVENT:
        {
            if (!buf.Event.KeyEvent.bKeyDown) return false;

            WORD Key = buf.Event.KeyEvent.wVirtualKeyCode;
            if (buf.Event.KeyEvent.dwControlKeyState
                    & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
                if (buf.Event.KeyEvent.dwControlKeyState
                        & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
                    // special "Alt Gr" case (equivalent to Ctrl+Alt)...
                    in.SetModifier(InputData::kModNone);
                }
                else {
                    in.SetModifier(InputData::kModCtrl);
                }
            }
            if ((Key >= 0x30 && Key <= 0x5A /*0-Z*/)
                    || (Key >= VK_NUMPAD0 && Key <= VK_DIVIDE)
                    || (Key >= VK_OEM_1 && Key <= VK_OEM_102)
                    || Key == VK_SPACE) {
                C = buf.Event.KeyEvent.uChar.AsciiChar;
                if (buf.Event.KeyEvent.dwControlKeyState
                        & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
                    // C is already 1..
                }
            } else {
                switch (Key) {
                case VK_BACK:
                    in.SetExtended(InputData::kEIBackSpace);
                    break;
                case VK_TAB:
                    in.SetExtended(InputData::kEITab);
                    break;
                case VK_RETURN:
                    in.SetExtended(InputData::kEIEnter);
                    break;
                case VK_ESCAPE:
                    in.SetExtended(InputData::kEIEsc);
                    break;
                case VK_PRIOR:
                    in.SetExtended(InputData::kEIPgUp);
                    break;
                case VK_NEXT:
                    in.SetExtended(InputData::kEIPgDown);
                    break;
                case VK_END:
                    in.SetExtended(InputData::kEIEnd);
                    break;
                case VK_HOME:
                    in.SetExtended(InputData::kEIHome);
                    break;
                case VK_LEFT:
                    in.SetExtended(InputData::kEILeft);
                    break;
                case VK_UP:
                    in.SetExtended(InputData::kEIUp);
                    break;
                case VK_RIGHT:
                    in.SetExtended(InputData::kEIRight);
                    break;
                case VK_DOWN:
                    in.SetExtended(InputData::kEIDown);
                    break;
                case VK_INSERT:
                    in.SetExtended(InputData::kEIIns);
                    break;
                case VK_DELETE:
                    in.SetExtended(InputData::kEIDel);
                    break;
                case VK_F1:
                    in.SetExtended(InputData::kEIF1);
                    break;
                case VK_F2:
                    in.SetExtended(InputData::kEIF2);
                    break;
                case VK_F3:
                    in.SetExtended(InputData::kEIF3);
                    break;
                case VK_F4:
                    in.SetExtended(InputData::kEIF4);
                    break;
                case VK_F5:
                    in.SetExtended(InputData::kEIF5);
                    break;
                case VK_F6:
                    in.SetExtended(InputData::kEIF6);
                    break;
                case VK_F7:
                    in.SetExtended(InputData::kEIF7);
                    break;
                case VK_F8:
                    in.SetExtended(InputData::kEIF8);
                    break;
                case VK_F9:
                    in.SetExtended(InputData::kEIF9);
                    break;
                case VK_F10:
                    in.SetExtended(InputData::kEIF10);
                    break;
                case VK_F11:
                    in.SetExtended(InputData::kEIF11);
                    break;
                case VK_F12:
                    in.SetExtended(InputData::kEIF12);
                    break;
                default:
                    in.SetExtended(InputData::kEIUninitialized);
                    return false;
                }
                return true;
            }
            break;
        }
        case WINDOW_BUFFER_SIZE_EVENT:
            in.SetExtended(InputData::kEIResizeEvent);
            ++nRead;
            return true;
            break;
        default:
            return false;
        }
    } else {
        if (!::ReadFile(fIn, &C, 1, &NRead, NULL)) {
            HandleError("reading file input");
            return false;
        }
    }
    HandleKeyEvent(C, in);
    ++nRead;
    return true;
}