a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
1465 lines
35 KiB
C#
1465 lines
35 KiB
C#
//
|
|
// System.ConsoleDriver
|
|
//
|
|
// Authors:
|
|
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
|
|
//
|
|
// (C) 2005,2006 Novell, Inc (http://www.novell.com)
|
|
//
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
#if !NET_2_1
|
|
|
|
//
|
|
// Defining this writes the output to console.log
|
|
//#define DEBUG
|
|
|
|
using System.Collections;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Runtime.InteropServices;
|
|
namespace System {
|
|
class TermInfoDriver : IConsoleDriver {
|
|
|
|
// This points to a variable that is updated by unmanage code on window size changes.
|
|
unsafe static int *native_terminal_size;
|
|
|
|
// The current size that we believe we have
|
|
static int terminal_size;
|
|
|
|
//static uint flag = 0xdeadbeef;
|
|
readonly static string [] locations = { "/etc/terminfo", "/usr/share/terminfo", "/usr/lib/terminfo" };
|
|
|
|
TermInfoReader reader;
|
|
int cursorLeft;
|
|
int cursorTop;
|
|
string title = String.Empty;
|
|
string titleFormat = String.Empty;
|
|
bool cursorVisible = true;
|
|
string csrVisible;
|
|
string csrInvisible;
|
|
string clear;
|
|
string bell;
|
|
string term;
|
|
StreamReader stdin;
|
|
CStreamWriter stdout;
|
|
|
|
int windowWidth;
|
|
int windowHeight;
|
|
//int windowTop;
|
|
//int windowLeft;
|
|
int bufferHeight;
|
|
int bufferWidth;
|
|
|
|
char [] buffer;
|
|
int readpos;
|
|
int writepos;
|
|
string keypadXmit, keypadLocal;
|
|
bool controlCAsInput;
|
|
bool inited;
|
|
object initLock = new object ();
|
|
bool initKeys;
|
|
string origPair;
|
|
string origColors;
|
|
string cursorAddress;
|
|
ConsoleColor fgcolor = ConsoleColor.White;
|
|
ConsoleColor bgcolor = ConsoleColor.Black;
|
|
bool color16 = false; // terminal supports 16 colors
|
|
string setlfgcolor;
|
|
string setlbgcolor;
|
|
string setfgcolor;
|
|
string setbgcolor;
|
|
bool noGetPosition;
|
|
Hashtable keymap;
|
|
ByteMatcher rootmap;
|
|
bool home_1_1; // if true, we have to add 1 to x and y when using cursorAddress
|
|
int rl_startx = -1, rl_starty = -1;
|
|
byte [] control_characters; // Indexed by ControlCharacters.XXXXXX
|
|
#if DEBUG
|
|
StreamWriter logger;
|
|
#endif
|
|
|
|
static string SearchTerminfo (string term)
|
|
{
|
|
if (term == null || term == String.Empty)
|
|
return null;
|
|
|
|
// Ignore TERMINFO and TERMINFO_DIRS by now
|
|
//string terminfo = Environment.GetEnvironmentVariable ("TERMINFO");
|
|
//string terminfoDirs = Environment.GetEnvironmentVariable ("TERMINFO_DIRS");
|
|
|
|
foreach (string dir in locations) {
|
|
if (!Directory.Exists (dir))
|
|
continue;
|
|
|
|
string path = Path.Combine (dir, term.Substring (0, 1));
|
|
if (!Directory.Exists (dir))
|
|
continue;
|
|
|
|
path = Path.Combine (path, term);
|
|
if (!File.Exists (path))
|
|
continue;
|
|
|
|
return path;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
void WriteConsole (string str)
|
|
{
|
|
if (str == null)
|
|
return;
|
|
|
|
stdout.InternalWriteString (str);
|
|
}
|
|
|
|
public TermInfoDriver ()
|
|
: this (Environment.GetEnvironmentVariable ("TERM"))
|
|
{
|
|
}
|
|
|
|
public TermInfoDriver (string term)
|
|
{
|
|
#if DEBUG
|
|
File.Delete ("console.log");
|
|
logger = new StreamWriter (File.OpenWrite ("console.log"));
|
|
#endif
|
|
this.term = term;
|
|
|
|
if (term == "xterm") {
|
|
reader = new TermInfoReader (term, KnownTerminals.xterm);
|
|
color16 = true;
|
|
} else if (term == "linux") {
|
|
reader = new TermInfoReader (term, KnownTerminals.linux);
|
|
color16 = true;
|
|
} else {
|
|
string filename = SearchTerminfo (term);
|
|
if (filename != null)
|
|
reader = new TermInfoReader (term, filename);
|
|
}
|
|
|
|
if (reader == null)
|
|
reader = new TermInfoReader (term, KnownTerminals.ansi);
|
|
|
|
if (!(Console.stdout is CStreamWriter)) {
|
|
// Application set its own stdout, we need a reference to the real stdout
|
|
stdout = new CStreamWriter (Console.OpenStandardOutput (0), Console.OutputEncoding);
|
|
((StreamWriter) stdout).AutoFlush = true;
|
|
} else {
|
|
stdout = (CStreamWriter) Console.stdout;
|
|
}
|
|
}
|
|
|
|
public bool Initialized {
|
|
get { return inited; }
|
|
}
|
|
|
|
public void Init ()
|
|
{
|
|
if (inited)
|
|
return;
|
|
|
|
lock (initLock){
|
|
if (inited)
|
|
return;
|
|
inited = true;
|
|
|
|
/* This should not happen any more, since it is checked for in Console */
|
|
if (!ConsoleDriver.IsConsole)
|
|
throw new IOException ("Not a tty.");
|
|
|
|
ConsoleDriver.SetEcho (false);
|
|
|
|
string endString = null;
|
|
keypadXmit = reader.Get (TermInfoStrings.KeypadXmit);
|
|
keypadLocal = reader.Get (TermInfoStrings.KeypadLocal);
|
|
if (keypadXmit != null) {
|
|
WriteConsole (keypadXmit); // Needed to get the arrows working
|
|
if (keypadLocal != null)
|
|
endString += keypadLocal;
|
|
}
|
|
|
|
origPair = reader.Get (TermInfoStrings.OrigPair);
|
|
origColors = reader.Get (TermInfoStrings.OrigColors);
|
|
setfgcolor = MangleParameters (reader.Get (TermInfoStrings.SetAForeground));
|
|
setbgcolor = MangleParameters (reader.Get (TermInfoStrings.SetABackground));
|
|
// lighter fg colours are 90 -> 97 rather than 30 -> 37
|
|
setlfgcolor = color16 ? setfgcolor.Replace ("[3", "[9") : setfgcolor;
|
|
// lighter bg colours are 100 -> 107 rather than 40 -> 47
|
|
setlbgcolor = color16 ? setbgcolor.Replace ("[4", "[10") : setbgcolor;
|
|
string resetColors = (origColors == null) ? origPair : origColors;
|
|
if (resetColors != null)
|
|
endString += resetColors;
|
|
|
|
unsafe {
|
|
if (!ConsoleDriver.TtySetup (keypadXmit, endString, out control_characters, out native_terminal_size)){
|
|
control_characters = new byte [17];
|
|
native_terminal_size = null;
|
|
//throw new IOException ("Error initializing terminal.");
|
|
}
|
|
}
|
|
|
|
stdin = new StreamReader (Console.OpenStandardInput (0), Console.InputEncoding);
|
|
clear = reader.Get (TermInfoStrings.ClearScreen);
|
|
bell = reader.Get (TermInfoStrings.Bell);
|
|
if (clear == null) {
|
|
clear = reader.Get (TermInfoStrings.CursorHome);
|
|
clear += reader.Get (TermInfoStrings.ClrEos);
|
|
}
|
|
|
|
csrVisible = reader.Get (TermInfoStrings.CursorNormal);
|
|
if (csrVisible == null)
|
|
csrVisible = reader.Get (TermInfoStrings.CursorVisible);
|
|
|
|
csrInvisible = reader.Get (TermInfoStrings.CursorInvisible);
|
|
if (term == "cygwin" || term == "linux" || (term != null && term.StartsWith ("xterm")) ||
|
|
term == "rxvt" || term == "dtterm") {
|
|
titleFormat = "\x1b]0;{0}\x7"; // icon + window title
|
|
} else if (term == "iris-ansi") {
|
|
titleFormat = "\x1bP1.y{0}\x1b\\"; // not tested
|
|
} else if (term == "sun-cmd") {
|
|
titleFormat = "\x1b]l{0}\x1b\\"; // not tested
|
|
}
|
|
|
|
cursorAddress = reader.Get (TermInfoStrings.CursorAddress);
|
|
if (cursorAddress != null) {
|
|
string result = cursorAddress.Replace ("%i", String.Empty);
|
|
home_1_1 = (cursorAddress != result);
|
|
cursorAddress = MangleParameters (result);
|
|
}
|
|
|
|
GetCursorPosition ();
|
|
#if DEBUG
|
|
logger.WriteLine ("noGetPosition: {0} left: {1} top: {2}", noGetPosition, cursorLeft, cursorTop);
|
|
logger.Flush ();
|
|
#endif
|
|
if (noGetPosition) {
|
|
WriteConsole (clear);
|
|
cursorLeft = 0;
|
|
cursorTop = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static string MangleParameters (string str)
|
|
{
|
|
if (str == null)
|
|
return null;
|
|
|
|
str = str.Replace ("{", "{{");
|
|
str = str.Replace ("}", "}}");
|
|
str = str.Replace ("%p1%d", "{0}");
|
|
return str.Replace ("%p2%d", "{1}");
|
|
}
|
|
|
|
static int TranslateColor (ConsoleColor desired, out bool light)
|
|
{
|
|
switch (desired) {
|
|
// Dark colours
|
|
case ConsoleColor.Black:
|
|
light = false;
|
|
return 0;
|
|
case ConsoleColor.DarkRed:
|
|
light = false;
|
|
return 1;
|
|
case ConsoleColor.DarkGreen:
|
|
light = false;
|
|
return 2;
|
|
case ConsoleColor.DarkYellow:
|
|
light = false;
|
|
return 3;
|
|
case ConsoleColor.DarkBlue:
|
|
light = false;
|
|
return 4;
|
|
case ConsoleColor.DarkMagenta:
|
|
light = false;
|
|
return 5;
|
|
case ConsoleColor.DarkCyan:
|
|
light = false;
|
|
return 6;
|
|
case ConsoleColor.Gray:
|
|
light = false;
|
|
return 7;
|
|
// Light colours
|
|
case ConsoleColor.DarkGray:
|
|
light = true;
|
|
return 0;
|
|
case ConsoleColor.Red:
|
|
light = true;
|
|
return 1;
|
|
case ConsoleColor.Green:
|
|
light = true;
|
|
return 2;
|
|
case ConsoleColor.Yellow:
|
|
light = true;
|
|
return 3;
|
|
case ConsoleColor.Blue:
|
|
light = true;
|
|
return 4;
|
|
case ConsoleColor.Magenta:
|
|
light = true;
|
|
return 5;
|
|
case ConsoleColor.Cyan:
|
|
light = true;
|
|
return 6;
|
|
case ConsoleColor.White:
|
|
light = true;
|
|
return 7;
|
|
}
|
|
|
|
light = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void IncrementX ()
|
|
{
|
|
cursorLeft++;
|
|
if (cursorLeft >= WindowWidth) {
|
|
cursorTop++;
|
|
cursorLeft = 0;
|
|
if (cursorTop >= WindowHeight) {
|
|
// Writing beyond the initial screen
|
|
if (rl_starty != -1) rl_starty--;
|
|
cursorTop--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Should never get called unless inited
|
|
public void WriteSpecialKey (ConsoleKeyInfo key)
|
|
{
|
|
switch (key.Key) {
|
|
case ConsoleKey.Backspace:
|
|
if (cursorLeft > 0) {
|
|
if (cursorLeft <= rl_startx && cursorTop == rl_starty)
|
|
break;
|
|
cursorLeft--;
|
|
SetCursorPosition (cursorLeft, cursorTop);
|
|
WriteConsole (" ");
|
|
SetCursorPosition (cursorLeft, cursorTop);
|
|
}
|
|
#if DEBUG
|
|
logger.WriteLine ("BS left: {0} top: {1}", cursorLeft, cursorTop);
|
|
logger.Flush ();
|
|
#endif
|
|
break;
|
|
case ConsoleKey.Tab:
|
|
int n = 8 - (cursorLeft % 8);
|
|
for (int i = 0; i < n; i++){
|
|
IncrementX ();
|
|
}
|
|
WriteConsole ("\t");
|
|
break;
|
|
case ConsoleKey.Clear:
|
|
WriteConsole (clear);
|
|
cursorLeft = 0;
|
|
cursorTop = 0;
|
|
break;
|
|
case ConsoleKey.Enter:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#if DEBUG
|
|
logger.WriteLine ("left: {0} top: {1}", cursorLeft, cursorTop);
|
|
logger.Flush ();
|
|
#endif
|
|
}
|
|
|
|
// Should never get called unless inited
|
|
public void WriteSpecialKey (char c)
|
|
{
|
|
WriteSpecialKey (CreateKeyInfoFromInt (c, false));
|
|
}
|
|
|
|
public bool IsSpecialKey (ConsoleKeyInfo key)
|
|
{
|
|
if (!inited)
|
|
return false;
|
|
|
|
switch (key.Key) {
|
|
case ConsoleKey.Backspace:
|
|
return true;
|
|
case ConsoleKey.Tab:
|
|
return true;
|
|
case ConsoleKey.Clear:
|
|
return true;
|
|
case ConsoleKey.Enter:
|
|
cursorLeft = 0;
|
|
cursorTop++;
|
|
if (cursorTop >= WindowHeight) {
|
|
cursorTop--;
|
|
//TODO: scroll up
|
|
}
|
|
return false;
|
|
default:
|
|
// CStreamWriter will handle writing this key
|
|
IncrementX ();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public bool IsSpecialKey (char c)
|
|
{
|
|
return IsSpecialKey (CreateKeyInfoFromInt (c, false));
|
|
}
|
|
|
|
public ConsoleColor BackgroundColor {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return bgcolor;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
bgcolor = value;
|
|
|
|
bool light;
|
|
int colour = TranslateColor (value, out light);
|
|
|
|
if (light)
|
|
WriteConsole (String.Format (setlbgcolor, colour));
|
|
else
|
|
WriteConsole (String.Format (setbgcolor, colour));
|
|
}
|
|
}
|
|
|
|
public ConsoleColor ForegroundColor {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return fgcolor;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
fgcolor = value;
|
|
|
|
bool light;
|
|
int colour = TranslateColor (value, out light);
|
|
|
|
if (light)
|
|
WriteConsole (String.Format (setlfgcolor, colour));
|
|
else
|
|
WriteConsole (String.Format (setfgcolor, colour));
|
|
}
|
|
}
|
|
|
|
void GetCursorPosition ()
|
|
{
|
|
int row = 0, col = 0;
|
|
int b;
|
|
|
|
// First, get any data in the input buffer. Merely reduces the likelyhood of getting an error
|
|
int inqueue = ConsoleDriver.InternalKeyAvailable (0);
|
|
while (inqueue-- > 0){
|
|
b = stdin.Read ();
|
|
AddToBuffer (b);
|
|
}
|
|
|
|
// Then try to probe for the cursor coordinates
|
|
WriteConsole ("\x1b[6n");
|
|
if (ConsoleDriver.InternalKeyAvailable (1000) <= 0) {
|
|
noGetPosition = true;
|
|
return;
|
|
}
|
|
|
|
b = stdin.Read ();
|
|
while (b != '\x1b') {
|
|
AddToBuffer (b);
|
|
if (ConsoleDriver.InternalKeyAvailable (100) <= 0)
|
|
return;
|
|
b = stdin.Read ();
|
|
}
|
|
|
|
b = stdin.Read ();
|
|
if (b != '[') {
|
|
AddToBuffer ('\x1b');
|
|
AddToBuffer (b);
|
|
return;
|
|
}
|
|
|
|
b = stdin.Read ();
|
|
if (b != ';') {
|
|
row = b - '0';
|
|
b = stdin.Read ();
|
|
while ((b >= '0') && (b <= '9')) {
|
|
row = row * 10 + b - '0';
|
|
b = stdin.Read ();
|
|
}
|
|
// Row/col is 0 based
|
|
row --;
|
|
}
|
|
|
|
b = stdin.Read ();
|
|
if (b != 'R') {
|
|
col = b - '0';
|
|
b = stdin.Read ();
|
|
while ((b >= '0') && (b <= '9')) {
|
|
col = col * 10 + b - '0';
|
|
b = stdin.Read ();
|
|
}
|
|
// Row/col is 0 based
|
|
col --;
|
|
}
|
|
|
|
#if DEBUG
|
|
logger.WriteLine ("GetCursorPosition: {0}, {1}", col, row);
|
|
logger.Flush ();
|
|
#endif
|
|
|
|
cursorLeft = col;
|
|
cursorTop = row;
|
|
}
|
|
|
|
public int BufferHeight {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
CheckWindowDimensions ();
|
|
return bufferHeight;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public int BufferWidth {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
CheckWindowDimensions ();
|
|
return bufferWidth;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public bool CapsLock {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public int CursorLeft {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return cursorLeft;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
SetCursorPosition (value, CursorTop);
|
|
}
|
|
}
|
|
|
|
public int CursorTop {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return cursorTop;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
SetCursorPosition (CursorLeft, value);
|
|
}
|
|
}
|
|
|
|
public bool CursorVisible {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return cursorVisible;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
cursorVisible = value;
|
|
WriteConsole ((value ? csrVisible : csrInvisible));
|
|
}
|
|
}
|
|
|
|
// we have CursorNormal vs. CursorVisible...
|
|
[MonoTODO]
|
|
public int CursorSize {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
return 1;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public bool KeyAvailable {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return (writepos > readpos || ConsoleDriver.InternalKeyAvailable (0) > 0);
|
|
}
|
|
}
|
|
|
|
// We don't know these next 2 values, so return something reasonable
|
|
public int LargestWindowHeight {
|
|
get { return WindowHeight; }
|
|
}
|
|
|
|
public int LargestWindowWidth {
|
|
get { return WindowWidth; }
|
|
}
|
|
|
|
public bool NumberLock {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public string Title {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
return title;
|
|
}
|
|
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
title = value;
|
|
WriteConsole (String.Format (titleFormat, value));
|
|
}
|
|
}
|
|
|
|
public bool TreatControlCAsInput {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
return controlCAsInput;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
if (controlCAsInput == value)
|
|
return;
|
|
|
|
ConsoleDriver.SetBreak (value);
|
|
controlCAsInput = value;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Requries that caller calls Init () if not !inited.
|
|
//
|
|
unsafe void CheckWindowDimensions ()
|
|
{
|
|
if (native_terminal_size == null || terminal_size == *native_terminal_size)
|
|
return;
|
|
|
|
if (*native_terminal_size == -1){
|
|
int c = reader.Get (TermInfoNumbers.Columns);
|
|
if (c != 0)
|
|
windowWidth = c;
|
|
|
|
c = reader.Get (TermInfoNumbers.Lines);
|
|
if (c != 0)
|
|
windowHeight = c;
|
|
} else {
|
|
terminal_size = *native_terminal_size;
|
|
windowWidth = terminal_size >> 16;
|
|
windowHeight = terminal_size & 0xffff;
|
|
}
|
|
bufferHeight = windowHeight;
|
|
bufferWidth = windowWidth;
|
|
}
|
|
|
|
|
|
public int WindowHeight {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
CheckWindowDimensions ();
|
|
return windowHeight;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public int WindowLeft {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
//CheckWindowDimensions ();
|
|
return 0;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public int WindowTop {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
//CheckWindowDimensions ();
|
|
return 0;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public int WindowWidth {
|
|
get {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
CheckWindowDimensions ();
|
|
return windowWidth;
|
|
}
|
|
set {
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotSupportedException ();
|
|
}
|
|
}
|
|
|
|
public void Clear ()
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
WriteConsole (clear);
|
|
cursorLeft = 0;
|
|
cursorTop = 0;
|
|
}
|
|
|
|
public void Beep (int frequency, int duration)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
WriteConsole (bell);
|
|
}
|
|
|
|
public void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight,
|
|
int targetLeft, int targetTop, Char sourceChar,
|
|
ConsoleColor sourceForeColor, ConsoleColor sourceBackColor)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotImplementedException ();
|
|
}
|
|
|
|
void AddToBuffer (int b)
|
|
{
|
|
if (buffer == null) {
|
|
buffer = new char [1024];
|
|
} else if (writepos >= buffer.Length) {
|
|
char [] newbuf = new char [buffer.Length * 2];
|
|
Buffer.BlockCopy (buffer, 0, newbuf, 0, buffer.Length);
|
|
buffer = newbuf;
|
|
}
|
|
|
|
buffer [writepos++] = (char) b;
|
|
}
|
|
|
|
void AdjustBuffer ()
|
|
{
|
|
if (readpos >= writepos) {
|
|
readpos = writepos = 0;
|
|
}
|
|
}
|
|
|
|
ConsoleKeyInfo CreateKeyInfoFromInt (int n, bool alt)
|
|
{
|
|
char c = (char) n;
|
|
ConsoleKey key = (ConsoleKey)n;
|
|
bool shift = false;
|
|
bool ctrl = false;
|
|
|
|
switch (n){
|
|
case 10:
|
|
key = ConsoleKey.Enter;
|
|
break;
|
|
case 0x20:
|
|
key = ConsoleKey.Spacebar;
|
|
break;
|
|
case 45:
|
|
key = ConsoleKey.Subtract;
|
|
break;
|
|
case 43:
|
|
key = ConsoleKey.Add;
|
|
break;
|
|
case 47:
|
|
key = ConsoleKey.Divide;
|
|
break;
|
|
case 42:
|
|
key = ConsoleKey.Multiply;
|
|
break;
|
|
case 8: case 9: case 12: case 13: case 19:
|
|
/* Values in ConsoleKey */
|
|
break;
|
|
case 27:
|
|
key = ConsoleKey.Escape;
|
|
break;
|
|
|
|
default:
|
|
if (n >= 1 && n <= 26) {
|
|
// For Ctrl-a to Ctrl-z.
|
|
ctrl = true;
|
|
key = ConsoleKey.A + n - 1;
|
|
} else if (n >= 'a' && n <= 'z') {
|
|
key = ConsoleKey.A - 'a' + n;
|
|
} else if (n >= 'A' && n <= 'Z') {
|
|
shift = true;
|
|
} else if (n >= '0' && n <= '9') {
|
|
} else
|
|
key = 0;
|
|
break;
|
|
}
|
|
|
|
return new ConsoleKeyInfo (c, key, shift, alt, ctrl);
|
|
}
|
|
|
|
object GetKeyFromBuffer (bool cooked)
|
|
{
|
|
if (readpos >= writepos)
|
|
return null;
|
|
|
|
int next = buffer [readpos];
|
|
if (!cooked || !rootmap.StartsWith (next)) {
|
|
readpos++;
|
|
AdjustBuffer ();
|
|
return CreateKeyInfoFromInt (next, false);
|
|
}
|
|
|
|
int used;
|
|
TermInfoStrings str = rootmap.Match (buffer, readpos, writepos - readpos, out used);
|
|
if ((int) str == -1){
|
|
// Escape sequences: alt keys are sent as ESC-key
|
|
if (buffer [readpos] == 27 && (writepos - readpos) >= 2){
|
|
readpos += 2;
|
|
AdjustBuffer ();
|
|
if (buffer [readpos+1] == 127)
|
|
return new ConsoleKeyInfo ((char)8, ConsoleKey.Backspace, false, true, false);
|
|
return CreateKeyInfoFromInt (buffer [readpos+1], true);
|
|
} else
|
|
return null;
|
|
}
|
|
|
|
ConsoleKeyInfo key;
|
|
if (keymap [str] != null) {
|
|
key = (ConsoleKeyInfo) keymap [str];
|
|
} else {
|
|
readpos++;
|
|
AdjustBuffer ();
|
|
return CreateKeyInfoFromInt (next, false);
|
|
}
|
|
|
|
readpos += used;
|
|
AdjustBuffer ();
|
|
return key;
|
|
}
|
|
|
|
ConsoleKeyInfo ReadKeyInternal (out bool fresh)
|
|
{
|
|
if (!inited)
|
|
Init ();
|
|
|
|
InitKeys ();
|
|
|
|
object o;
|
|
|
|
if ((o = GetKeyFromBuffer (true)) == null) {
|
|
do {
|
|
if (ConsoleDriver.InternalKeyAvailable (150) > 0) {
|
|
do {
|
|
AddToBuffer (stdin.Read ());
|
|
} while (ConsoleDriver.InternalKeyAvailable (0) > 0);
|
|
} else if (stdin.DataAvailable ()) {
|
|
do {
|
|
AddToBuffer (stdin.Read ());
|
|
} while (stdin.DataAvailable ());
|
|
} else {
|
|
if ((o = GetKeyFromBuffer (false)) != null)
|
|
break;
|
|
|
|
AddToBuffer (stdin.Read ());
|
|
}
|
|
|
|
o = GetKeyFromBuffer (true);
|
|
} while (o == null);
|
|
|
|
// freshly read character
|
|
fresh = true;
|
|
} else {
|
|
// this char was pre-buffered (e.g. not fresh)
|
|
fresh = false;
|
|
}
|
|
|
|
return (ConsoleKeyInfo) o;
|
|
}
|
|
|
|
#region Input echoing optimization
|
|
bool InputPending ()
|
|
{
|
|
// check if we've got pending input we can read immediately
|
|
return readpos < writepos || stdin.DataAvailable ();
|
|
}
|
|
|
|
char [] echobuf = null;
|
|
int echon = 0;
|
|
|
|
// Queues a character to be echo'd back to the console
|
|
void QueueEcho (char c)
|
|
{
|
|
if (echobuf == null)
|
|
echobuf = new char [1024];
|
|
|
|
echobuf[echon++] = c;
|
|
|
|
if (echon == echobuf.Length || !InputPending ()) {
|
|
// blit our echo buffer to the console
|
|
stdout.InternalWriteChars (echobuf, echon);
|
|
echon = 0;
|
|
}
|
|
}
|
|
|
|
// Queues a key to be echo'd back to the console
|
|
void Echo (ConsoleKeyInfo key)
|
|
{
|
|
if (!IsSpecialKey (key)) {
|
|
QueueEcho (key.KeyChar);
|
|
return;
|
|
}
|
|
|
|
// flush pending echo's
|
|
EchoFlush ();
|
|
|
|
WriteSpecialKey (key);
|
|
}
|
|
|
|
// Flush the pending echo queue
|
|
void EchoFlush ()
|
|
{
|
|
if (echon == 0)
|
|
return;
|
|
|
|
// flush our echo buffer to the console
|
|
stdout.InternalWriteChars (echobuf, echon);
|
|
echon = 0;
|
|
}
|
|
#endregion
|
|
|
|
public int Read ([In, Out] char [] dest, int index, int count)
|
|
{
|
|
bool fresh, echo = false;
|
|
StringBuilder sbuf;
|
|
ConsoleKeyInfo key;
|
|
int BoL = 0; // Beginning-of-Line marker (can't backspace beyond this)
|
|
object o;
|
|
char c;
|
|
|
|
sbuf = new StringBuilder ();
|
|
|
|
// consume buffered keys first (do not echo, these have already been echo'd)
|
|
while (true) {
|
|
if ((o = GetKeyFromBuffer (true)) == null)
|
|
break;
|
|
|
|
key = (ConsoleKeyInfo) o;
|
|
c = key.KeyChar;
|
|
|
|
if (key.Key != ConsoleKey.Backspace) {
|
|
if (key.Key == ConsoleKey.Enter)
|
|
BoL = sbuf.Length;
|
|
|
|
sbuf.Append (c);
|
|
} else if (sbuf.Length > BoL) {
|
|
sbuf.Length--;
|
|
}
|
|
}
|
|
|
|
// continue reading until Enter is hit
|
|
rl_startx = cursorLeft;
|
|
rl_starty = cursorTop;
|
|
|
|
do {
|
|
key = ReadKeyInternal (out fresh);
|
|
echo = echo || fresh;
|
|
c = key.KeyChar;
|
|
|
|
if (key.Key != ConsoleKey.Backspace) {
|
|
if (key.Key == ConsoleKey.Enter)
|
|
BoL = sbuf.Length;
|
|
|
|
sbuf.Append (c);
|
|
} else if (sbuf.Length > BoL) {
|
|
sbuf.Length--;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
// echo fresh keys back to the console
|
|
if (echo)
|
|
Echo (key);
|
|
} while (key.Key != ConsoleKey.Enter);
|
|
|
|
EchoFlush ();
|
|
|
|
rl_startx = -1;
|
|
rl_starty = -1;
|
|
|
|
// copy up to count chars into dest
|
|
int nread = 0;
|
|
while (count > 0 && nread < sbuf.Length) {
|
|
dest[index + nread] = sbuf[nread];
|
|
nread++;
|
|
count--;
|
|
}
|
|
|
|
// put the rest back into our key buffer
|
|
for (int i = nread; i < sbuf.Length; i++)
|
|
AddToBuffer (sbuf[i]);
|
|
|
|
return nread;
|
|
}
|
|
|
|
public ConsoleKeyInfo ReadKey (bool intercept)
|
|
{
|
|
bool fresh;
|
|
|
|
ConsoleKeyInfo key = ReadKeyInternal (out fresh);
|
|
|
|
if (!intercept && fresh) {
|
|
// echo the fresh key back to the console
|
|
Echo (key);
|
|
EchoFlush ();
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
public string ReadLine ()
|
|
{
|
|
if (!inited)
|
|
Init ();
|
|
|
|
// Hack to make Iron Python work (since it goes behind our backs
|
|
// when writing to the console thus preventing us from keeping
|
|
// cursor state normally).
|
|
GetCursorPosition ();
|
|
|
|
StringBuilder builder = new StringBuilder ();
|
|
bool fresh, echo = false;
|
|
ConsoleKeyInfo key;
|
|
char c;
|
|
|
|
rl_startx = cursorLeft;
|
|
rl_starty = cursorTop;
|
|
char eof = (char) control_characters [ControlCharacters.EOF];
|
|
|
|
do {
|
|
key = ReadKeyInternal (out fresh);
|
|
echo = echo || fresh;
|
|
c = key.KeyChar;
|
|
// EOF -> Ctrl-D (EOT) pressed.
|
|
if (c == eof && c != 0 && builder.Length == 0)
|
|
return null;
|
|
|
|
if (key.Key != ConsoleKey.Enter) {
|
|
if (key.Key != ConsoleKey.Backspace) {
|
|
builder.Append (c);
|
|
} else if (builder.Length > 0) {
|
|
builder.Length--;
|
|
} else {
|
|
// skips over echoing the key to the console
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// echo fresh keys back to the console
|
|
if (echo)
|
|
Echo (key);
|
|
} while (key.Key != ConsoleKey.Enter);
|
|
|
|
EchoFlush ();
|
|
|
|
rl_startx = -1;
|
|
rl_starty = -1;
|
|
|
|
return builder.ToString ();
|
|
}
|
|
|
|
public void ResetColor ()
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
string str = (origPair != null) ? origPair : origColors;
|
|
WriteConsole (str);
|
|
}
|
|
|
|
public void SetBufferSize (int width, int height)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
throw new NotImplementedException (String.Empty);
|
|
}
|
|
|
|
public void SetCursorPosition (int left, int top)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
CheckWindowDimensions ();
|
|
if (left < 0 || left >= bufferWidth)
|
|
throw new ArgumentOutOfRangeException ("left", "Value must be positive and below the buffer width.");
|
|
|
|
if (top < 0 || top >= bufferHeight)
|
|
throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height.");
|
|
|
|
// Either CursorAddress or nothing.
|
|
// We might want to play with up/down/left/right/home when ca is not available.
|
|
if (cursorAddress == null)
|
|
throw new NotSupportedException ("This terminal does not suport setting the cursor position.");
|
|
|
|
int one = (home_1_1 ? 1 : 0);
|
|
WriteConsole (String.Format (cursorAddress, top + one, left + one));
|
|
cursorLeft = left;
|
|
cursorTop = top;
|
|
}
|
|
|
|
public void SetWindowPosition (int left, int top)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
// No need to throw exceptions here.
|
|
//throw new NotSupportedException ();
|
|
}
|
|
|
|
public void SetWindowSize (int width, int height)
|
|
{
|
|
if (!inited) {
|
|
Init ();
|
|
}
|
|
|
|
// No need to throw exceptions here.
|
|
//throw new NotSupportedException ();
|
|
}
|
|
|
|
|
|
void CreateKeyMap ()
|
|
{
|
|
keymap = new Hashtable ();
|
|
|
|
keymap [TermInfoStrings.KeyBackspace] = new ConsoleKeyInfo ('\0', ConsoleKey.Backspace, false, false, false);
|
|
keymap [TermInfoStrings.KeyClear] = new ConsoleKeyInfo ('\0', ConsoleKey.Clear, false, false, false);
|
|
// Delete character...
|
|
keymap [TermInfoStrings.KeyDown] = new ConsoleKeyInfo ('\0', ConsoleKey.DownArrow, false, false, false);
|
|
keymap [TermInfoStrings.KeyF1] = new ConsoleKeyInfo ('\0', ConsoleKey.F1, false, false, false);
|
|
keymap [TermInfoStrings.KeyF10] = new ConsoleKeyInfo ('\0', ConsoleKey.F10, false, false, false);
|
|
keymap [TermInfoStrings.KeyF2] = new ConsoleKeyInfo ('\0', ConsoleKey.F2, false, false, false);
|
|
keymap [TermInfoStrings.KeyF3] = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, false);
|
|
keymap [TermInfoStrings.KeyF4] = new ConsoleKeyInfo ('\0', ConsoleKey.F4, false, false, false);
|
|
keymap [TermInfoStrings.KeyF5] = new ConsoleKeyInfo ('\0', ConsoleKey.F5, false, false, false);
|
|
keymap [TermInfoStrings.KeyF6] = new ConsoleKeyInfo ('\0', ConsoleKey.F6, false, false, false);
|
|
keymap [TermInfoStrings.KeyF7] = new ConsoleKeyInfo ('\0', ConsoleKey.F7, false, false, false);
|
|
keymap [TermInfoStrings.KeyF8] = new ConsoleKeyInfo ('\0', ConsoleKey.F8, false, false, false);
|
|
keymap [TermInfoStrings.KeyF9] = new ConsoleKeyInfo ('\0', ConsoleKey.F9, false, false, false);
|
|
keymap [TermInfoStrings.KeyHome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
|
|
keymap [TermInfoStrings.KeyLeft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, false, false, false);
|
|
keymap [TermInfoStrings.KeyLl] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
|
|
keymap [TermInfoStrings.KeyNpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
|
|
keymap [TermInfoStrings.KeyPpage] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
|
|
keymap [TermInfoStrings.KeyRight] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, false, false, false);
|
|
keymap [TermInfoStrings.KeySf] = new ConsoleKeyInfo ('\0', ConsoleKey.PageDown, false, false, false);
|
|
keymap [TermInfoStrings.KeySr] = new ConsoleKeyInfo ('\0', ConsoleKey.PageUp, false, false, false);
|
|
keymap [TermInfoStrings.KeyUp] = new ConsoleKeyInfo ('\0', ConsoleKey.UpArrow, false, false, false);
|
|
keymap [TermInfoStrings.KeyA1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad7, false, false, false);
|
|
keymap [TermInfoStrings.KeyA3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad9, false, false, false);
|
|
keymap [TermInfoStrings.KeyB2] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad5, false, false, false);
|
|
keymap [TermInfoStrings.KeyC1] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad1, false, false, false);
|
|
keymap [TermInfoStrings.KeyC3] = new ConsoleKeyInfo ('\0', ConsoleKey.NumPad3, false, false, false);
|
|
keymap [TermInfoStrings.KeyBtab] = new ConsoleKeyInfo ('\0', ConsoleKey.Tab, true, false, false);
|
|
keymap [TermInfoStrings.KeyBeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, false, false, false);
|
|
keymap [TermInfoStrings.KeyCopy] = new ConsoleKeyInfo ('C', ConsoleKey.C, false, true, false);
|
|
keymap [TermInfoStrings.KeyEnd] = new ConsoleKeyInfo ('\0', ConsoleKey.End, false, false, false);
|
|
keymap [TermInfoStrings.KeyEnter] = new ConsoleKeyInfo ('\n', ConsoleKey.Enter, false, false, false);
|
|
keymap [TermInfoStrings.KeyHelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, false, false, false);
|
|
keymap [TermInfoStrings.KeyPrint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, false, false, false);
|
|
keymap [TermInfoStrings.KeyUndo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z , false, true, false);
|
|
keymap [TermInfoStrings.KeySbeg] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
|
|
keymap [TermInfoStrings.KeyScopy] = new ConsoleKeyInfo ('C', ConsoleKey.C , true, true, false);
|
|
keymap [TermInfoStrings.KeySdc] = new ConsoleKeyInfo ('\x9', ConsoleKey.Delete, true, false, false);
|
|
keymap [TermInfoStrings.KeyShelp] = new ConsoleKeyInfo ('\0', ConsoleKey.Help, true, false, false);
|
|
keymap [TermInfoStrings.KeyShome] = new ConsoleKeyInfo ('\0', ConsoleKey.Home, true, false, false);
|
|
keymap [TermInfoStrings.KeySleft] = new ConsoleKeyInfo ('\0', ConsoleKey.LeftArrow, true, false, false);
|
|
keymap [TermInfoStrings.KeySprint] = new ConsoleKeyInfo ('\0', ConsoleKey.Print, true, false, false);
|
|
keymap [TermInfoStrings.KeySright] = new ConsoleKeyInfo ('\0', ConsoleKey.RightArrow, true, false, false);
|
|
keymap [TermInfoStrings.KeySundo] = new ConsoleKeyInfo ('Z', ConsoleKey.Z, true, false, false);
|
|
keymap [TermInfoStrings.KeyF11] = new ConsoleKeyInfo ('\0', ConsoleKey.F11, false, false, false);
|
|
keymap [TermInfoStrings.KeyF12] = new ConsoleKeyInfo ('\0', ConsoleKey.F12 , false, false, false);
|
|
keymap [TermInfoStrings.KeyF13] = new ConsoleKeyInfo ('\0', ConsoleKey.F13, false, false, false);
|
|
keymap [TermInfoStrings.KeyF14] = new ConsoleKeyInfo ('\0', ConsoleKey.F14, false, false, false);
|
|
keymap [TermInfoStrings.KeyF15] = new ConsoleKeyInfo ('\0', ConsoleKey.F15, false, false, false);
|
|
keymap [TermInfoStrings.KeyF16] = new ConsoleKeyInfo ('\0', ConsoleKey.F16, false, false, false);
|
|
keymap [TermInfoStrings.KeyF17] = new ConsoleKeyInfo ('\0', ConsoleKey.F17, false, false, false);
|
|
keymap [TermInfoStrings.KeyF18] = new ConsoleKeyInfo ('\0', ConsoleKey.F18, false, false, false);
|
|
keymap [TermInfoStrings.KeyF19] = new ConsoleKeyInfo ('\0', ConsoleKey.F19, false, false, false);
|
|
keymap [TermInfoStrings.KeyF20] = new ConsoleKeyInfo ('\0', ConsoleKey.F20, false, false, false);
|
|
keymap [TermInfoStrings.KeyF21] = new ConsoleKeyInfo ('\0', ConsoleKey.F21, false, false, false);
|
|
keymap [TermInfoStrings.KeyF22] = new ConsoleKeyInfo ('\0', ConsoleKey.F22, false, false, false);
|
|
keymap [TermInfoStrings.KeyF23] = new ConsoleKeyInfo ('\0', ConsoleKey.F23, false, false, false);
|
|
keymap [TermInfoStrings.KeyF24] = new ConsoleKeyInfo ('\0', ConsoleKey.F24, false, false, false);
|
|
// These were previously missing:
|
|
keymap [TermInfoStrings.KeyDc] = new ConsoleKeyInfo ('\0', ConsoleKey.Delete, false, false, false);
|
|
keymap [TermInfoStrings.KeyIc] = new ConsoleKeyInfo ('\0', ConsoleKey.Insert, false, false, false);
|
|
}
|
|
|
|
void InitKeys ()
|
|
{
|
|
if (initKeys)
|
|
return;
|
|
|
|
CreateKeyMap ();
|
|
rootmap = new ByteMatcher ();
|
|
|
|
//
|
|
// The keys that we know about and use
|
|
//
|
|
var UsedKeys = new [] {
|
|
TermInfoStrings.KeyBackspace,
|
|
TermInfoStrings.KeyClear,
|
|
TermInfoStrings.KeyDown,
|
|
TermInfoStrings.KeyF1,
|
|
TermInfoStrings.KeyF10,
|
|
TermInfoStrings.KeyF2,
|
|
TermInfoStrings.KeyF3,
|
|
TermInfoStrings.KeyF4,
|
|
TermInfoStrings.KeyF5,
|
|
TermInfoStrings.KeyF6,
|
|
TermInfoStrings.KeyF7,
|
|
TermInfoStrings.KeyF8,
|
|
TermInfoStrings.KeyF9,
|
|
TermInfoStrings.KeyHome,
|
|
TermInfoStrings.KeyLeft,
|
|
TermInfoStrings.KeyLl,
|
|
TermInfoStrings.KeyNpage,
|
|
TermInfoStrings.KeyPpage,
|
|
TermInfoStrings.KeyRight,
|
|
TermInfoStrings.KeySf,
|
|
TermInfoStrings.KeySr,
|
|
TermInfoStrings.KeyUp,
|
|
TermInfoStrings.KeyA1,
|
|
TermInfoStrings.KeyA3,
|
|
TermInfoStrings.KeyB2,
|
|
TermInfoStrings.KeyC1,
|
|
TermInfoStrings.KeyC3,
|
|
TermInfoStrings.KeyBtab,
|
|
TermInfoStrings.KeyBeg,
|
|
TermInfoStrings.KeyCopy,
|
|
TermInfoStrings.KeyEnd,
|
|
TermInfoStrings.KeyEnter,
|
|
TermInfoStrings.KeyHelp,
|
|
TermInfoStrings.KeyPrint,
|
|
TermInfoStrings.KeyUndo,
|
|
TermInfoStrings.KeySbeg,
|
|
TermInfoStrings.KeyScopy,
|
|
TermInfoStrings.KeySdc,
|
|
TermInfoStrings.KeyShelp,
|
|
TermInfoStrings.KeyShome,
|
|
TermInfoStrings.KeySleft,
|
|
TermInfoStrings.KeySprint,
|
|
TermInfoStrings.KeySright,
|
|
TermInfoStrings.KeySundo,
|
|
TermInfoStrings.KeyF11,
|
|
TermInfoStrings.KeyF12,
|
|
TermInfoStrings.KeyF13,
|
|
TermInfoStrings.KeyF14,
|
|
TermInfoStrings.KeyF15,
|
|
TermInfoStrings.KeyF16,
|
|
TermInfoStrings.KeyF17,
|
|
TermInfoStrings.KeyF18,
|
|
TermInfoStrings.KeyF19,
|
|
TermInfoStrings.KeyF20,
|
|
TermInfoStrings.KeyF21,
|
|
TermInfoStrings.KeyF22,
|
|
TermInfoStrings.KeyF23,
|
|
TermInfoStrings.KeyF24,
|
|
|
|
// These were missing
|
|
TermInfoStrings.KeyDc,
|
|
TermInfoStrings.KeyIc
|
|
};
|
|
|
|
foreach (TermInfoStrings tis in UsedKeys)
|
|
AddStringMapping (tis);
|
|
|
|
rootmap.AddMapping (TermInfoStrings.KeyBackspace, new byte [] { control_characters [ControlCharacters.Erase] });
|
|
rootmap.Sort ();
|
|
initKeys = true;
|
|
}
|
|
|
|
void AddStringMapping (TermInfoStrings s)
|
|
{
|
|
byte [] bytes = reader.GetStringBytes (s);
|
|
if (bytes == null)
|
|
return;
|
|
|
|
rootmap.AddMapping (s, bytes);
|
|
}
|
|
}
|
|
|
|
class ByteMatcher {
|
|
Hashtable map = new Hashtable ();
|
|
Hashtable starts = new Hashtable ();
|
|
|
|
public void AddMapping (TermInfoStrings key, byte [] val)
|
|
{
|
|
if (val.Length == 0)
|
|
return;
|
|
|
|
map [val] = key;
|
|
starts [(int) val [0]] = true;
|
|
}
|
|
|
|
public void Sort ()
|
|
{
|
|
}
|
|
|
|
public bool StartsWith (int c)
|
|
{
|
|
return (starts [c] != null);
|
|
}
|
|
|
|
public TermInfoStrings Match (char [] buffer, int offset, int length, out int used)
|
|
{
|
|
foreach (byte [] bytes in map.Keys) {
|
|
for (int i = 0; i < bytes.Length && i < length; i++) {
|
|
if ((char) bytes [i] != buffer [offset + i])
|
|
break;
|
|
|
|
if (bytes.Length - 1 == i) {
|
|
used = bytes.Length;
|
|
return (TermInfoStrings) map [bytes];
|
|
}
|
|
}
|
|
}
|
|
|
|
used = 0;
|
|
return (TermInfoStrings) (-1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|