/// <summary> /// Map the Unicode chars (and the fake control codes we made) into what the /// terminal wants to see. /// Subclasses of this should perform their own manipulations, then fallthrough /// to this base class implementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public override char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = t; outputExpected = ExpectNextChar.RESIZEHEIGHT; break; case ExpectNextChar.RESIZEHEIGHT: int height = t; sb.AppendFormat("{0}8;{1};{2}t", CSI, height, pendingWidth); outputExpected = ExpectNextChar.NORMAL; break; case ExpectNextChar.INTITLE: if (t == (char)UnicodeCommand.TITLEEND) { sb.AppendFormat("{0}]2;{1}{2}", ESCAPE_CHARACTER, pendingTitle, BELL_CHAR); pendingTitle = new StringBuilder(); outputExpected = ExpectNextChar.NORMAL; } else { pendingTitle.Append(t); } break; default: switch (t) { case (char)UnicodeCommand.RESIZESCREEN: outputExpected = ExpectNextChar.RESIZEWIDTH; break; case (char)UnicodeCommand.TITLEBEGIN: outputExpected = ExpectNextChar.INTITLE; pendingTitle = new StringBuilder(); break; case (char)UnicodeCommand.CLEARSCREEN: sb.AppendFormat("{0}?47h", ESCAPE_CHARACTER); // <-- Tells xterm to use fixed-buffer mode, not saving in scrollback. sb.AppendFormat("{0}2J{0}H", CSI); // <-- The normal clear screen char from vt100. break; default: sb.Append(t); // default passhtrough break; } break; } } return(base.OutputConvert(sb.ToString())); }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) into what the /// terminal wants to see. /// Subclasses of this should perform their own manipulations, then fallthrough /// to this base class implementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public override char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = t; outputExpected = ExpectNextChar.RESIZEHEIGHT; break; case ExpectNextChar.RESIZEHEIGHT: int height = t; sb.AppendFormat("{0}8;{1};{2}t", CSI, height, pendingWidth); outputExpected = ExpectNextChar.NORMAL; break; case ExpectNextChar.INTITLE: if (t == (char)UnicodeCommand.TITLEEND) { sb.AppendFormat("{0}]2;{1}{2}", ESCAPE_CHARACTER , pendingTitle, BELL_CHAR); pendingTitle = new StringBuilder(); outputExpected = ExpectNextChar.NORMAL; } else pendingTitle.Append(t); break; default: switch (t) { case (char)UnicodeCommand.RESIZESCREEN: outputExpected = ExpectNextChar.RESIZEWIDTH; break; case (char)UnicodeCommand.TITLEBEGIN: outputExpected = ExpectNextChar.INTITLE; pendingTitle = new StringBuilder(); break; case (char)UnicodeCommand.CLEARSCREEN: sb.AppendFormat("{0}?47h", ESCAPE_CHARACTER); // <-- Tells xterm to use fixed-buffer mode, not saving in scrollback. sb.AppendFormat("{0}2J{0}H", CSI); // <-- The normal clear screen char from vt100. break; default: sb.Append(t); // default passhtrough break; } break; } } return base.OutputConvert(sb.ToString()); }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) into what the terminal /// wants to see. /// In this base class, all it does is just mostly passthru things as-is with no /// conversions. /// Subclasses of this should perform their own manipulations, then fallthrough /// to this base class inmplementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public virtual char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = t; outputExpected = ExpectNextChar.RESIZEHEIGHT; break; case ExpectNextChar.RESIZEHEIGHT: int height = t; sb.Append("{Please resize to " + pendingWidth + "x" + height + "}"); // By default, assume the terminal has no such control code, but this can be overridden. outputExpected = ExpectNextChar.NORMAL; break; case ExpectNextChar.INTITLE: // Default behavior: Ignore all content until the title ender. Assume most terminals don't know how to do this. if (t == (char)UnicodeCommand.TITLEEND) { outputExpected = ExpectNextChar.NORMAL; } break; default: switch (t) { case (char)UnicodeCommand.RESIZESCREEN: outputExpected = ExpectNextChar.RESIZEWIDTH; break; case (char)UnicodeCommand.TITLEBEGIN: outputExpected = ExpectNextChar.INTITLE; break; case (char)UnicodeCommand.STARTNEXTLINE: sb.Append("\r\n"); break; case (char)UnicodeCommand.LINEFEEDKEEPCOL: sb.Append("\n"); break; case (char)UnicodeCommand.GOTOLEFTEDGE: sb.Append("\r"); break; default: sb.Append(t); // default passhtrough break; } break; } } // By this point, any UnicodeCommand chars still left must be un-mapped by any of the mappers: if (!AllowNativeUnicodeCommands) { StripUnicodeCommands(sb); } return(sb.ToString().ToCharArray()); }
/// <summary> /// Respond to one single input character in Unicode, using the pretend /// virtual Unicode terminal keycodes described in the UnicodeCommand enum. /// To keep things simple, all key input is coerced into single Unicode chars /// even if the actual keypress takes multiple characters to express in its /// native form (i.e. ESC [ A means left-arrow on a VT100 terminal. If /// a telnet is talking via VT100 codes, that ESC [ A will get converted into /// a single UnicdeCommand.LEFTCURSORONE character before being sent here.) /// <br/> /// This method is public because it is also how other mods should send input /// to the terminal if they want some other source to send simulated keystrokes. /// </summary> /// <param name="ch">The character, which might be a UnicodeCommand char</param> /// <param name="whichTelnet">If this came from a telnet session, which one did it come from? /// Set to null in order to say it wasn't from a telnet but was from the interactive GUI</param> /// <param name="doQueuing">true if the keypress should get queued if we're not ready for it /// right now. If false, then the keypress will be ignored if we're not ready for it.</param> public void ProcessOneInputChar(char ch, TelnetSingletonServer whichTelnet, bool doQueuing = true) { // Weird exceptions for multi-char data combos that would have been begun on previous calls to this method: switch (inputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = ch; inputExpected = ExpectNextChar.RESIZEHEIGHT; return; case ExpectNextChar.RESIZEHEIGHT: int height = ch; shared.Screen.SetSize(height, pendingWidth); inputExpected = ExpectNextChar.NORMAL; return; default: break; } // Printable ASCII section of Unicode - the common vanilla situation // (Idea: Since this is all Unicode anyway, should we allow a wider range to // include multi-language accent characters and so on? Answer: to do so we'd // first need to expand the font pictures in the font image file, so it's a // bigger task than it may first seem.) if (0x0020 <= ch && ch <= 0x007f) { Type(ch, doQueuing); } else { switch(ch) { // A few conversions from UnicodeCommand into those parts of ASCII that it // maps directly into nicely, otherwise just pass it through to SpecialKey(): case (char)UnicodeCommand.DELETELEFT: case (char)8: Type((char)8, doQueuing); break; case (char)UnicodeCommand.STARTNEXTLINE: case '\r': Type('\r', doQueuing); break; case '\t': Type('\t', doQueuing); break; case (char)UnicodeCommand.RESIZESCREEN: inputExpected = ExpectNextChar.RESIZEWIDTH; break; // next expected char is the width. // Finish session: If GUI, then close window. If Telnet, then detatch from the session: case (char)0x0004/*control-D*/: // How users of unix shells are used to doing this. case (char)0x0018/*control-X*/: // How kOS did it in the past in the GUI window. if (shared.Interpreter.IsAtStartOfCommand()) { if (whichTelnet == null) Close(); else whichTelnet.DisconnectFromProcessor(); } break; // User asking for redraw (Unity already requires that we continually redraw the GUI Terminal, so this is only meaningful for telnet): case (char)UnicodeCommand.REQUESTREPAINT: if (whichTelnet != null) { ResizeAndRepaintTelnet(whichTelnet, shared.Screen.ColumnCount, shared.Screen.RowCount, true); } break; // Typical case is to just let SpecialKey do the work: default: SpecialKey(ch, doQueuing); break; } } // else ignore it - unimplemented char. }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) on output to what the terminal /// wants to see. /// Subclasses of this should perform their own manipulations, then fall-through /// to this base class implementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public override char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.TELEPORTCURSORCOL: pendingCol = t; outputExpected = ExpectNextChar.TELEPORTCURSORROW; break; case ExpectNextChar.TELEPORTCURSORROW: int row = t; // VT100 counts rows and cols starting at 1, not 0, thus the +1's below: sb.AppendFormat("{0}{1};{2}H", csi, (row + 1), (pendingCol + 1)); outputExpected = ExpectNextChar.NORMAL; break; default: switch (t) { case (char)UnicodeCommand.TELEPORTCURSOR: outputExpected = ExpectNextChar.TELEPORTCURSORCOL; break; case (char)UnicodeCommand.CLEARSCREEN: sb.AppendFormat("{0}2J{0}H", csi); break; case (char)UnicodeCommand.SCROLLSCREENUPONE: sb.AppendFormat("{0}S", csi); break; case (char)UnicodeCommand.SCROLLSCREENDOWNONE: sb.AppendFormat("{0}T", csi); break; case (char)UnicodeCommand.HOMECURSOR: sb.AppendFormat("{0}H", csi); break; case (char)UnicodeCommand.UPCURSORONE: sb.AppendFormat("{0}A", csi); break; case (char)UnicodeCommand.DOWNCURSORONE: sb.AppendFormat("{0}B", csi); break; case (char)UnicodeCommand.RIGHTCURSORONE: sb.AppendFormat("{0}C", csi); break; case (char)UnicodeCommand.LEFTCURSORONE: sb.AppendFormat("{0}D", csi); break; case (char)UnicodeCommand.DELETELEFT: sb.AppendFormat("{0}K", csi); break; case (char)UnicodeCommand.DELETERIGHT: sb.AppendFormat("{0}1K", csi); break; case (char)UnicodeCommand.BEEP: sb.Append(BELL_CHAR); break; case (char)UnicodeCommand.REVERSESCREENMODE: sb.AppendFormat("{0}?5h", csi); break; case (char)UnicodeCommand.NORMALSCREENMODE: sb.AppendFormat("{0}?5l", csi); break; case (char)UnicodeCommand.VISUALBEEPMODE: // sadly, have to consume and ignore - no vt100 code for this, so it's not supported. break; case (char)UnicodeCommand.AUDIOBEEPMODE: // sadly, have to consume and ignore - no vt100 code for this. so it's not supported. break; default: sb.Append(t); // default passhtrough break; } break; } } return(base.OutputConvert(sb.ToString())); }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) on output to what the terminal /// wants to see. /// Subclasses of this should perform their own manipulations, then fall-through /// to this base class implementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public override char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.TELEPORTCURSORCOL: pendingCol = t; outputExpected = ExpectNextChar.TELEPORTCURSORROW; break; case ExpectNextChar.TELEPORTCURSORROW: int row = t; // VT100 counts rows and cols starting at 1, not 0, thus the +1's below: sb.AppendFormat("{0}{1};{2}H", csi, (row + 1), (pendingCol + 1)); outputExpected = ExpectNextChar.NORMAL; break; default: switch (t) { case (char)UnicodeCommand.TELEPORTCURSOR: outputExpected = ExpectNextChar.TELEPORTCURSORCOL; break; case (char)UnicodeCommand.CLEARSCREEN: sb.AppendFormat("{0}2J{0}H", csi); break; case (char)UnicodeCommand.SCROLLSCREENUPONE: sb.AppendFormat("{0}S", csi); break; case (char)UnicodeCommand.SCROLLSCREENDOWNONE: sb.AppendFormat("{0}T", csi); break; case (char)UnicodeCommand.HOMECURSOR: sb.AppendFormat("{0}H", csi); break; case (char)UnicodeCommand.UPCURSORONE: sb.AppendFormat("{0}A", csi); break; case (char)UnicodeCommand.DOWNCURSORONE: sb.AppendFormat("{0}B", csi); break; case (char)UnicodeCommand.RIGHTCURSORONE: sb.AppendFormat("{0}C", csi); break; case (char)UnicodeCommand.LEFTCURSORONE: sb.AppendFormat("{0}D", csi); break; case (char)UnicodeCommand.DELETELEFT: sb.AppendFormat("{0}K", csi); break; case (char)UnicodeCommand.DELETERIGHT: sb.AppendFormat("{0}1K", csi); break; case (char)UnicodeCommand.BEEP: sb.Append(BELL_CHAR); break; case (char)UnicodeCommand.REVERSESCREENMODE: sb.AppendFormat("{0}?5h", csi); break; case (char)UnicodeCommand.NORMALSCREENMODE: sb.AppendFormat("{0}?5l", csi); break; case (char)UnicodeCommand.VISUALBEEPMODE: // sadly, have to consume and ignore - no vt100 code for this, so it's not supported. break; case (char)UnicodeCommand.AUDIOBEEPMODE: // sadly, have to consume and ignore - no vt100 code for this. so it's not supported. break; default: sb.Append(t); // default passhtrough break; } break; } } return base.OutputConvert(sb.ToString()); }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) on output to what the terminal /// wants to see. /// Subclasses of this should perform their own manipulations, then fall-through /// to this base class implementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public override char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.TELEPORTCURSORCOL: pendingCol = t; outputExpected = ExpectNextChar.TELEPORTCURSORROW; break; case ExpectNextChar.TELEPORTCURSORROW: int row = t; // VT100 counts rows and cols starting at 1, not 0, thus the +1's below: sb.AppendFormat("{0}{1};{2}H", csi, (row + 1), (pendingCol + 1)); outputExpected = ExpectNextChar.NORMAL; break; default: switch (t) { case (char)UnicodeCommand.TELEPORTCURSOR: outputExpected = ExpectNextChar.TELEPORTCURSORCOL; break; case (char)UnicodeCommand.CLEARSCREEN: sb.AppendFormat("{0}2J{0}H", csi); break; case (char)UnicodeCommand.SCROLLSCREENUPONE: sb.AppendFormat("{0}S", csi); break; case (char)UnicodeCommand.SCROLLSCREENDOWNONE: sb.AppendFormat("{0}T", csi); break; case (char)UnicodeCommand.HOMECURSOR: sb.AppendFormat("{0}H", csi); break; case (char)UnicodeCommand.UPCURSORONE: sb.AppendFormat("{0}A", csi); break; case (char)UnicodeCommand.DOWNCURSORONE: sb.AppendFormat("{0}B", csi); break; case (char)UnicodeCommand.RIGHTCURSORONE: sb.AppendFormat("{0}C", csi); break; case (char)UnicodeCommand.LEFTCURSORONE: sb.AppendFormat("{0}D", csi); break; case (char)UnicodeCommand.DELETELEFT: sb.AppendFormat("{0}K", csi); break; case (char)UnicodeCommand.DELETERIGHT: sb.AppendFormat("{0}1K", csi); break; default: sb.Append(t); // default passhtrough break; } break; } } return(base.OutputConvert(sb.ToString())); }
/// <summary> /// Respond to one single input character in Unicode, using the pretend /// virtual Unicode terminal keycodes described in the UnicodeCommand enum. /// To keep things simple, all key input is coerced into single Unicode chars /// even if the actual keypress takes multiple characters to express in its /// native form (i.e. ESC [ A means left-arrow on a VT100 terminal. If /// a telnet is talking via VT100 codes, that ESC [ A will get converted into /// a single UnicdeCommand.LEFTCURSORONE character before being sent here.) /// <br/> /// This method is public because it is also how other mods should send input /// to the terminal if they want some other source to send simulated keystrokes. /// </summary> /// <param name="ch">The character, which might be a UnicodeCommand char</param> /// <param name="whichTelnet">If this came from a telnet session, which one did it come from? /// Set to null in order to say it wasn't from a telnet but was from the interactive GUI</param> public void ProcessOneInputChar(char ch, TelnetSingletonServer whichTelnet) { // Weird exceptions for multi-char data combos that would have been begun on previous calls to this method: switch (inputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = ch; inputExpected = ExpectNextChar.RESIZEHEIGHT; return; case ExpectNextChar.RESIZEHEIGHT: int height = ch; shared.Screen.SetSize(height, pendingWidth); inputExpected = ExpectNextChar.NORMAL; return; default: break; } // Printable ASCII section of Unicode - the common vanilla situation // (Idea: Since this is all Unicode anyway, should we allow a wider range to // include multi-language accent characters and so on? Answer: to do so we'd // first need to expand the font pictures in the font image file, so it's a // bigger task than it may first seem.) if (0x0020 <= ch && ch <= 0x007f) { Type(ch); } else { switch (ch) { // A few conversions from UnicodeCommand into those parts of ASCII that it // maps directly into nicely, otherwise just pass it through to SpecialKey(): case (char)UnicodeCommand.DELETELEFT: Type((char)8); break; case (char)UnicodeCommand.STARTNEXTLINE: Type('\r'); break; case '\t': Type('\t'); break; case (char)UnicodeCommand.RESIZESCREEN: inputExpected = ExpectNextChar.RESIZEWIDTH; break; // next expected char is the width. // Finish session: If GUI, then close window. If Telnet, then detatch from the session: case (char)0x0004 /*control-D*/: // How users of unix shells are used to doing this. case (char)0x0018 /*control-X*/: // How kOS did it in the past in the GUI window. if (shared.Interpreter.IsAtStartOfCommand()) { if (whichTelnet == null) { Close(); } else { whichTelnet.DisconnectFromProcessor(); } } break; // User asking for redraw (Unity already requires that we continually redraw the GUI Terminal, so this is only meaningful for telnet): case (char)UnicodeCommand.REQUESTREPAINT: if (whichTelnet != null) { ResizeAndRepaintTelnet(whichTelnet, shared.Screen.ColumnCount, shared.Screen.RowCount, true); } break; // Typical case is to just let SpecialKey do the work: default: SpecialKey(ch); break; } } // else ignore it - unimplemented char. }
/// <summary> /// Map the Unicode chars (and the fake control codes we made) into what the terminal /// wants to see. /// In this base class, all it does is just mostly passthru things as-is with no /// conversions. /// Subclasses of this should perform their own manipulations, then fallthrough /// to this base class inmplementation at the bottom, to allow chains of /// subclasses to all operate on the data. /// </summary> /// <param name="str">Unicode char</param> /// <returns>raw byte stream to send to the terminal</returns> public virtual char[] OutputConvert(string str) { StringBuilder sb = new StringBuilder(); foreach (char t in str) { switch (outputExpected) { case ExpectNextChar.RESIZEWIDTH: pendingWidth = t; outputExpected = ExpectNextChar.RESIZEHEIGHT; break; case ExpectNextChar.RESIZEHEIGHT: int height = t; sb.Append("{Please resize to " + pendingWidth + "x" + height + "}"); // By default, assume the terminal has no such control code, but this can be overridden. outputExpected = ExpectNextChar.NORMAL; break; case ExpectNextChar.INTITLE: // Default behavior: Ignore all content until the title ender. Assume most terminals don't know how to do this. if (t == (char)UnicodeCommand.TITLEEND) outputExpected = ExpectNextChar.NORMAL; break; default: switch (t) { case (char)UnicodeCommand.RESIZESCREEN: outputExpected = ExpectNextChar.RESIZEWIDTH; break; case (char)UnicodeCommand.TITLEBEGIN: outputExpected = ExpectNextChar.INTITLE; break; case (char)UnicodeCommand.STARTNEXTLINE: sb.Append("\r\n"); break; case (char)UnicodeCommand.LINEFEEDKEEPCOL: sb.Append("\n"); break; case (char)UnicodeCommand.GOTOLEFTEDGE: sb.Append("\r"); break; default: sb.Append(t); // default passhtrough break; } break; } } // By this point, any UnicodeCommand chars still left must be un-mapped by any of the mappers: if (!AllowNativeUnicodeCommands) StripUnicodeCommands(sb); return sb.ToString().ToCharArray(); }