234 lines
6.6 KiB
C#
234 lines
6.6 KiB
C#
///
|
|
/// Copyright (c) 2017 Sensus Metering Systems
|
|
///
|
|
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace TBF.BenchControl.Network.Telnet
|
|
{
|
|
/// <summary>
|
|
/// Virtual terminal (an array of characters).
|
|
/// This class is thread safe under these circumstances:
|
|
/// - ClearScreen() and WriteVt() methods called from one thread only
|
|
/// - properties Text, etc. can be safely read from an arbitrary thread
|
|
/// </summary>
|
|
public class VirtualTerminal
|
|
{
|
|
const uint DefaultVtRowsCount = 80; /// Default VT height (number of rows)
|
|
const uint DefaultVtColumnsCount = 132; /// Default VT width (number of columns)
|
|
|
|
/// <summary>
|
|
/// Virtual terminal special characters.
|
|
/// <seealso cref = http://support.microsoft.com/kb/231866 />
|
|
/// </summary>
|
|
enum SpecialChar
|
|
{
|
|
BS = 8, /// 8 = Backspace (move one position to the left)
|
|
HT, /// 9 = Horizontal tab
|
|
LF, /// 10 = Line feed
|
|
VT, /// 11 = Vertical tab
|
|
FF, /// 12 = Form feed (on visual displays most commonly clears the screen)
|
|
CR /// 13 = Carriage return
|
|
}
|
|
|
|
|
|
///
|
|
/// Public properties
|
|
///
|
|
public uint Rows { get { return vtRows; } }
|
|
public uint Columns { get { return vtColumns; } }
|
|
public uint CurRow { get { return curRow; } }
|
|
public uint CurColumn { get { return curColumn; } }
|
|
|
|
/// <summary>
|
|
/// Virtual terminal text buffer as a single string. To be printed out using monospaced font.
|
|
/// </summary>
|
|
public string Text
|
|
{
|
|
get
|
|
{
|
|
string result = "";
|
|
char[] oneRow = new char[vtColumns];
|
|
|
|
for (int row = 0; row < vtRows; row++)
|
|
{
|
|
for (int column = 0; column < vtColumns; column++)
|
|
{
|
|
oneRow[column] = vt[row, column];
|
|
}
|
|
result += new String(oneRow);
|
|
|
|
/// New line at the end of each line except of the last one
|
|
if (row < vtRows - 1) result += System.Environment.NewLine;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
///
|
|
/// Private fields
|
|
///
|
|
char[,] vt; /// Virtual terminal text buffer
|
|
uint vtRows = 0; /// VT height (number of rows)
|
|
uint vtColumns = 0; /// VT width (number of columns)
|
|
uint curRow = 0; /// Current row (cursor position)
|
|
uint curColumn = 0; /// Current column (cursor position)
|
|
|
|
|
|
/// <summary>
|
|
/// Default constructor.
|
|
/// </summary>
|
|
public VirtualTerminal()
|
|
{
|
|
vt = new char[DefaultVtRowsCount, DefaultVtColumnsCount];
|
|
if (vt != null)
|
|
{
|
|
vtRows = DefaultVtRowsCount;
|
|
vtColumns = DefaultVtColumnsCount;
|
|
ClearScreen();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Arbitrary VT size constructor.
|
|
/// </summary>
|
|
public VirtualTerminal(uint nrRows, uint nrColumns)
|
|
{
|
|
vt = new char[nrRows, nrColumns];
|
|
if (vt != null)
|
|
{
|
|
vtRows = nrRows;
|
|
vtColumns = nrColumns;
|
|
ClearScreen();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear VT.
|
|
/// </summary>
|
|
public void ClearScreen()
|
|
{
|
|
for (uint row = 0; row < vtRows; row++)
|
|
{
|
|
for (uint column = 0; column < vtColumns; column++)
|
|
{
|
|
vt[row, column] = ' ';
|
|
}
|
|
}
|
|
curRow = 0;
|
|
curColumn = 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scroll VT one line up and clear the bottom line.
|
|
/// </summary>
|
|
void ScrollUp()
|
|
{
|
|
for (uint row = 0; row < vtRows - 1; row++)
|
|
{
|
|
for (uint column = 0; column < vtColumns; column++)
|
|
{
|
|
vt[row, column] = vt[row + 1, column];
|
|
}
|
|
}
|
|
for (uint column = 0; column < vtColumns; column++)
|
|
{
|
|
vt[vtRows - 1, column] = ' ';
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write one regular printable character to VC.
|
|
/// </summary>
|
|
void WritePrintableChar(char c)
|
|
{
|
|
vt[curRow, curColumn] = c;
|
|
if (curColumn < vtColumns - 1)
|
|
{
|
|
curColumn++;
|
|
}
|
|
else if (curRow < vtRows - 1)
|
|
{
|
|
curRow++;
|
|
curColumn = 0;
|
|
}
|
|
else
|
|
{
|
|
ScrollUp();
|
|
curRow = vtRows - 1;
|
|
curColumn = 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write one character to VT (regular or special).
|
|
/// </summary>
|
|
public void WriteVt(char c)
|
|
{
|
|
if (c >= 32 && c <= 127)
|
|
{
|
|
WritePrintableChar(c);
|
|
}
|
|
else
|
|
{
|
|
switch ((SpecialChar)c)
|
|
{
|
|
/// Carriage return
|
|
case SpecialChar.CR:
|
|
curColumn = 0;
|
|
break;
|
|
|
|
/// Line feed
|
|
case SpecialChar.LF:
|
|
if (curRow < vtRows - 1)
|
|
{
|
|
curRow++;
|
|
}
|
|
else
|
|
{
|
|
ScrollUp();
|
|
curRow = vtRows - 1;
|
|
}
|
|
break;
|
|
|
|
/// Form feed (= clear screen)
|
|
case SpecialChar.FF:
|
|
ClearScreen();
|
|
break;
|
|
|
|
/// Backspace
|
|
case SpecialChar.BS:
|
|
if (curColumn > 0)
|
|
{
|
|
vt[curRow, --curColumn] = ' ';
|
|
}
|
|
else if (curRow > 0)
|
|
{
|
|
curColumn = vtColumns - 1;
|
|
vt[--curRow, curColumn] = ' ';
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write a string to VT.
|
|
/// </summary>
|
|
public void WriteVt(string txt)
|
|
{
|
|
if (txt != null)
|
|
{
|
|
for (int i = 0; i < txt.Length; i++)
|
|
{
|
|
WriteVt(txt[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|