#include #include #include #include #include // TODO: // // Add sockets. // Add telnet negotiation. // Add conversions to and from wint_t to UTF-8. // Add SSL // Add configure.in // Add scrollback in output window. // class Output; class Status; class Input { public: Input(int lines, int columns, int yOrigin, int xOrigin, Output *pOut); bool Valid(void); int Refresh(void); void AppendCharacter(wchar_t chin); void Backspace(void); bool EndOfLine(void); private: WINDOW *m_w; int m_lines; int m_columns; wchar_t m_aBuffer[4000]; size_t m_nBuffer; Output *m_pOut; }; class Output { public: Output(int lines, int columns, int yOrigin, int xOrigin); bool Valid(void); int Refresh(void); void AppendLine(size_t nLine, const wchar_t *pLine); void AppendLine(const wchar_t *pLine); private: WINDOW *m_w; int m_lines; int m_columns; }; class Status { public: Status(int lines, int columns, int yOrigin, int xOrigin); bool Valid(void); void Update(void); int Refresh(void); private: WINDOW *m_w; int m_lines; int m_columns; }; Input::Input(int lines, int columns, int yOrigin, int xOrigin, Output *pOut) { m_nBuffer = 0; m_pOut = NULL; m_w = newwin(lines, columns, yOrigin, xOrigin); if (NULL != m_w) { m_lines = lines; m_columns = columns; m_pOut = pOut; idlok(m_w, TRUE); scrollok(m_w, TRUE); } } bool Input::Valid(void) { return (NULL != m_w); } int Input::Refresh(void) { return wnoutrefresh(m_w); } void Input::Backspace(void) { if (0 < m_nBuffer) { m_nBuffer--; } int y, x; getyx(m_w, y, x); mvwdelch(m_w, y, x-1); } bool Input::EndOfLine(void) { m_aBuffer[m_nBuffer] = L'\0'; if (wcscasecmp(L"/quit", m_aBuffer) == 0) { return true; } // Send line to output window. // m_pOut->AppendLine(m_nBuffer, m_aBuffer); m_nBuffer = 0; int x, y; getyx(m_w, y, x); if (m_lines-1 == y) { scroll(m_w); wmove(m_w, m_lines-1, 0); } else { wmove(m_w, y+1, 0); } return false; } void Input::AppendCharacter(wchar_t chin) { wchar_t chtemp[2] = { L'\0', L'\0' }; if (m_nBuffer < sizeof(m_aBuffer)) { m_aBuffer[m_nBuffer++] = chin; cchar_t chout; chtemp[0] = chin; if (OK == setcchar(&chout, chtemp, A_NORMAL, 0, NULL)) { (void)wadd_wch(m_w, &chout); } } } Output::Output(int lines, int columns, int yOrigin, int xOrigin) { m_w = newwin(lines, columns, yOrigin, xOrigin); if (NULL != m_w) { m_lines = lines; m_columns = columns; idlok(m_w, TRUE); scrollok(m_w, TRUE); } } bool Output::Valid(void) { return (NULL != m_w); } int Output::Refresh(void) { return wnoutrefresh(m_w); } void Output::AppendLine(size_t nLine, const wchar_t *pLine) { int y, x; getyx(m_w, y, x); if (m_lines-1 == y) { scroll(m_w); wmove(m_w, m_lines-1, 0); } else { wmove(m_w, y+1, 0); } wchar_t chtemp[2] = { L'\0', L'\0' }; for (int i = 0; i < nLine && L'\0' != pLine[i]; i++) { cchar_t chout; chtemp[0] = pLine[i]; if (OK == setcchar(&chout, chtemp, A_NORMAL, 0, NULL)) { (void)wadd_wch(m_w, &chout); } } } void Output::AppendLine(const wchar_t *pLine) { AppendLine(wcslen(pLine), pLine); } Status::Status(int lines, int columns, int yOrigin, int xOrigin) { m_w = newwin(lines, columns, yOrigin, xOrigin); if (NULL != m_w) { m_lines = lines; m_columns = columns; } } bool Status::Valid(void) { return (NULL != m_w); } int Status::Refresh(void) { return wnoutrefresh(m_w); } void Status::Update(void) { wchar_t wchSpace[2] = { L' ', L'\0' }; cchar_t cchSpace; (void)setcchar(&cchSpace, wchSpace, A_UNDERLINE, 0, NULL); wmove(m_w, 0, 0); int n = COLS; while (n--) { (void)wadd_wch(m_w, &cchSpace); } } int main(int argc, char *argv[]) { setlocale(LC_ALL, ""); initscr(); keypad(stdscr, TRUE); if ( COLS < 10 || LINES < 10) { // Too small. // endwin(); fprintf(stderr, "Window is less than 10x10.\r\n"); return 1; } raw(); noecho(); nonl(); idlok(stdscr, TRUE); scrollok(stdscr, TRUE); intrflush(stdscr, FALSE); timeout(50); refresh(); Output output(LINES-3, COLS, 0, 0); Status status(1, COLS, LINES-3, 0); Input input(2, COLS, LINES-2, 0, &output); if ( !output.Valid() || !status.Valid() || !input.Valid()) { endwin(); fprintf(stderr, "Could not create a window.\r\n"); return 1; } wchar_t chtemp[2] = { L'\0', L'\0' }; output.AppendLine(L"Hello, World."); status.Update(); for (;;) { if ( ERR == output.Refresh() || ERR == status.Refresh() || ERR == input.Refresh() || ERR == doupdate()) { break; } wint_t chin; cchar_t chout; int cc = get_wch(&chin); if (KEY_CODE_YES == cc) { // Function key pressed. // if (KEY_BACKSPACE == chin) { input.Backspace(); } else { wchar_t buffer[100]; swprintf(buffer, sizeof(buffer), L"[0x%08X]", chin); output.AppendLine(buffer); } } else if (OK == cc) { // Normal character. // if (iswcntrl(chin)) { // Control character. // if (L'\r' == chin) { if (input.EndOfLine()) { break; } } } else if (iswprint(chin)) { // Printable character. // input.AppendCharacter(chin); } } } endwin(); return 0; }