/// <summary> /// 解析CSI类命令 /// </summary> /// <param name="data"></param> bool ParseCSICommand(RingQueue <byte> data) { /** * 命令基本为字母结尾 * h: 模式设定(SET) * l: 模式设定(RESET) * A: 光标上移指定行 CSI [num] A * B: 光标下移指定行 CSI [num] B * C: 光标左移指定列 CSI [num] C * D: 光标右移指定列 CSI [num] D * H: 指定光标位置 CSI [num|column] ; [num|row] H * f: 同H * g: 清除一个水平Tab停止位置 CSI [num] g * null/0: 清除当前位置的水平Tab停止 * 3:清除所有 * m: 设置图形渲染模式 CSI [num] ; [num] ... m * 0/null: 关闭所有 * 1: 粗体 * 4: 下划线 * 5: 闪烁 * 7: 反转显示 * 2 2: 一般 * 2 4: 不显示下划线 * 2 5: 不显示闪烁 * 2 7: 不反转 * L: 光标指定位置插入指定行 CSI [num] L * M: 从光标所在行开始删除指定行 CSI [num] M * @: 从光标当前位置插入指定个字符(仅VT200) CSI [num] @ * P: 从光标位置开始删除指定个字符 CSI [num] P * K: 删除字符 CSI [num] K * null/0: 删除光标所在行右侧的字符(包含光标字符) * 1: 删除光标所在行左侧的字符(包含光标字符) * 2: 删除整行 * * ? null/0: 删除光标所在行右侧的字符(包含光标字符|仅VT200) * ? 1: 删除光标所在行左侧的字符(包含光标字符|仅VT200) * ? 2: 删除整行(仅VT200) * J: 删除字符 CSI [num] J * null/0: 删除光标到屏幕结束的字符(包含光标字符) * 1: 删除光标到屏幕开始的字符(包含光标字符) * 2: 清除屏幕 * r: 设置上下的页边距 CSI [top] ; [bottom] r * i: 打印设定 CSI [num] i * ? 5: 开启自动打印模式 * ? 4: 关闭自动打印模式 * 5: 开启打印控制模式 * 4: 关闭打印控制模式 * ? 1: 打印当前行 * null/0: 打印当前屏幕 * */ while (!Encoding.ASCII.GetBytes("hlABCDHgmLMPJK@rif").Contains(data.GetNextValue()) && data.Current != data.FOOT) { ; } if (!Encoding.ASCII.GetBytes("hlABCDHgmLMPJK@rif").Contains(data.Value)) { return(false); } var cmdbytes = data.LTrim().Select(o => Convert.ToByte(o)).ToArray(); var cmd = Encoding.ASCII.GetString(cmdbytes, 2, cmdbytes.Length - 3); switch (cmdbytes.Last()) { case 0x66: //f if (cmdbytes.Length > 3) { if (cmd == ";") { Screen.CursorSetPos(0, 0); } else { var wh = cmd.Split(';'); wh[0] = wh[0] == "" ? "1" : wh[0]; wh[1] = wh[1] == "" ? "1" : wh[1]; Screen.CursorSetPos(int.Parse(wh[0]) - 1, int.Parse(wh[1]) - 1); } } break; case 0x48: //H if (cmdbytes.Length > 3) { if (cmd == ";") { Screen.CursorSetPos(0, 0); } else { var wh = cmd.Split(';'); Screen.CursorSetPos(int.Parse(wh[0]) - 1, int.Parse(wh[1]) - 1); } } break; case 0x4A: //J if (cmdbytes.Length == 3) { Screen.ScreenClearAfterCursor(); } else { switch (cmd) { case "0": Screen.ScreenClearAfterCursor(); break; case "1": Screen.ScreenClearBeforeCursor(); break; case "2": Screen.ScreenClear(); break; } } break; case 0x4B: //K if (cmdbytes.Length == 3) { Screen.LineClearAfterCursor(); } else { switch (cmd) { case "0": Screen.LineClearAfterCursor(); break; case "1": Screen.LineClearBeforeCursor(); break; case "2": Screen.LineClear(); break; } } break; case 0x68: //h Logger.Debug("模式设定(SET):" + cmd.Substring(1)); break; case 0x6C: //l Logger.Debug("模式设定(RESET):" + cmd.Substring(1)); break; case 0x6D: //m if (cmdbytes.Length == 3) { Screen.IsBold = false; Screen.IsUnderline = false; Screen.IsBlinking = false; Screen.IsReverse = false; } else { foreach (var v in cmd.Split(';')) { switch (v) { case "": case "0": Screen.IsBold = false; Screen.IsUnderline = false; Screen.IsBlinking = false; Screen.IsReverse = false; break; case "1": Screen.IsBold = true; break; case "4": Screen.IsUnderline = true; break; case "5": Screen.IsBlinking = true; break; case "7": Screen.IsReverse = true; break; case "22": Screen.IsBold = false; break; case "24": Screen.IsUnderline = false; break; case "25": Screen.IsBlinking = false; break; case "27": Screen.IsReverse = false; break; } } } Logger.Debug("样式渲染:" + cmd); break; case 0x69: // i if (cmdbytes.Length == 3) { Logger.Debug("打印当前屏幕"); } else { switch (cmd) { case "5": if (PrintFileName == "") { PrintFileName = Environment.CurrentDirectory + "\\print.txt"; } OnBeginPrint(new PrintEventArgs(PrintFileName)); IsPrinting = true; Output = new System.IO.FileStream(PrintFileName, System.IO.FileMode.Create); TickCount = Environment.TickCount; Logger.Warn(string.Format("开始输出打印数据({0})", PrintFileName)); break; case "4": Logger.Warn("输出打印数据完成"); IsPrinting = false; Output.Flush(); Output.Close(); Output = null; OnEndPrint(new PrintEventArgs(PrintFileName)); Logger.Info("共耗时: " + (Environment.TickCount - TickCount) / 1000.0F + " 秒"); break; } } break; default: Logger.Error("无法识别CSI指令: " + Encoding.ASCII.GetString(cmdbytes)); break; } return(true); }
/// <summary> /// 处理VT220协议数据 /// </summary> /// <param name="data"></param> void ParseVT220Command(RingQueue <byte> data) { while (data.Count > 0) { var b = data.GetFirstValue(); if (b == ESC) { if (data.Count < 2) { break; } /** * 第二指令说明: ESC [opt] * * N: 转交SS2命令处理 * O: 转交SS3命令处理 * P: 转交DCS命令处理 * [: 转交CSI命令处理 * \: 转交ST命令处理 * D: 光标向下移动一行(同IND命令),若光标在底部则内容向上滚动 * M: 光标向上移动一行(同RI命令),若光标在顶部则内容向下滚动 * E: 光标移动到下一行首位(同NEL命令),若光标在底部则内容向上滚动 * 7: 保存光标状态(光标位置,图形渲染,字符偏移状态,自动换行,参考点,删除内容区域) * 8: 重置光标状态 * H: 设置水平Tab光标停留位置(同HTS命令) * #: 行属性 * ESC # 3 上半部 * ESC # 4 下半部 * ESC # 5 单倍宽度 * ESC # 6 双倍宽度 * c: 硬重置终端 * =: 键盘模式(应用模式) * >:键盘模式(数字模式) * (: G0字符集 ESC ( [final] * ): G1字符集 ESC ) [final] * *: G2字符集 ESC * [final] * +: G3字符集 ESC + [final] */ switch (data.GetNextValue()) { case 0x5B: // [ ==> CSI if (!ParseCSICommand(data)) { return; } break; #region 编码集设定 case 0x28: // ( //Console.WriteLine("G0 " + data.GetNextValue().ToString()); Logger.Debug("编码集设定: " + "G0 " + data.GetNextValue().ToString()); Screen.Charset0 = ParseCharsets(data.Value); data.LTrim(); break; case 0x29: // ) Logger.Debug("编码集设定: " + "G1 " + data.GetNextValue().ToString()); //Console.WriteLine("G1 " + data.GetNextValue().ToString()); Screen.Charset1 = ParseCharsets(data.Value); data.LTrim(); break; case 0x2A: // * Logger.Debug("编码集设定: " + "G2 " + data.GetNextValue().ToString()); //Console.WriteLine("G2 " + data.GetNextValue().ToString()); Screen.Charset2 = ParseCharsets(data.Value); data.LTrim(); break; case 0x2B: // + Logger.Debug("编码集设定: " + "G3 " + data.GetNextValue().ToString()); //Console.WriteLine("G3 " + data.GetNextValue().ToString()); Screen.Charset3 = ParseCharsets(data.Value); data.LTrim(); break; #endregion case 0x3E: // > 键盘模式(数字键盘) 参考4.6.18 Logger.Debug("键盘模式:数字模式"); //Console.WriteLine("键盘模式:数字模式"); data.LTrim(); break; } } else if (b == 0x0F) //LS0 将G0字符集映射到GL { Logger.Debug("G0字符集映射到GL"); Screen.Charset = Screen.Charset0; data.LTrim(); } else if (b == 0x0E) //LS1 将G1字符集映射到GL { Logger.Debug("G1字符集映射到GL"); Screen.Charset = Screen.Charset1; data.LTrim(); } else if (b == 0x07) //Beep { Console.Beep(250, 100); data.LTrim(); } else if (b == 0x08) //退格 { var pos = Screen.CursorPos; pos.X--; Screen.CursorPos = pos; Screen.WriteByte(0); Screen.CursorPos = pos; data.LTrim(); } else { data.LTrim(); if (b != 0) { if (IsPrinting) { //输出到文件 Output.WriteByte(b); } else { Screen.WriteByte(b); } } } } }