tbf/TestBenchFramework/BenchControl/Network/Telnet/VirtualTerminal.cs

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 : IVirtualTerminal
{
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]);
}
}
}
}
}