diff --git a/CMakeLists.txt b/CMakeLists.txt index 26fd7747..2e122088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,7 +183,7 @@ else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-32") add_library(pip STATIC ${CPPS}) else () - list(APPEND LIBS pthread dl) + list(APPEND LIBS pthread dl util) if (NOT APPLE) list(APPEND LIBS rt) endif() diff --git a/FindPIP.cmake b/FindPIP.cmake index c7973a57..71eda5fd 100644 --- a/FindPIP.cmake +++ b/FindPIP.cmake @@ -8,7 +8,8 @@ else () if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") find_library(PTHREAD_LIBRARY pthread) find_library(DL_LIBRARY dl) - list(APPEND PIP_LIBRARY ${PTHREAD_LIBRARY} ${DL_LIBRARY}) + find_library(UTIL_LIBRARY util) + list(APPEND PIP_LIBRARY ${PTHREAD_LIBRARY} ${DL_LIBRARY} ${UTIL_LIBRARY}) endif () set(PIP_INCLUDES /usr/include/pip) set(PIP_CMG /usr/bin/pip_cmg) diff --git a/main.cpp b/main.cpp index 3715e6d4..a3deb4e8 100644 --- a/main.cpp +++ b/main.cpp @@ -20,11 +20,24 @@ const char conn_config[] = device.test.disconnectTimeout = 3.00000000 #f\n\ []\n"; - class Obj : public PIObject { - PIOBJECT(Obj) - public: - Obj() { - CONNECTU(&conn, dataReceivedEvent, this, recv); +private: + void drawEvent(PIScreenDrawer * d) { + //piCout << "draw" << visible; + if (!term) return; + PIVector > c = term->content(); + d->fillRect(x_, y_, x_ + width_, y_ + height_, c); + } + bool keyEvent(PIKbdListener::KeyEvent key) { + //piCout << "key"; + //return false; + if (!term) return false; + if (PITerminal::isSpecialKey(key.key)) term->write((PIKbdListener::SpecialKey)key.key, key.modifiers); + else { + PIByteArray ba; + //ba << PIChar(key.key).toConcole1Byte(); + //piCout << key.key; + ba = PIString(PIChar(key.key)).toUTF8(); + term->write(ba); } EVENT_HANDLER1(void, keyEv, PIKbdListener::KeyEvent, k) { piCoutObj << k.key; @@ -49,20 +62,48 @@ const char conn_config[] = }; int main (int argc, char * argv[]) { - screen.rootTile()->addTile(new TilePICout()); - screen.enableExitCapture(); - screen.rootTile()->children().front()->setFocus(); - Obj * o = new Obj(); - CONNECTU(&screen, keyPressed, o, keyEv) - PIString s = conn_config; - conn.configureFromString(&s); - PISerial * ser = (PISerial *)conn.deviceByName("test"); - if (ser) { - piCout << ser->constructFullPath() << ser->isOpened(); - ser->startThreadedWrite(); + /*const char cs[] = "this is text\e"; + PIByteArray ba(cs, sizeof(cs) - 1); + PIString s(ba); + piCout << ba; + piCout << s; + piCout << s.toByteArray(); + return 0;*/ + PIScreen * screen = 0; + if (argc > 1) screen = new PIScreen(); + PITerminal term; + TileTerminal tt(&term); + if (screen) { + screen->rootTile()->addTile(&tt); + screen->rootTile()->addTile(new TilePICout()); + screen->enableExitCapture(); + } + tt.setFocus(); + term.initialize(); + piMSleep(100); + //term.write(PIString("ls -l /etc/\n").toByteArray()); + //term.write(PIString("mc\n").toByteArray()); + //term.write(PIString("aptitude\n").toByteArray()); + if (screen) { + screen->start(); + piMSleep(100); + //piCout << tt.width() << tt.height(); + term.resize(tt.width(), tt.height()); + screen->waitForFinish(); + } else { + piMSleep(4000); + term.write(PIKbdListener::KeyEvent(PIKbdListener::Tab)); + piMSleep(1000); + term.write(PIKbdListener::KeyEvent(PIKbdListener::Tab)); + //term.write(PIKbdListener::KeyEvent(PIKbdListener::Space)); + //term.write(PIString("exit\n").toByteArray()); + term.write(PIString("Q\n").toByteArray()); + piMSleep(1000); + } + if (screen) { + screen->rootTile()->takeTile(&tt); + delete screen; } - conn.start(); - screen.waitForFinish(); return 0; } diff --git a/src/console/piscreen.cpp b/src/console/piscreen.cpp index c3354743..4d69e6e2 100644 --- a/src/console/piscreen.cpp +++ b/src/console/piscreen.cpp @@ -240,7 +240,12 @@ void PIScreen::SystemConsole::print() { #define BACKGROUND_MASK (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) WORD PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { WORD attr = PRIVATE->dattr; - switch (c.format.color_char) { + bool inv = ((c.format.flags & Inverse) == Inverse); + if (c.format.flags & Bold) attr |= (inv ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY); + else attr &= ~(inv ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY); + if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE; + else attr &= ~COMMON_LVB_UNDERSCORE; + switch (inv ? c.format.color_back : c.format.color_char) { case Black: attr = (attr & ~FOREGROUND_MASK); break; case Red: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED; break; case Green: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_GREEN; break; @@ -250,7 +255,7 @@ WORD PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { case Yellow: attr = (attr & ~FOREGROUND_MASK) | FOREGROUND_RED | FOREGROUND_GREEN; break; case White: attr = attr | FOREGROUND_MASK; break; } - switch (c.format.color_back) { + switch (inv ? c.format.color_char : c.format.color_back) { case Black: attr = (attr & ~BACKGROUND_MASK); break; case Red: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED; break; case Green: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_GREEN; break; @@ -260,10 +265,6 @@ WORD PIScreen::SystemConsole::attributes(const PIScreenTypes::Cell & c) { case Yellow: attr = (attr & ~BACKGROUND_MASK) | BACKGROUND_RED | BACKGROUND_GREEN; break; case White: attr = attr | BACKGROUND_MASK; break; } - if (c.format.flags & Bold) attr |= FOREGROUND_INTENSITY; - else attr &= ~FOREGROUND_INTENSITY; - if (c.format.flags & Underline) attr |= COMMON_LVB_UNDERSCORE; - else attr &= ~COMMON_LVB_UNDERSCORE; return attr; } #undef FOREGROUND_MASK @@ -296,9 +297,6 @@ PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { case Yellow: ts += ";33"; break; case White: ts += ";37"; break; } - if (c.format.flags & Bold) ts += ";1"; - if (c.format.flags & Blink) ts += ";5"; - if (c.format.flags & Underline) ts += ";4"; switch (c.format.color_back) { case Black: ts += ";40"; break; case Red: ts += ";41"; break; @@ -309,6 +307,10 @@ PIString PIScreen::SystemConsole::formatString(const PIScreenTypes::Cell & c) { case Yellow: ts += ";43"; break; case White: ts += ";47"; break; } + if ((c.format.flags & Bold) == Bold) ts += ";1"; + if ((c.format.flags & Underline) == Underline) ts += ";4"; + if ((c.format.flags & Blink) == Blink) ts += ";5"; + if ((c.format.flags & Inverse) == Inverse) ts += ";7"; return ts + "m"; } #endif diff --git a/src/console/piscreentypes.h b/src/console/piscreentypes.h index 69fc1d35..e2e878c2 100644 --- a/src/console/piscreentypes.h +++ b/src/console/piscreentypes.h @@ -47,7 +47,8 @@ namespace PIScreenTypes { enum CharFlag { Bold /** Bold or bright */ = 0x1, Blink /** Blink text */ = 0x2, - Underline /** Underline text */ = 0x4 + Underline /** Underline text */ = 0x4, + Inverse = 0x08 }; //! Alignment @@ -108,7 +109,7 @@ namespace PIScreenTypes { }; struct Cell { - Cell(PIChar c = PIChar(' ')) {symbol = c;} + Cell(PIChar c = PIChar(' '), CellFormat f = CellFormat()) {symbol = c; format = f;} CellFormat format; PIChar symbol; bool operator ==(const Cell & c) const {return format == c.format && symbol == c.symbol;} diff --git a/src/console/piterminal.cpp b/src/console/piterminal.cpp index 68461375..f587d788 100644 --- a/src/console/piterminal.cpp +++ b/src/console/piterminal.cpp @@ -23,13 +23,17 @@ # include # include #else +# include +# include +# include +# include #endif //extern PIMutex __PICout_mutex__; -#define PIPE_BUFFER_SIZE 1024 #ifdef WINDOWS +# define PIPE_BUFFER_SIZE 1024 enum PITerminalAuxMessageType { mtKey = 1, mtResize, @@ -42,6 +46,8 @@ struct PITerminalAuxData { int size_y; int cells_size; }; +#else +# define BUFFER_SIZE 4096 #endif @@ -52,10 +58,21 @@ PRIVATE_DEFINITION_START(PITerminal) STARTUPINFOA si; PROCESS_INFORMATION pi; HANDLE pipe; +#else + PIString shell; + PIByteArray read_buf, tmp_buf; + PIScreenTypes::CellFormat cur_format; + int fd, cur_x, cur_y; + int save_cur_x, save_cur_y; + pid_t pid; + PIString esc_seq; + bool is_esc_seq, last_read; + termios desc; #endif PRIVATE_DEFINITION_END(PITerminal) +#ifdef WINDOWS int writePipe(HANDLE pipe, const PIByteArray & ba) { DWORD wrote[2]; int sz = ba.size_s(); @@ -64,16 +81,19 @@ int writePipe(HANDLE pipe, const PIByteArray & ba) { //piCout << "send" << ba.size_s(); return int(wrote[0] + wrote[1]); } +#endif PITerminal::PITerminal(): PIThread() { setName("terminal"); initPrivate(); - cursor_visible = false; + cursor_blink = false; cursor_x = cursor_y = 0; dsize_x = 80; dsize_y = 24; +#ifdef WINDOWS PRIVATE->shm = 0; +#endif } @@ -82,7 +102,9 @@ PITerminal::~PITerminal() { stop(); PIThread::waitForFinish(10); destroy(); +#ifdef WINDOWS if (PRIVATE->shm) delete PRIVATE->shm; +#endif } @@ -94,15 +116,20 @@ void PITerminal::write(const PIByteArray & d) { ke << PIKbdListener::KeyEvent(d[i]); msg << int(mtKey) << ke; writePipe(PRIVATE->pipe, msg); +#else + if (PRIVATE->fd == 0) return; + ssize_t wrote = 0; + wrote = ::write(PRIVATE->fd, d.data(), d.size_s()); + //piCout << "wrote" << wrote << d; #endif cursor_tm.reset(); - cursor_visible = true; + cursor_blink = true; } void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) { -#ifdef WINDOWS PIByteArray ba; +#ifdef WINDOWS switch (k) { case PIKbdListener::Tab: ba << uchar('\t'); break; case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break; @@ -118,9 +145,42 @@ void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers msg << int(mtKey) << ke; writePipe(PRIVATE->pipe, msg); } +#else + switch (k) { + case PIKbdListener::Tab: ba << uchar('\t'); break; + case PIKbdListener::Return: ba << uchar('\n'); break; + case PIKbdListener::Esc: ba << uchar('\e'); break; + case PIKbdListener::Space: ba << uchar(' '); break; + case PIKbdListener::Backspace: ba << uchar(0x7f); break; + case PIKbdListener::UpArrow: ba << uchar('\e') << uchar('[') /*<< uchar('1')*/ << uchar('A'); break; + case PIKbdListener::DownArrow: ba << uchar('\e') << uchar('[') /*<< uchar('1')*/ << uchar('B'); break; + case PIKbdListener::RightArrow: ba << uchar('\e') << uchar('[') /*<< uchar('1')*/ << uchar('C'); break; + case PIKbdListener::LeftArrow: ba << uchar('\e') << uchar('[') /*<< uchar('1')*/ << uchar('D'); break; + case PIKbdListener::Home: break; + case PIKbdListener::End: break; + case PIKbdListener::PageUp: ba << uchar('\e') << uchar('[') << uchar('5') << uchar('~'); break; + case PIKbdListener::PageDown: ba << uchar('\e') << uchar('[') << uchar('6') << uchar('~'); break; + case PIKbdListener::Insert: ba << uchar('\e') << uchar('[') << uchar('2') << uchar('~'); break; + case PIKbdListener::Delete: ba << uchar('\e') << uchar('[') << uchar('3') << uchar('~'); break; + case PIKbdListener::F1: break; + case PIKbdListener::F2: break; + case PIKbdListener::F3: break; + case PIKbdListener::F4: break; + case PIKbdListener::F5: break; + case PIKbdListener::F6: break; + case PIKbdListener::F7: break; + case PIKbdListener::F8: break; + case PIKbdListener::F9: break; + case PIKbdListener::F10: break; + case PIKbdListener::F11: break; + case PIKbdListener::F12: break; + default: break; + } + //piCout << "write" << ba.size(); + if (!ba.isEmpty()) write(ba); #endif cursor_tm.reset(); - cursor_visible = true; + cursor_blink = true; } @@ -136,7 +196,13 @@ void PITerminal::write(PIKbdListener::KeyEvent ke) { PIVector > PITerminal::content() { readConsole(); - return cells; + getCursor(cursor_x, cursor_y); + PIVector > ret = cells; + if (cursor_blink && cursor_visible) + if (cursor_x >= 0 && cursor_x < size_x) + if (cursor_y >= 0 && cursor_y < size_y) + ret[cursor_y][cursor_x].format.flags ^= PIScreenTypes::Inverse; + return ret; } @@ -180,7 +246,19 @@ void PITerminal::initPrivate() { PRIVATE->hConBuf = INVALID_HANDLE_VALUE; PRIVATE->pipe = INVALID_HANDLE_VALUE; PRIVATE->pi.hProcess = 0; +#else + PRIVATE->shell = "/bin/bash"; + PRIVATE->read_buf.reserve(BUFFER_SIZE); + PRIVATE->read_buf.fill(0); + PRIVATE->fd = PRIVATE->cur_x = PRIVATE->cur_y = 0; + PRIVATE->save_cur_x = PRIVATE->save_cur_y = 0; + PRIVATE->pid = 0; + PRIVATE->is_esc_seq = false; + PRIVATE->last_read = true; + PRIVATE->esc_seq.clear(); + PRIVATE->cur_format = PIScreenTypes::CellFormat(); #endif + cursor_blink = cursor_visible = true; size_x = size_y = 0; } @@ -201,10 +279,6 @@ void PITerminal::readConsole() { ba >> cells; #endif //piCout << cursor_x << cursor_y; - if (cursor_visible) - if (cursor_x >= 0 && cursor_x < size_x) - if (cursor_y >= 0 && cursor_y < size_y) - cells[cursor_y][cursor_x].format.color_back = invertColor(cells[cursor_y][cursor_x].format.color_back); } @@ -213,6 +287,9 @@ void PITerminal::getCursor(int & x, int & y) { if (!PRIVATE->shm) return; int sz = 0; PRIVATE->shm->read(&sz, 4); +#else + x = PRIVATE->cur_x; + y = PRIVATE->cur_y; #endif } @@ -236,14 +313,286 @@ uchar PITerminal::invertColor(uchar c) { void PITerminal::run() { if (cursor_tm.elapsed_m() >= 500) { cursor_tm.reset(); - cursor_visible = !cursor_visible; - if (cursor_visible) { + cursor_blink = !cursor_blink; + if (cursor_blink) { getCursor(cursor_x, cursor_y); } } +#ifndef WINDOWS + if (PRIVATE->fd == 0) return; + PRIVATE->tmp_buf.resize(BUFFER_SIZE); + int readed = ::read(PRIVATE->fd, PRIVATE->tmp_buf.data(), BUFFER_SIZE - PRIVATE->read_buf.size_s()); + bool used = false; + if (readed > 0) { + PRIVATE->last_read = true; + //piCoutObj << "readed" << readed << PIString(PRIVATE->tmp_buf.resized(readed)).replaceAll("\e", "\\e"); + piCoutObj << "readed" << readed << (PRIVATE->tmp_buf.resized(readed)); + PRIVATE->read_buf.append(PRIVATE->tmp_buf.resized(readed)); + for (;;) { + int ind = -1; + for (int i = PRIVATE->read_buf.size_s() - 1; i >= 0; --i) + if (PRIVATE->read_buf[i] == uchar('\n') || PRIVATE->read_buf[i] == uchar('\e')) { + ind = i; + break; + } + if (ind <= 0) break; + used = true; + parseInput(PIString((const char *)PRIVATE->read_buf.data(), ind)); + PRIVATE->read_buf.remove(0, ind); + } + if (PRIVATE->read_buf.size_s() >= BUFFER_SIZE) { + parseInput(PIString(PRIVATE->read_buf)); + PRIVATE->read_buf.clear(); + } + //printf("%s", PRIVATE->read_buf.data()); + } + if (!used && !PRIVATE->last_read && !PRIVATE->read_buf.isEmpty()) { + parseInput(PIString(PRIVATE->read_buf)); + PRIVATE->read_buf.clear(); + } + PRIVATE->last_read = false; +#endif } +#ifndef WINDOWS +void PITerminal::parseInput(const PIString & s) { + //piCoutObj << s.replaceAll("\e", "\\e"); + //printf("%s", s.data()); + for (int i = 0; i < s.size_s(); ++i) { + if (s[i].unicode16Code() == 0) break; + if (PRIVATE->is_esc_seq) { + if (s[i] == '\e') { + applyEscSeq(PRIVATE->esc_seq); + PRIVATE->esc_seq.clear(); + PRIVATE->is_esc_seq = true; + } else { + PRIVATE->esc_seq += s[i]; + if (isCompleteEscSeq(PRIVATE->esc_seq)) { + PRIVATE->is_esc_seq = false; + applyEscSeq(PRIVATE->esc_seq); + //piCoutObj << PRIVATE->esc_seq; + } + } + } else { + if (s[i] == '\e') { + PRIVATE->esc_seq.clear(); + PRIVATE->is_esc_seq = true; + } else { + if (s[i] == '\a') continue; + if (s[i] == '\b') { + moveCursor(-1, 0); + continue; + } + if (s[i] == '\r') continue; + if (s[i] == '\n') { + //piCoutObj << "new line"; + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i].format = PRIVATE->cur_format; + PRIVATE->cur_x = 0; + moveCursor(0, 1); + continue; + } + //piCoutObj << "char" << s[i] << s[i].unicode16Code() << "at" << PRIVATE->cur_x << PRIVATE->cur_y; + cells[PRIVATE->cur_y][PRIVATE->cur_x].symbol = s[i]; + cells[PRIVATE->cur_y][PRIVATE->cur_x].format = PRIVATE->cur_format; + moveCursor(1, 0); + } + } + } +} + + +bool PITerminal::isCompleteEscSeq(const PIString & es) { + if (es.size_s() < 2) return false; + if (es.front() == ']') { + if (es.back().toAscii() == '\\' || es.back().toAscii() == '\a') return true; + } else { + if (es.back().toAscii() >= 64 && es.back().toAscii() <= 126) return true; + } + return false; +} + + +void PITerminal::applyEscSeq(PIString es) { + piCoutObj << es; + if (es.size_s() < 2) return; + if (es[1] == '?' && es.size_s() >= 2) { // cursor + PIString c = es.mid(2); + if (c == "25l") cursor_visible = false; + if (c == "25h") cursor_visible = true; + } + PIScreenTypes::Cell def_cell = PIScreenTypes::Cell(' ', PRIVATE->cur_format); + if (es[0] == '[') { // CSI + if (es.back() == 'm') { + es.cutLeft(1).cutRight(1); + if (es.isEmpty()) { + PRIVATE->cur_format = PIScreenTypes::CellFormat(); + return; + } + PIStringList args = es.split(";"); + piForeachC (PIString & a, args) { + int av = a.toInt(); + switch (av) { + case 0: PRIVATE->cur_format = PIScreenTypes::CellFormat(); break; + case 1: PRIVATE->cur_format.flags |= PIScreenTypes::Bold; break; + case 4: PRIVATE->cur_format.flags |= PIScreenTypes::Underline; break; + case 5: PRIVATE->cur_format.flags |= PIScreenTypes::Blink; break; + case 7: PRIVATE->cur_format.flags |= PIScreenTypes::Inverse; break; + default: { + bool col = false, target = false; + int cid = av % 10; + if (av >= 30 && av <= 37) {col = true; target = false;} + if (av >= 40 && av <= 47) {col = true; target = true;} + if (col) { + int cfl = 0; + switch (cid) { + case 0: cfl = PIScreenTypes::Black; break; + case 1: cfl = PIScreenTypes::Red; break; + case 2: cfl = PIScreenTypes::Green; break; + case 3: cfl = PIScreenTypes::Yellow; break; + case 4: cfl = PIScreenTypes::Blue; break; + case 5: cfl = PIScreenTypes::Magenta; break; + case 6: cfl = PIScreenTypes::Cyan; break; + case 7: cfl = PIScreenTypes::White; break; + } + (target ? PRIVATE->cur_format.color_back : PRIVATE->cur_format.color_char) = cfl; break; + } + } break; + } + } + /*if ((PRIVATE->cur_format.flags & PIScreenTypes::Inverse) == PIScreenTypes::Inverse) { + uchar t = PRIVATE->cur_format.color_char; + PRIVATE->cur_format.color_char = PRIVATE->cur_format.color_back; + PRIVATE->cur_format.color_back = t; + }*/ + } + if (es.back() == 's') { + PRIVATE->save_cur_x = PRIVATE->cur_x; + PRIVATE->save_cur_y = PRIVATE->cur_y; + } + if (es.back() == 'u') { + PRIVATE->cur_x = PRIVATE->save_cur_x; + PRIVATE->cur_y = PRIVATE->save_cur_y; + } + if (es.back() == 'H' || es.back() == 'f') { + es.cutLeft(1).cutRight(1); + PIStringList args = es.split(";"); + args.resize(2); + int x(0), y(0); + if (!args[0].isEmpty()) y = args[0].toInt() - 1; + if (!args[1].isEmpty()) x = args[1].toInt() - 1; + //piCoutObj << x << y; + PRIVATE->cur_x = piClamp(x, 0, size_x - 1); + PRIVATE->cur_y = piClamp(y, 0, size_y - 1); + } + if (es.back() == 'A') { // cursor up + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); + } + if (es.back() == 'B') { // cursor down + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); + } + if (es.back() == 'C' || es.back() == 'a') { // cursor forward, next column + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = piClamp(PRIVATE->cur_x + v, 0, size_x - 1); + } + if (es.back() == 'D') { // cursor back + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = piClamp(PRIVATE->cur_x - v, 0, size_x - 1); + } + if (es.back() == 'G' || es.back() == '`') { // goto column + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + if (v) PRIVATE->cur_x = piClamp(v - 1, 0, size_x - 1); + } + if (es.back() == 'd') { // goto line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(v - 1, 0, size_y - 1); + } + if (es.back() == 'E' || es.back() == 'e') { // next line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y + v, 0, size_y - 1); + } + if (es.back() == 'F') { // previous line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + PRIVATE->cur_x = 0; + PRIVATE->cur_y = piClamp(PRIVATE->cur_y - v, 0, size_y - 1); + } + if (es.back() == 'P') { // delete characters + es.cutLeft(1).cutRight(1); + int v = es.toInt(); if (v == 0) v = 1; + for (int i = PRIVATE->cur_x; i < size_x - v; ++i) cells[PRIVATE->cur_y][i] = cells[PRIVATE->cur_y][i + v]; + for (int i = size_x - v; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + } + if (es.back() == 'J') { // erase data + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + switch (v) { + case 0: + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + for (int i = PRIVATE->cur_y + 1; i < size_y; ++i) cells[i].fill(def_cell); + break; + case 1: + for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + for (int i = 0; i < PRIVATE->cur_y; ++i) cells[i].fill(def_cell); + break; + case 2: + for (int i = 0; i < size_y; ++i) cells[i].fill(def_cell); + //PRIVATE->cur_x = PRIVATE->cur_y = 0; + break; + } + } + if (es.back() == 'K') { // erase in line + es.cutLeft(1).cutRight(1); + int v = es.toInt(); + switch (v) { + case 0: + for (int i = PRIVATE->cur_x; i < size_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + break; + case 1: + for (int i = 0; i <= PRIVATE->cur_x; ++i) cells[PRIVATE->cur_y][i] = def_cell; + break; + case 2: + cells[PRIVATE->cur_y].fill(def_cell); + break; + } + } + } +} + + +void PITerminal::moveCursor(int dx, int dy) { + PRIVATE->cur_x += dx; + PRIVATE->cur_y += dy; + if (PRIVATE->cur_x < 0) PRIVATE->cur_x = 0; + if (PRIVATE->cur_y < 0) PRIVATE->cur_y = 0; + if (PRIVATE->cur_x >= size_x) { + PRIVATE->cur_x = 0; + PRIVATE->cur_y++; + } + if (PRIVATE->cur_y >= size_y) { + int scroll = piMini(PRIVATE->cur_y - size_y + 1, size_y - 1); + //piCout << "scroll" << size_x << size_y << size_y - scroll - 1; + PRIVATE->cur_y = size_y - 1; + for (int y = 0; y < size_y - scroll; ++y) + cells[y] = cells[y + scroll]; + for (int y = size_y - scroll; y < size_y; ++y) + cells[y].fill(PIScreenTypes::Cell()); + } +} +#endif + + bool PITerminal::initialize() { destroy(); #ifdef WINDOWS @@ -309,32 +658,58 @@ bool PITerminal::initialize() { } if (PRIVATE->shm) delete PRIVATE->shm; PRIVATE->shm = new PISharedMemory("piterm_aux" + shmh, 1024*1024); - //WaitForSingleObject(PRIVATE->pi.hProcess, INFINITE); - //piCout << PRIVATE->pi.hThread << PRIVATE->pi.hProcess; CloseHandle(PRIVATE->pi.hThread); resize(dsize_x, dsize_y); +#else + char pty[256]; memset(pty, 0, 256); + winsize ws; + ws.ws_col = dsize_x; + ws.ws_row = dsize_y; + pid_t fr = forkpty(&(PRIVATE->fd), pty, 0, &ws); + //piCoutObj << fr << PRIVATE->fd << pty; + if (fr == 0) { + char ** argv = new char*[2]; + argv[0] = new char[PRIVATE->shell.lengthAscii() + 1]; + memcpy(argv[0], PRIVATE->shell.dataAscii(), PRIVATE->shell.lengthAscii()); + argv[0][PRIVATE->shell.lengthAscii()] = 0; + argv[1] = 0; + execvp(PRIVATE->shell.dataAscii(), argv); + delete[] argv[0]; + delete[] argv; + exit(0); + } else { + if (fr < 0 || PRIVATE->fd < 0) { + piCoutObj << "forkpty error," << errorString(); + initPrivate(); + return false; + } + PRIVATE->pid = fr; + fcntl(PRIVATE->fd, F_SETFL, O_NONBLOCK); + /* + tcgetattr(PRIVATE->fd, &PRIVATE->desc); + PRIVATE->desc.c_oflag = PRIVATE->desc.c_lflag = PRIVATE->desc.c_cflag = 0; + PRIVATE->desc.c_iflag = IGNBRK; + PRIVATE->desc.c_cflag = CLOCAL | HUPCL; + PRIVATE->desc.c_cflag |= (CSIZE & CS8); + PRIVATE->desc.c_cflag |= CREAD; + PRIVATE->desc.c_cc[VMIN] = 1; + PRIVATE->desc.c_cc[VTIME] = 1; - /*DWORD written; - WriteFile(PRIVATE->pipe_in[1], "pisd -h\r\n", 9, &written, 0); - piCout << "write" << written; - piMSleep(500);*/ - /*PIByteArray rb(1024); - ReadFile(PRIVATE->pipe_out[0], rb.data(), rb.size_s(), &written, 0); - piCout << "read" << written; - piCout << PIString(rb);*/ - /*bool a = AllocConsole(); - if (a) { - HWND wnd = GetConsoleWindow(); - if (wnd) - ShowWindow(wnd, SW_HIDE); - } - PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, 0, CONSOLE_TEXTMODE_BUFFER, 0); - if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) { - piCoutObj << "CreateConsoleScreenBuffer error," << errorString(); + cfsetispeed(&PRIVATE->desc, B38400); + cfsetospeed(&PRIVATE->desc, B38400); + + if (tcsetattr(PRIVATE->fd, TCSANOW, &PRIVATE->desc) < 0) { + piCoutObj << "Can`t set attributes for \"" << pty << "\""; + destroy(); return false; - }*/ + } + */ + size_x = dsize_x; + size_y = dsize_y; + resize(size_x, size_y); + } #endif - cursor_visible = false; + cursor_blink = false; cursor_tm.reset(); start(40); return true; @@ -355,6 +730,11 @@ void PITerminal::destroy() { if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe); if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf); //piCout << "destroy" << size_y; +#else + if (PRIVATE->pid != 0) + kill(PRIVATE->pid, SIGKILL); + if (PRIVATE->fd != 0) + ::close(PRIVATE->fd); #endif initPrivate(); } @@ -369,6 +749,15 @@ bool PITerminal::resize(int cols, int rows) { PIByteArray msg; msg << int(mtResize) << dsize_x << dsize_y; writePipe(PRIVATE->pipe, msg); +#else + if (PRIVATE->fd == 0) return false; + size_x = dsize_x; + size_y = dsize_y; + //piCout << "resize" << PRIVATE->fd << size_x << size_y; + winsize ws; + ws.ws_col = cols; + ws.ws_row = rows; + ioctl(PRIVATE->fd, TIOCSWINSZ, &ws); #endif cells.resize(size_y); for (int i = 0; i < size_y; ++i) diff --git a/src/console/piterminal.h b/src/console/piterminal.h index 2ba1df4d..fb6cc31c 100644 --- a/src/console/piterminal.h +++ b/src/console/piterminal.h @@ -56,11 +56,17 @@ private: void getCursor(int & x, int & y); uchar invertColor(uchar c); void run(); +#ifndef WINDOWS + void parseInput(const PIString & s); + bool isCompleteEscSeq(const PIString & es); + void applyEscSeq(PIString es); + void moveCursor(int dx, int dy); +#endif PRIVATE_DECLARATION int dsize_x, dsize_y; int size_x, size_y, cursor_x, cursor_y; - bool cursor_visible; + bool cursor_blink, cursor_visible; PITimeMeasurer cursor_tm; PIVector > cells; diff --git a/src/core/pichar.cpp b/src/core/pichar.cpp index 58c835ec..d7d9e6a4 100644 --- a/src/core/pichar.cpp +++ b/src/core/pichar.cpp @@ -38,14 +38,15 @@ char * __sysoemname__ = 0; */ -PIChar::PIChar(const char * c) { +PIChar::PIChar(const char * c, int * bytes) { #ifdef PIP_ICU UErrorCode e((UErrorCode)0); UConverter * cc = ucnv_open(__syslocname__, &e); if (cc) { UChar uc; e = (UErrorCode)0; - ucnv_toUChars(cc, &uc, 1, c, 4, &e); + int ret = ucnv_toUChars(cc, &uc, 1, c, 4, &e); + if (bytes) * bytes = ret; ucnv_close(cc); ch = uc; return; diff --git a/src/core/pichar.h b/src/core/pichar.h index 1d74e220..ef2c80cd 100755 --- a/src/core/pichar.h +++ b/src/core/pichar.h @@ -56,7 +56,7 @@ public: PIChar(const uint c = 0) {ch = c;} //! Contructs symbol from no more than 4 bytes of string - PIChar(const char * c); + PIChar(const char * c, int * bytes = 0); //inline operator const int() {return static_cast(ch);} //inline operator const char() {return toAscii();} diff --git a/src/io/piserial.cpp b/src/io/piserial.cpp index 485cdd20..a5fe3b16 100755 --- a/src/io/piserial.cpp +++ b/src/io/piserial.cpp @@ -583,7 +583,7 @@ void PISerial::applySettings() { tcflush(fd, TCIOFLUSH); setTimeouts(); - if(tcsetattr(fd, TCSANOW, &PRIVATE->desc) < 0) { + if (tcsetattr(fd, TCSANOW, &PRIVATE->desc) < 0) { piCoutObj << "Can`t set attributes for \"" << path() << "\""; return; }