git-svn-id: svn://db.shs.com.ru/pip@248 12ceb7fc-bf1f-11e4-8940-5bc7170c53b5
This commit is contained in:
@@ -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
367
src/console/piterminal.cpp
Normal 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
69
src/console/piterminal.h
Normal 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
|
||||
Reference in New Issue
Block a user