diff --git a/CMakeLists.txt b/CMakeLists.txt index 124ba8e4..26fd7747 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,9 @@ else () message(STATUS "Install to local \"bin\"") endif () +# Auxiliary +add_subdirectory("src/auxiliary/piterminal") + # Utils add_subdirectory("utils/system_test") add_subdirectory("utils/remote_console") diff --git a/main.cpp b/main.cpp index 29e5637c..786e4f4b 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,7 @@ #include "piethernet.h" #include "piintrospection.h" #include "pifile.h" -#include "pisingleapplication.h" +#include "piterminal.h" //struct MS { // //MS() {i = 0; f = 0.;} @@ -31,13 +31,58 @@ public: T dot(VC a) {T res = T(); for (uint i=0; i > c = term->content(); + d->fillRect(x, y, x + width, y + height, c); + } + bool keyEvent(PIKbdListener::KeyEvent key) { + //piCout << "key"; + 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(); + term->write(ba); + } + return true; + } + void resizeEvent(int w, int h) { + if (!term) return; + term->resize(w, h); + } + + + PITerminal * term; +}; int main (int argc, char * argv[]) { - PISingleApplication sa("app"); + PIScreen screen; + PITerminal term; + TerminalTile tt(&term); + screen.rootTile()->addTile(&tt); + tt.setFocus(); + screen.enableExitCapture(); + term.initialize(); + piMSleep(100); + term.write(PIString("pisd -h").toByteArray()); + screen.start(); + screen.waitForFinish(); + term.destroy(); + return 0; + /*PISingleApplication sa("app"); if (!sa.isFirst()) sa.sendMessage(PIString("message to first").toByteArray()); else - piMSleep(5000); + piMSleep(5000);*/ //piCout << PIString(argv[1]).toInt(); //sh.destroy(); //proc.terminate(); diff --git a/src/auxiliary/piterminal/CMakeLists.txt b/src/auxiliary/piterminal/CMakeLists.txt new file mode 100644 index 00000000..77ce30f6 --- /dev/null +++ b/src/auxiliary/piterminal/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(piterminal "main.cpp") +target_link_libraries(piterminal pip) +if (DEFINED LIB) + install(TARGETS piterminal DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) +endif () diff --git a/src/auxiliary/piterminal/main.cpp b/src/auxiliary/piterminal/main.cpp new file mode 100644 index 00000000..3f50c99f --- /dev/null +++ b/src/auxiliary/piterminal/main.cpp @@ -0,0 +1,258 @@ +#include "piplatform.h" + +#ifndef WINDOWS +int main (int argc, char * argv[]) { + return 0; +} +#else +# include "piscreentypes.h" +# include "pisharedmemory.h" +# include "piterminal.cpp" +# include "pifile.h" +# include + + +PIVector > cells; +CONSOLE_SCREEN_BUFFER_INFO sbi; +CHAR_INFO * chars = 0; +HANDLE console = 0, cstdin = 0, pipe = 0, cmd_proc = 0; +PITerminalAuxData data_out; +PIMutex con_mutex; +int con_w = -1, con_h = -1; + + +PIScreenTypes::Cell CharInfo2Cell(const CHAR_INFO & c) { + PIScreenTypes::Cell ret; + ret.symbol = PIChar::fromConsole(c.Char.AsciiChar); + ret.format.color_char = PIScreenTypes::Black; + if ((c.Attributes & (FOREGROUND_RED)) == FOREGROUND_RED) ret.format.color_char = PIScreenTypes::Red; + if ((c.Attributes & (FOREGROUND_GREEN)) == FOREGROUND_GREEN) ret.format.color_char = PIScreenTypes::Green; + if ((c.Attributes & (FOREGROUND_BLUE)) == FOREGROUND_BLUE) ret.format.color_char = PIScreenTypes::Blue; + if ((c.Attributes & (FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Cyan; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::Magenta; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN)) == (FOREGROUND_RED | FOREGROUND_GREEN)) ret.format.color_char = PIScreenTypes::Yellow; + if ((c.Attributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_char = PIScreenTypes::White; + ret.format.color_back = PIScreenTypes::Black; + if ((c.Attributes & (BACKGROUND_RED)) == (BACKGROUND_RED)) ret.format.color_back = PIScreenTypes::Red; + if ((c.Attributes & (BACKGROUND_GREEN)) == (BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Green; + if ((c.Attributes & (BACKGROUND_BLUE)) == (BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Blue; + if ((c.Attributes & (BACKGROUND_GREEN | BACKGROUND_BLUE)) == (BACKGROUND_GREEN | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Cyan; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_BLUE)) == (BACKGROUND_RED | BACKGROUND_BLUE)) ret.format.color_back = PIScreenTypes::Magenta; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN)) == (BACKGROUND_RED | BACKGROUND_GREEN)) ret.format.color_back = PIScreenTypes::Yellow; + if ((c.Attributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE)) == (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)) ret.format.color_back = PIScreenTypes::White; + if ((c.Attributes & (FOREGROUND_INTENSITY)) > 0) ret.format.flags |= PIScreenTypes::Bold; + return ret; +} + + +int SpecialKey2VirtualKeyCode(PIKbdListener::SpecialKey k) { + switch (k) { + case PIKbdListener::Tab : return '\t'; break; + case PIKbdListener::Return : return '\n'; break; + case PIKbdListener::Space : return ' '; break; + case PIKbdListener::Backspace : return 8 ; + case PIKbdListener::PageUp : return 33 ; + case PIKbdListener::PageDown : return 34 ; + case PIKbdListener::End : return 35 ; + case PIKbdListener::Home : return 36 ; + case PIKbdListener::LeftArrow : return 37 ; + case PIKbdListener::UpArrow : return 38 ; + case PIKbdListener::RightArrow: return 39 ; + case PIKbdListener::DownArrow : return 40 ; + case PIKbdListener::Insert : return 45 ; + case PIKbdListener::Delete : return 46 ; + case PIKbdListener::F1 : return 112; + case PIKbdListener::F2 : return 113; + case PIKbdListener::F3 : return 114; + case PIKbdListener::F4 : return 115; + case PIKbdListener::F5 : return 116; + case PIKbdListener::F6 : return 117; + case PIKbdListener::F7 : return 118; + case PIKbdListener::F8 : return 119; + case PIKbdListener::F9 : return 120; + case PIKbdListener::F10 : return 121; + case PIKbdListener::F11 : return 122; + case PIKbdListener::F12 : return 123; + default: break; + } + return 0; +} + + +int KeyModifiers2ControlKeyState(PIKbdListener::KeyModifiers m) { + int ret(0); + if (m[PIKbdListener::Ctrl]) ret |= LEFT_CTRL_PRESSED; + if (m[PIKbdListener::Shift]) ret |= SHIFT_PRESSED; + if (m[PIKbdListener::Alt]) ret |= LEFT_ALT_PRESSED; + return ret; +} + + +void readConsole(int x, int y, int w, int h) { + GetConsoleScreenBufferInfo(console, &sbi); + COORD bs, bc; + bs.X = w; + bs.Y = h; + bc.X = bc.Y = 0; + ReadConsoleOutput(console, chars, bs, bc, &(sbi.srWindow)); + for (int i = 0; i < h; ++i) + for (int j = 0; j < w; ++j) + cells[i][j] = CharInfo2Cell(chars[i * w + j]); +} + + +void resizeCells(int w, int h) { + if (chars) delete[] chars; + chars = new CHAR_INFO[w * h]; + cells.resize(h); + for (int i = 0; i < h; ++i) + cells[i].resize(w); +} + + +void resizeConsole(int w, int h) { + if (con_w == w && con_h == h) return; + con_w = w; + con_h = h; + GetConsoleScreenBufferInfo(console, &sbi); + sbi.srWindow.Right = sbi.srWindow.Left + w - 1; + sbi.srWindow.Bottom = sbi.srWindow.Top + h - 1; + SetConsoleWindowInfo(console, TRUE, &(sbi.srWindow)); + //system(("mode CON: COLS=" + PIString::fromNumber(w) + " LINES=" + PIString::fromNumber(h)).dataAscii()); + resizeCells(w, h); +} + + +class PipeReader: public PIThread { +public: + PipeReader(): PIThread() { + wrote = readed = 0; + msg_size = 0; + start(1); + } + ~PipeReader() { + stop(); + } + void run() { + in.resize(PIPE_BUFFER_SIZE); + ReadFile(pipe, in.data(), in.size_s(), &readed, 0); + if (GetLastError() == ERROR_BROKEN_PIPE) { + stop(); + return; + } + //piCout << errorString(); + if (readed > 0) { + in.resize(readed); + stream.append(in); + if (msg_size == 0) { + if (stream.size_s() < 4) return; + stream >> msg_size; + } + if (stream.size_s() >= msg_size) { + msg = PIByteArray(stream.data(), msg_size); + stream.remove(0, msg_size); + msg_size = 0; + parseMessage(); + } + if (msg_size == 0 && stream.size_s() < 4) return; + } + } + void parseMessage() { + if (msg.size_s() < 4) return; + PIMutexLocker _ml(con_mutex); + int type; msg >> type; + //piCout << "msg" << type; + switch ((PITerminalAuxMessageType)type) { + case mtKey: { + PIVector ke; + msg >> ke; + PIVector ir(ke.size() * 2); + for (int i = 0; i < ke.size_s(); ++i) { + PIKbdListener::KeyEvent k(ke[i]); + int j = i+i, z = j+1; + ir[j].EventType = KEY_EVENT; + ir[j].Event.KeyEvent.wRepeatCount = 1; + ir[j].Event.KeyEvent.dwControlKeyState = KeyModifiers2ControlKeyState(k.modifiers); + if (PITerminal::isSpecialKey(k.key)) + ir[j].Event.KeyEvent.wVirtualKeyCode = SpecialKey2VirtualKeyCode((PIKbdListener::SpecialKey)k.key); + ir[j].Event.KeyEvent.uChar.AsciiChar = PIChar(piMaxi(k.key, 0)).toConcole1Byte(); + //piCout << ir[j].Event.KeyEvent.wVirtualKeyCode << int(ir[j].Event.KeyEvent.uChar.AsciiChar); + ir[j].Event.KeyEvent.bKeyDown = true; + ir[z] = ir[j]; + ir[z].Event.KeyEvent.bKeyDown = false; + } + WriteConsoleInput(cstdin, ir.data(), ir.size_s(), &wrote); + } + break; + case mtResize: { + int rw, rh; + msg >> rw >> rh; + resizeConsole(rw, rh); + } + break; + default: break; + } + } + DWORD wrote, readed; + int msg_size; + PIByteArray in, stream, msg; +}; + + +void getCursor(int & x, int & y) { + GetConsoleScreenBufferInfo(console, &sbi); + x = sbi.dwCursorPosition.X + sbi.srWindow.Left; + y = sbi.dwCursorPosition.Y + sbi.srWindow.Top; +} + + +int main (int argc, char * argv[]) { + //piCout << "start"; + STARTUPINFO si; + PROCESS_INFORMATION pi; + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + memset(&sbi, 0, sizeof(sbi)); + PIString shmh, pname; + if (argc > 1) shmh = argv[1]; + if (argc > 2) pname = argv[2]; + if(!CreateProcessA(0, (LPSTR)"cmd", 0, 0, true, 0, 0, 0, &si, &pi)) { + return 1; + } + PISharedMemory shm("piterm_aux" + shmh, 1024*1024); + pipe = CreateFile((LPSTR)pname.dataAscii(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); + if (pipe == INVALID_HANDLE_VALUE) { + return 1; + } + CloseHandle(pi.hThread); + cmd_proc = pi.hProcess; + console = GetStdHandle(STD_OUTPUT_HANDLE); + cstdin = GetStdHandle(STD_INPUT_HANDLE); + resizeConsole(80, 24); + PipeReader pipe_reader; + pipe_reader.waitForStart(); + PIByteArray scr; + while (true) { + //piCout << "loop"; + if (!pipe_reader.isRunning()) break; + con_mutex.lock(); + getCursor(data_out.cursor_x, data_out.cursor_y); + readConsole(0, 0, con_w, con_h); + scr.clear(); + scr << cells; + data_out.size_x = con_w; + data_out.size_y = con_h; + data_out.cells_size = scr.size_s(); + con_mutex.unlock(); + shm.write(&data_out, sizeof(data_out)); + shm.write(scr, sizeof(data_out)); + piMSleep(25); + } + //piCout << "exit"; + TerminateProcess(pi.hProcess, 0); + CloseHandle(pi.hProcess); + return 0; +} + + +#endif diff --git a/src/console/pikbdlistener.cpp b/src/console/pikbdlistener.cpp index 09bdbb2c..5bc67384 100644 --- a/src/console/pikbdlistener.cpp +++ b/src/console/pikbdlistener.cpp @@ -187,7 +187,7 @@ void PIKbdListener::readKeyboard() { if (alt) ke.modifiers |= Alt; //if (meta) ke.modifiers |= Meta; if (ker.dwControlKeyState & CAPSLOCK_ON) shift = !shift; - //cout << "key " << int(ker.wVirtualKeyCode) << endl; + //piCout << "key" << int(ker.wVirtualKeyCode) << int(ker.uChar.AsciiChar); switch (ker.wVirtualKeyCode) { case 8: ret = 1; ke.key = Backspace; break; case 33: ret = 1; ke.key = PageUp; break; diff --git a/src/console/pikbdlistener.h b/src/console/pikbdlistener.h index c7dde541..a5dff354 100644 --- a/src/console/pikbdlistener.h +++ b/src/console/pikbdlistener.h @@ -169,4 +169,10 @@ private: }; + +inline PIByteArray & operator <<(PIByteArray & s, const PIKbdListener::KeyEvent & v) {s << v.key << int(v.modifiers); return s;} + +inline PIByteArray & operator >>(PIByteArray & s, PIKbdListener::KeyEvent & v) {int m(0); s >> v.key >> m; v.modifiers = m; return s;} + + #endif // PIKBDLISTENER_H diff --git a/src/console/piscreendrawer.cpp b/src/console/piscreendrawer.cpp index 8bcae4ac..046de556 100644 --- a/src/console/piscreendrawer.cpp +++ b/src/console/piscreendrawer.cpp @@ -76,8 +76,7 @@ PIScreenDrawer::PIScreenDrawer(PIVector > & c): cells(c) { void PIScreenDrawer::clear() { - for (int i = 0; i < cells.size_s(); ++i) - cells[i].fill(Cell()); + clear(cells); } @@ -215,6 +214,30 @@ void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, const PIChar & c, } +void PIScreenDrawer::fillRect(int x0, int y0, int x1, int y1, PIVector > & content) { + if (x0 > x1) piSwap(x0, x1); + if (y0 > y1) piSwap(y0, y1); + int w = x1 - x0; + int h = y1 - y0; + for (int j = y0; j != h; ++j) + if (j >= 0 && j < piMini(height, content.size_s())) { + if ((j + y0) >= 0 && (j + y0) < height) { + PIVector & cv(cells[y0 + j]); + PIVector & contv(content[j]); + for (int i = 0; i != piMini(w, contv.size_s()); ++i) + if ((i + x0) >= 0 && (i + x0) < width) + cv[x0 + i] = contv[i]; + } + } +} + + +void PIScreenDrawer::clear(PIVector > & cells) { + for (int i = 0; i < cells.size_s(); ++i) + cells[i].fill(Cell()); +} + + void PIScreenDrawer::drawText(int x, int y, const PIString & s, Color col_char, Color col_back, CharFlags flags_char) { if (x < 0 || x >= width || y < 0 || y >= height) return; PIVector & cv(cells[y]); diff --git a/src/console/piscreendrawer.h b/src/console/piscreendrawer.h index 94a710ec..8696f5fb 100644 --- a/src/console/piscreendrawer.h +++ b/src/console/piscreendrawer.h @@ -41,9 +41,12 @@ public: void drawFrame(int x0, int y0, int x1, int y1, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); void drawText(int x, int y, const PIString & s, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Transparent, PIScreenTypes::CharFlags flags_char = 0); void fillRect(int x0, int y0, int x1, int y1, const PIChar & c, PIScreenTypes::Color col_char = PIScreenTypes::Default, PIScreenTypes::Color col_back = PIScreenTypes::Default, PIScreenTypes::CharFlags flags_char = 0); + void fillRect(int x0, int y0, int x1, int y1, PIVector > & content); PIChar artChar(const ArtChar type) const {return arts_.value(type, PIChar(' '));} - + + static void clear(PIVector > & cells); + private: PIVector > & cells; int width, height; diff --git a/src/console/piscreentypes.h b/src/console/piscreentypes.h index 61884df6..69fc1d35 100644 --- a/src/console/piscreentypes.h +++ b/src/console/piscreentypes.h @@ -138,7 +138,12 @@ namespace PIScreenTypes { virtual void tileSetFocusInternal(PIScreenTile * ) {} }; -}; +} + + +inline PIByteArray & operator <<(PIByteArray & s, const PIScreenTypes::Cell & v) {s << v.symbol << v.format.raw_format; return s;} + +inline PIByteArray & operator >>(PIByteArray & s, PIScreenTypes::Cell & v) {s >> v.symbol >> v.format.raw_format; return s;} #endif // PISCREENTYPES_H diff --git a/utils/system_daemon/main.cpp b/utils/system_daemon/main.cpp index 09d86395..3ca293ba 100755 --- a/utils/system_daemon/main.cpp +++ b/utils/system_daemon/main.cpp @@ -255,6 +255,10 @@ public: if (e.key == PIKbdListener::Esc) menuRequest(); //piCout << "key" << e.key; } + EVENT_HANDLER1(void, messageFromApp, const PIByteArray & , m) { + if (m[0] == 'k') PIKbdListener::exiting = true; + + } Daemon & daemon_; PIScreenTile * tmenu, * tinfo, * tfm, * tdaemon, * tpeer, * tpeerdiag; TileList * peers_tl, * addrs_tl, * peermap_tl; @@ -271,10 +275,11 @@ void usage() { piCout << PICoutManipulators::Bold << "PIP System Daemon"; piCout << PICoutManipulators::Cyan << "Version" << PICoutManipulators::Bold << PIPVersion() << PICoutManipulators::NewLine; piCout << PICoutManipulators::Green << PICoutManipulators::Bold << "Usage:" << PICoutManipulators::Default - << "\"pisd [-hdf] [-n ]\"" << PICoutManipulators::NewLine; + << "\"pisd [-hdfk] [-n ]\"" << PICoutManipulators::NewLine; piCout << PICoutManipulators::Green << PICoutManipulators::Bold << "Details:"; piCout << "-h --help " << PICoutManipulators::Green << "- display this message and exit"; piCout << "-d --daemon " << PICoutManipulators::Green << "- start as daemon"; + piCout << "-k --kill " << PICoutManipulators::Green << "- kill daemon"; piCout << "-f --force " << PICoutManipulators::Green << "- don`t check for another running instance"; piCout << "-n --name " << PICoutManipulators::Green << "- set daemon name"; } @@ -286,6 +291,7 @@ int main(int argc, char * argv[]) { cli.addArgument("help"); cli.addArgument("daemon"); cli.addArgument("force"); + cli.addArgument("kill"); cli.addArgument("1"); cli.addArgument("name", true); if (cli.hasArgument("help")) { @@ -294,10 +300,16 @@ int main(int argc, char * argv[]) { } PIString name = cli.argumentValue("name"); PISingleApplication * sapp = 0; - if (cli.hasArgument("1") && !cli.hasArgument("force")) { + if ((cli.hasArgument("1") && !cli.hasArgument("force")) || cli.hasArgument("kill")) { sapp = new PISingleApplication("pisd"); - if (!sapp->isFirst()) { - piCout << "Another pisd is running, exit"; + if (cli.hasArgument("1")) { + if (!sapp->isFirst()) { + piCout << "Another pisd is running, exit"; + return 0; + } + } + if (cli.hasArgument("kill")) { + sapp->sendMessage(PIByteArray("k", 1)); return 0; } } @@ -320,6 +332,7 @@ int main(int argc, char * argv[]) { if (!name.isEmpty()) daemon->changeName(pisd_prefix + name); MainMenu * menu = new MainMenu(*daemon); + if (sapp) CONNECTU(sapp, messageReceived, menu, messageFromApp) screen->start(); screen->waitForFinish(); delete menu;