diff --git a/src/auxiliary/piterminal/main.cpp b/src/auxiliary/piterminal/main.cpp
index 3f50c99f..69150b7d 100644
--- a/src/auxiliary/piterminal/main.cpp
+++ b/src/auxiliary/piterminal/main.cpp
@@ -182,14 +182,12 @@ public:
ir[z].Event.KeyEvent.bKeyDown = false;
}
WriteConsoleInput(cstdin, ir.data(), ir.size_s(), &wrote);
- }
- break;
+ } break;
case mtResize: {
int rw, rh;
msg >> rw >> rh;
resizeConsole(rw, rh);
- }
- break;
+ } break;
default: break;
}
}
diff --git a/src/console/piterminal.cpp b/src/console/piterminal.cpp
new file mode 100644
index 00000000..995aeddd
--- /dev/null
+++ b/src/console/piterminal.cpp
@@ -0,0 +1,367 @@
+/*
+ PIP - Platform Independent Primitives
+ Virtual terminal
+ Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "piterminal.h"
+#ifdef WINDOWS
+# include "pisharedmemory.h"
+# include
+# include
+#else
+#endif
+
+
+//extern PIMutex __PICout_mutex__;
+#define PIPE_BUFFER_SIZE 1024
+
+#ifdef WINDOWS
+enum PITerminalAuxMessageType {
+ mtKey = 1,
+ mtResize,
+ mtScroll
+};
+struct PITerminalAuxData {
+ int cursor_x;
+ int cursor_y;
+ int size_x;
+ int size_y;
+ int cells_size;
+};
+#endif
+
+
+PRIVATE_DEFINITION_START(PITerminal)
+#ifdef WINDOWS
+ PISharedMemory * shm;
+ HANDLE hConBuf;
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+ HANDLE pipe;
+#endif
+PRIVATE_DEFINITION_END(PITerminal)
+
+
+int writePipe(HANDLE pipe, const PIByteArray & ba) {
+ DWORD wrote[2];
+ int sz = ba.size_s();
+ WriteFile(pipe, &sz, 4, &(wrote[0]), 0);
+ WriteFile(pipe, ba.data(), ba.size_s(), &(wrote[1]), 0);
+ //piCout << "send" << ba.size_s();
+ return int(wrote[0] + wrote[1]);
+}
+
+
+PITerminal::PITerminal(): PIThread() {
+ setName("terminal");
+ initPrivate();
+ cursor_visible = false;
+ cursor_x = cursor_y = 0;
+ dsize_x = 80;
+ dsize_y = 24;
+ PRIVATE->shm = 0;
+}
+
+
+PITerminal::~PITerminal() {
+ if (isRunning())
+ stop();
+ PIThread::waitForFinish(10);
+ destroy();
+ if (PRIVATE->shm) delete PRIVATE->shm;
+}
+
+
+void PITerminal::write(const PIByteArray & d) {
+#ifdef WINDOWS
+ PIByteArray msg;
+ PIVector ke;
+ for (int i = 0; i < d.size_s(); ++i)
+ ke << PIKbdListener::KeyEvent(d[i]);
+ msg << int(mtKey) << ke;
+ writePipe(PRIVATE->pipe, msg);
+#endif
+ cursor_tm.reset();
+ cursor_visible = true;
+}
+
+
+void PITerminal::write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m) {
+#ifdef WINDOWS
+ PIByteArray ba;
+ switch (k) {
+ case PIKbdListener::Tab: ba << uchar('\t'); break;
+ case PIKbdListener::Return: ba << uchar('\r') << uchar('\n'); break;
+ case PIKbdListener::Space: ba << uchar(' '); break;
+ default: break;
+ }
+ //piCout << "write" << ba.size();
+ if (!ba.isEmpty()) write(ba);
+ else {
+ PIByteArray msg;
+ PIVector ke;
+ ke << PIKbdListener::KeyEvent(k, m);
+ msg << int(mtKey) << ke;
+ writePipe(PRIVATE->pipe, msg);
+ }
+#endif
+ cursor_tm.reset();
+ cursor_visible = true;
+}
+
+
+PIVector > PITerminal::content() {
+ readConsole();
+ return cells;
+}
+
+
+bool PITerminal::isSpecialKey(int k) {
+ switch (k) {
+ case PIKbdListener::Tab:
+ case PIKbdListener::Return:
+ case PIKbdListener::Esc:
+ case PIKbdListener::Space:
+ case PIKbdListener::Backspace:
+ case PIKbdListener::UpArrow:
+ case PIKbdListener::DownArrow:
+ case PIKbdListener::RightArrow:
+ case PIKbdListener::LeftArrow:
+ case PIKbdListener::Home:
+ case PIKbdListener::End:
+ case PIKbdListener::PageUp:
+ case PIKbdListener::PageDown:
+ case PIKbdListener::Insert:
+ case PIKbdListener::Delete:
+ case PIKbdListener::F1:
+ case PIKbdListener::F2:
+ case PIKbdListener::F3:
+ case PIKbdListener::F4:
+ case PIKbdListener::F5:
+ case PIKbdListener::F6:
+ case PIKbdListener::F7:
+ case PIKbdListener::F8:
+ case PIKbdListener::F9:
+ case PIKbdListener::F10:
+ case PIKbdListener::F11:
+ case PIKbdListener::F12: return true;
+ default: return false;
+ }
+ return false;
+}
+
+
+void PITerminal::initPrivate() {
+#ifdef WINDOWS
+ PRIVATE->hConBuf = INVALID_HANDLE_VALUE;
+ PRIVATE->pipe = INVALID_HANDLE_VALUE;
+ PRIVATE->pi.hProcess = 0;
+#endif
+ size_x = size_y = 0;
+}
+
+
+void PITerminal::readConsole() {
+#ifdef WINDOWS
+ if (!PRIVATE->shm) return;
+ PITerminalAuxData data;
+ PRIVATE->shm->read(&data, sizeof(data));
+ if (data.cells_size <= 4) return;
+ cursor_x = data.cursor_x;
+ cursor_y = data.cursor_y;
+ size_x = data.size_x;
+ size_y = data.size_y;
+ PIByteArray ba;
+ ba.resize(data.cells_size);
+ PRIVATE->shm->read(ba.data(), ba.size_s(), sizeof(data));
+ 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);
+}
+
+
+void PITerminal::getCursor(int & x, int & y) {
+#ifdef WINDOWS
+ if (!PRIVATE->shm) return;
+ int sz = 0;
+ PRIVATE->shm->read(&sz, 4);
+#endif
+}
+
+
+uchar PITerminal::invertColor(uchar c) {
+ switch ((PIScreenTypes::Color)c) {
+ case PIScreenTypes::Black: return PIScreenTypes::White;
+ case PIScreenTypes::Red: return PIScreenTypes::Cyan;
+ case PIScreenTypes::Green: return PIScreenTypes::Magenta;
+ case PIScreenTypes::Blue: return PIScreenTypes::Yellow;
+ case PIScreenTypes::Cyan: return PIScreenTypes::Red;
+ case PIScreenTypes::Magenta: return PIScreenTypes::Green;
+ case PIScreenTypes::Yellow: return PIScreenTypes::Blue;
+ case PIScreenTypes::White: return PIScreenTypes::Black;
+ default: break;
+ }
+ return PIScreenTypes::White;
+}
+
+
+void PITerminal::run() {
+ if (cursor_tm.elapsed_m() >= 500) {
+ cursor_tm.reset();
+ cursor_visible = !cursor_visible;
+ if (cursor_visible) {
+ getCursor(cursor_x, cursor_y);
+ }
+ }
+}
+
+
+bool PITerminal::initialize() {
+ destroy();
+#ifdef WINDOWS
+ /*SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = true;
+ sa.lpSecurityDescriptor = 0;
+ if (!CreatePipe(&(PRIVATE->pipe_in[0]), &(PRIVATE->pipe_in[1]), &sa, 0)) {
+ piCoutObj << "CreatePipe error," << errorString();
+ initPrivate();
+ return false;
+ }
+ PRIVATE->hConBuf = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0, &sa, CONSOLE_TEXTMODE_BUFFER, 0);
+ if (PRIVATE->hConBuf == INVALID_HANDLE_VALUE) {
+ piCoutObj << "CreateConsoleScreenBuffer error," << errorString();
+ destroy();
+ return false;
+ }*/
+ //CreatePipe(&(PRIVATE->pipe_out[0]), &(PRIVATE->pipe_out[1]), &sa, 0);
+ //SetHandleInformation(PRIVATE->pipe_in[1], HANDLE_FLAG_INHERIT, 0);
+ //SetHandleInformation(PRIVATE->hConBuf, HANDLE_FLAG_INHERIT, 0);
+ //GetStartupInfoA(&PRIVATE->si);
+ memset(&PRIVATE->si, 0, sizeof(PRIVATE->si));
+ PRIVATE->si.cb = sizeof(STARTUPINFO);
+ //PRIVATE->si.dwFlags |= STARTF_USESTDHANDLES;
+ PRIVATE->si.dwFlags |= STARTF_USESHOWWINDOW;
+ PRIVATE->si.dwFlags |= STARTF_USECOUNTCHARS;
+ //PRIVATE->si.hStdInput = PRIVATE->pipe;
+ //PRIVATE->si.hStdOutput = PRIVATE->hConBuf;
+ //PRIVATE->si.hStdError = PRIVATE->hConBuf;
+ PRIVATE->si.wShowWindow = SW_HIDE;
+ PRIVATE->si.dwXCountChars = 80;
+ PRIVATE->si.dwYCountChars = 24;
+
+ memset(&PRIVATE->pi, 0, sizeof(PRIVATE->pi));
+
+ PIString shmh = PIString::fromNumber(rand() % 10000);
+ PIString pname = "\\\\.\\pipe\\piterm" + shmh;
+ PIString cmd = "piterminal \"" + shmh + "\" \"" + pname + "\"";
+ if(!CreateProcessA(0, (LPSTR)cmd.dataAscii(), 0, 0, false, CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, 0, 0, &PRIVATE->si, &PRIVATE->pi)) {
+ piCoutObj << "CreateProcess error," << errorString();
+ destroy();
+ return false;
+ }
+ PRIVATE->pipe = CreateNamedPipe((LPSTR)pname.dataAscii(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 1000, NULL);
+ if (PRIVATE->pipe == INVALID_HANDLE_VALUE) {
+ piCoutObj << "CreateNamedPipe error," << errorString();
+ destroy();
+ return false;
+ }
+ PITimeMeasurer tm;
+ bool ok = false;
+ while (tm.elapsed_m() < 1000) {
+ if (ConnectNamedPipe(PRIVATE->pipe, 0) == TRUE) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) {
+ piCoutObj << "ConnectNamedPipe error," << errorString();
+ destroy();
+ return false;
+ }
+ 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);
+
+ /*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();
+ return false;
+ }*/
+#endif
+ cursor_visible = false;
+ cursor_tm.reset();
+ start(40);
+ return true;
+}
+
+
+void PITerminal::destroy() {
+ //piCout << "destroy ...";
+ stop();
+ waitForFinish(1000);
+#ifdef WINDOWS
+ if (PRIVATE->pi.hProcess) {
+ piCout << "term";
+ //TerminateProcess(PRIVATE->pi.hProcess, 0);
+ GenerateConsoleCtrlEvent(CTRL_C_EVENT, PRIVATE->pi.dwProcessId);
+ CloseHandle(PRIVATE->pi.hProcess);
+ }
+ if (PRIVATE->pipe != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->pipe);
+ if (PRIVATE->hConBuf != INVALID_HANDLE_VALUE) CloseHandle(PRIVATE->hConBuf);
+ //piCout << "destroy" << size_y;
+#endif
+ initPrivate();
+}
+
+
+bool PITerminal::resize(int cols, int rows) {
+ bool ret = true;
+ dsize_x = cols;
+ dsize_y = rows;
+#ifdef WINDOWS
+ if (PRIVATE->pipe == INVALID_HANDLE_VALUE) return false;
+ PIByteArray msg;
+ msg << int(mtResize) << dsize_x << dsize_y;
+ writePipe(PRIVATE->pipe, msg);
+#endif
+ cells.resize(size_y);
+ for (int i = 0; i < size_y; ++i)
+ cells[i].resize(size_x);
+ return ret;
+}
diff --git a/src/console/piterminal.h b/src/console/piterminal.h
new file mode 100644
index 00000000..fdadbed3
--- /dev/null
+++ b/src/console/piterminal.h
@@ -0,0 +1,69 @@
+/*! \file piterminal.h
+ * \brief Virtual terminal
+*/
+/*
+ PIP - Platform Independent Primitives
+ Virtual terminal
+ Copyright (C) 2016 Ivan Pelipenko peri4ko@yandex.ru
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifndef PITERMINAL_H
+#define PITERMINAL_H
+
+#include "pithread.h"
+#include "pikbdlistener.h"
+#include "piscreentypes.h"
+
+
+class PIP_EXPORT PITerminal: public PIThread
+{
+ PIOBJECT_SUBCLASS(PITerminal, PIThread)
+public:
+
+ //! Constructs %PITerminal
+ PITerminal();
+
+ ~PITerminal();
+
+ int columns() const {return size_x;}
+ int rows() const {return size_y;}
+ bool resize(int cols, int rows);
+
+ void write(const PIByteArray & d);
+ void write(PIKbdListener::SpecialKey k, PIKbdListener::KeyModifiers m);
+ PIVector > content();
+ static bool isSpecialKey(int k);
+
+ bool initialize();
+ void destroy();
+private:
+ void initPrivate();
+ void readConsole();
+ void getCursor(int & x, int & y);
+ uchar invertColor(uchar c);
+ void run();
+
+ PRIVATE_DECLARATION
+ int dsize_x, dsize_y;
+ int size_x, size_y, cursor_x, cursor_y;
+ bool cursor_visible;
+ PITimeMeasurer cursor_tm;
+ PIVector > cells;
+
+};
+
+
+#endif // PITERMINAL_H