+2006-09-19 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * ConsoleDriver.cs:
+ * TermInfoDriver.cs:
+ * IConsoleDriver.cs:
+ * Console.cs:
+ * WindowsConsoleDriver.cs: don't switch to the alternate window.
+ Trigger the cancel event. Retrieve the cursor position at the
+ beginning, as we're going to keep track of it instead of querying it
+ all the time.
+
2006-09-14 Jonathan Chambers <joncham@gmail.com>
* Environment.cs (ProcessorCount): Implement as icall.
inputEncoding = outputEncoding = Encoding.Default;
}
- stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding);
- ((StreamWriter)stderr).AutoFlush = true;
- stderr = TextWriter.Synchronized (stderr, true);
+#if NET_2_0
+/*
+ if (ConsoleDriver.IsConsole) {
+ CStreamWriter w = new CStreamWriter (OpenStandardError (0), outputEncoding);
+ w.AutoFlush = true;
+ stderr = TextWriter.Synchronized (w, true);
+
+ w = new CStreamWriter (OpenStandardOutput (0), outputEncoding);
+ w.AutoFlush = true;
+ stdout = TextWriter.Synchronized (w, true);
+ } else {
+ */
+#endif
+ stderr = new UnexceptionalStreamWriter (OpenStandardError (0), outputEncoding);
+ ((StreamWriter)stderr).AutoFlush = true;
+ stderr = TextWriter.Synchronized (stderr, true);
- stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
- ((StreamWriter)stdout).AutoFlush = true;
- stdout = TextWriter.Synchronized (stdout, true);
+ stdout = new UnexceptionalStreamWriter (OpenStandardOutput (0), outputEncoding);
+ ((StreamWriter)stdout).AutoFlush = true;
+ stdout = TextWriter.Synchronized (stdout, true);
+#if NET_2_0
+ //}
+#endif
stdin = new UnexceptionalStreamReader (OpenStandardInput (0), inputEncoding);
stdin = TextReader.Synchronized (stdin);
return OpenStandardError (0);
}
- // calling any FileStream constructor with an handle normally
+ // calling any FileStream constructor with a handle normally
// requires permissions UnmanagedCode permissions. In this
// case we assert this permission so the console can be used
// in partial trust (i.e. without having UnmanagedCode).
return OpenStandardInput (0);
}
- // calling any FileStream constructor with an handle normally
+ // calling any FileStream constructor with a handle normally
// requires permissions UnmanagedCode permissions. In this
// case we assert this permission so the console can be used
// in partial trust (i.e. without having UnmanagedCode).
return OpenStandardOutput (0);
}
- // calling any FileStream constructor with an handle normally
+ // calling any FileStream constructor with a handle normally
// requires permissions UnmanagedCode permissions. In this
// case we assert this permission so the console can be used
// in partial trust (i.e. without having UnmanagedCode).
}
#endif
+#if NET_2_0
public static int Read ()
{
- return stdin.Read ();
+ if (ConsoleDriver.IsConsole) {
+ return ConsoleDriver.Read ();
+ } else {
+ return stdin.Read ();
+ }
}
-#if NET_2_0
public static string ReadLine ()
{
- bool prevEcho = false;
- if (ConsoleDriver.Initialized) {
- prevEcho = ConsoleDriver.Echo;
- ConsoleDriver.Echo = true;
+ if (ConsoleDriver.IsConsole) {
+ return ConsoleDriver.ReadLine ();
+ } else {
+ return stdin.ReadLine ();
}
-
- string ret = stdin.ReadLine ();
- if (ConsoleDriver.Initialized)
- ConsoleDriver.Echo = prevEcho;
-
- return ret;
}
#else
+ public static int Read ()
+ {
+ return stdin.Read ();
+ }
+
public static string ReadLine ()
{
return stdin.ReadLine ();
ConsoleDriver.SetWindowSize (width, height);
}
- [MonoTODO ("Implement add/remove hooks")]
public static event ConsoleCancelEventHandler CancelKeyPress;
+
+ delegate void InternalCancelHandler ();
+ static InternalCancelHandler cancel_handler = new InternalCancelHandler (DoConsoleCancelEvent);
+
+ internal static void DoConsoleCancelEvent ()
+ {
+ bool exit = true;
+ if (CancelKeyPress != null) {
+ ConsoleCancelEventArgs args = new ConsoleCancelEventArgs (ConsoleSpecialKey.ControlC);
+ Delegate [] delegates = CancelKeyPress.GetInvocationList ();
+ foreach (ConsoleCancelEventHandler d in delegates){
+ try {
+ // Sender is always null here.
+ d (null, args);
+ } catch {} // Ignore any exception.
+ }
+ exit = !args.Cancel;
+ }
+
+ if (exit)
+ Environment.Exit (58);
+ }
#endif
}
}
+
namespace System {
class ConsoleDriver {
static IConsoleDriver driver;
+ static bool is_console;
+ static bool called_isatty;
static ConsoleDriver ()
{
targetLeft, targetTop, sourceChar, sourceForeColor, sourceBackColor);
}
+ public static int Read ()
+ {
+ return ReadKey (false).KeyChar;
+ }
+
+ public static string ReadLine ()
+ {
+ return driver.ReadLine ();
+ }
+
public static ConsoleKeyInfo ReadKey (bool intercept)
{
return driver.ReadKey (intercept);
driver.SetWindowSize (width, height);
}
+ public static bool IsConsole {
+ get {
+ if (called_isatty)
+ return is_console;
+
+ is_console = (Isatty (MonoIO.ConsoleOutput) && Isatty (MonoIO.ConsoleInput));
+ called_isatty = true;
+ return is_console;
+ }
+ }
+
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool Isatty (IntPtr handle);
+ static extern bool Isatty (IntPtr handle);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int InternalKeyAvailable (int ms_timeout);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern bool TtySetup (string teardown);
+ internal static extern bool TtySetup (string teardown, out byte verase, out byte vsusp, out byte intr);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool SetEcho (bool wantEcho);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool GetTtySize (IntPtr handle, out int width, out int height);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern void Suspend ();
}
}
#endif
void SetCursorPosition (int left, int top);
void SetWindowPosition (int left, int top);
void SetWindowSize (int width, int height);
+ string ReadLine ();
}
}
#endif
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
-// (C) 2005 Novell, Inc (http://www.novell.com)
+// (C) 2005,2006 Novell, Inc (http://www.novell.com)
//
//
#if NET_2_0
using System.Collections;
using System.IO;
+using System.Text;
namespace System {
class TermInfoDriver : IConsoleDriver {
static string [] locations = { "/etc/terminfo", "/usr/share/terminfo", "/usr/lib/terminfo" };
string term;
Stream stdout;
Stream stdin;
+ byte verase;
+ byte vsusp;
+ byte intr;
int windowWidth;
int windowHeight;
byte [] buffer;
int readpos;
int writepos;
- string enterCA, exitCA;
string keypadXmit, keypadLocal;
bool controlCAsInput;
bool inited;
if (reader == null)
reader = new TermInfoReader (term, KnownTerminals.ansi);
+
+ Init ();
}
public bool Initialized {
{
if (inited)
return;
+
+ /* This should not happen any more, since it is checked for in Console */
+ if (!ConsoleDriver.IsConsole)
+ throw new IOException ("Not a tty.");
inited = true;
- enterCA = reader.Get (TermInfoStrings.EnterCaMode);
- exitCA = reader.Get (TermInfoStrings.ExitCaMode);
+ ConsoleDriver.SetEcho (false);
string endString = null;
- if (enterCA != null && exitCA != null)
- endString = exitCA;
-
keypadXmit = reader.Get (TermInfoStrings.KeypadXmit);
keypadLocal = reader.Get (TermInfoStrings.KeypadLocal);
if (keypadXmit != null) {
- WriteConsole (keypadXmit);
+ WriteConsole (keypadXmit); // Needed to get the arrows working
if (keypadLocal != null)
endString += keypadLocal;
}
- if (!ConsoleDriver.Isatty (MonoIO.ConsoleOutput) || !ConsoleDriver.Isatty (MonoIO.ConsoleInput))
- throw new IOException ("Not a tty.");
-
origPair = reader.Get (TermInfoStrings.OrigPair);
origColors = reader.Get (TermInfoStrings.OrigColors);
setafcolor = MangleParameters (reader.Get (TermInfoStrings.SetAForeground));
if (resetColors != null)
endString += resetColors;
- if (!ConsoleDriver.TtySetup (endString))
+ if (!ConsoleDriver.TtySetup (endString, out verase, out vsusp, out intr))
throw new IOException ("Error initializing terminal.");
- if (enterCA != null && exitCA != null)
- WriteConsole (enterCA);
-
stdout = Console.OpenStandardOutput (0);
stdin = Console.OpenStandardInput (0);
clear = reader.Get (TermInfoStrings.ClearScreen);
home_1_1 = (cursorAddress != result);
cursorAddress = MangleParameters (result);
}
+
+ GetCursorPosition ();
+ if (noGetPosition) {
+ WriteConsole (clear);
+ cursorLeft = 0;
+ cursorTop = 0;
+ }
}
static string MangleParameters (string str)
public ConsoleColor BackgroundColor {
get { return bgcolor; }
set {
- Init ();
bgcolor = value;
WriteConsole (String.Format (setabcolor, TranslateColor (value)));
}
public ConsoleColor ForegroundColor {
get { return fgcolor; }
set {
- Init ();
fgcolor = value;
WriteConsole (String.Format (setafcolor, TranslateColor (value)));
}
}
+ // Only used once.
void GetCursorPosition ()
{
- if (noGetPosition)
- return;
-
int row = 0, col = 0;
bool prevEcho = Echo;
Echo = false;
public int BufferHeight {
get {
- GetWindowDimensions ();
return bufferHeight;
}
set {
public int BufferWidth {
get {
- GetWindowDimensions ();
return bufferWidth;
}
set {
public int CursorLeft {
get {
- Init ();
GetCursorPosition ();
return cursorLeft;
}
set {
- Init ();
SetCursorPosition (value, CursorTop);
cursorLeft = value;
}
public int CursorTop {
get {
- Init ();
GetCursorPosition ();
return cursorTop;
}
set {
- Init ();
SetCursorPosition (CursorLeft, value);
cursorTop = value;
}
public bool CursorVisible {
get {
- Init ();
return cursorVisible;
}
set {
- Init ();
cursorVisible = value;
WriteConsole ((value ? csrVisible : csrInvisible));
}
public bool KeyAvailable {
get {
- Init ();
return (writepos > readpos || ConsoleDriver.InternalKeyAvailable (0) > 0);
}
}
get { return title; }
set {
- Init ();
title = value;
WriteConsole (String.Format (titleFormat, value));
}
if (controlCAsInput == value)
return;
- Init ();
ConsoleDriver.SetBreak (value);
controlCAsInput = value;
}
}
+ // TODO: use this at the beginning and on every SIGWINCH
void GetWindowDimensions ()
{
- //TODO: Handle SIGWINCH
-
/* Try the ioctl first */
if (!ConsoleDriver.GetTtySize (MonoIO.ConsoleOutput, out windowWidth, out windowHeight)) {
windowWidth = reader.Get (TermInfoNumbers.Columns);
}
}
- //windowTop = 0;
- //windowLeft = 0;
bufferHeight = windowHeight;
bufferWidth = windowWidth;
}
public void Clear ()
{
- Init ();
WriteConsole (clear);
}
public void Beep (int frequency, int duration)
{
- Init ();
WriteConsole (bell);
}
public ConsoleKeyInfo ReadKey (bool intercept)
{
- Init ();
bool prevEcho = Echo;
if (prevEcho == intercept)
Echo = !intercept;
return key;
}
+ public string ReadLine ()
+ {
+ bool prevEcho = Echo;
+ if (prevEcho == false)
+ Echo = true;
+ StringBuilder builder = new StringBuilder ();
+ bool exit = false;
+ do {
+ ConsoleKeyInfo key = ReadKeyInternal ();
+ char c = key.KeyChar;
+ exit = (c == '\n');
+ if (!exit)
+ builder.Append (c);
+ stdout.WriteByte ((byte) c);
+ } while (!exit);
+ if (prevEcho == false)
+ Echo = prevEcho;
+ return builder.ToString ();
+ }
+
public void ResetColor ()
{
- Init ();
string str = (origPair != null) ? origPair : origColors;
WriteConsole (str);
}
if (top < 0 || top >= bufferHeight)
throw new ArgumentOutOfRangeException ("top", "Value must be positive and below the buffer height.");
- Init ();
-
// 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 ArgumentException (String.Empty, "Cannot write to the specified coordinates.");
}
+ public string ReadLine ()
+ {
+ StringBuilder builder = new StringBuilder ();
+ bool exit = false;
+ do {
+ ConsoleKeyInfo key = ReadKey (false);
+ char c = key.KeyChar;
+ exit = (c == '\n');
+ if (!exit)
+ builder.Append (key.KeyChar);
+ } while (!exit);
+ return builder.ToString ();
+ }
+
public ConsoleKeyInfo ReadKey (bool intercept)
{
int eventsRead;