git-svn-id: svn://db.shs.com.ru/pip@248 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5

This commit is contained in:
2016-09-01 13:10:49 +00:00
parent e4d76ac5a7
commit bae0456042
3 changed files with 438 additions and 4 deletions

View File

@@ -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;
}
}

367
src/console/piterminal.cpp Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#include "piterminal.h"
#ifdef WINDOWS
# include "pisharedmemory.h"
# include <wincon.h>
# include <winuser.h>
#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<PIKbdListener::KeyEvent> 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<PIKbdListener::KeyEvent> ke;
ke << PIKbdListener::KeyEvent(k, m);
msg << int(mtKey) << ke;
writePipe(PRIVATE->pipe, msg);
}
#endif
cursor_tm.reset();
cursor_visible = true;
}
PIVector<PIVector<PIScreenTypes::Cell> > 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;
}

69
src/console/piterminal.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
#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<PIVector<PIScreenTypes::Cell> > 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<PIVector<PIScreenTypes::Cell> > cells;
};
#endif // PITERMINAL_H