/// <summary> /// - Processes a character event into an Action that occurs while in the DcsParam state. /// Events in this state will: /// 1. Ignore C0 control characters /// 2. Ignore Delete characters /// 3. Collect DCS parameter data /// 4. Enter DcsIntermediate if we see an intermediate /// 5. Begin to ignore all remaining parameters when an invalid character is detected (DcsIgnore) /// 6. Dispatch the Final character in preparation for parsing the data string /// </summary> /// <param name="ch"></param> private void EventDCSParam(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsNumericParamValue(ch) || ASCIIChars.IsParameterDelimiter(ch)) { this.ActionParam(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionCollect(ch); this.EnterDCSIntermediate(); } else if (ASCIIChars.IsParameterInvalid(ch)) { this.EnterDCSIgnore(); } else { this.ActionDCSDispatch(ch); } }
/// <summary> /// 当状态改变为Ground的时候触发 /// </summary> /// <param name="ch"></param> private void EventGround(byte ch) { if (ASCIIChars.IsC0Code(ch) || ASCIIChars.IsDelete(ch)) { // 如果是C0控制字符和Delete字符,说明要执行动作 this.ActionExecute(ch); } else if (ASCIIChars.IsPrintable(ch)) { // 其他字符直接打印 this.ActionPrint(ch); } else { // 不是可见字符,当多字节字符处理,用UTF8编码 // UTF8参考:https://www.cnblogs.com/fnlingnzb-learner/p/6163205.html if (this.unicodeText.Count == 0) { bool bit6 = BytesExtentions.GetBit(ch, 5); this.unicodeText.Capacity = bit6 ? 3 : 2; } this.unicodeText.Add(ch); if (this.unicodeText.Count == this.unicodeText.Capacity) { string text = Encoding.UTF8.GetString(this.unicodeText.ToArray()); this.ActionPrint(text); this.unicodeText.Clear(); } } }
/// <summary> /// - Processes a character event into an Action that occurs while in the CsiEntry state. /// Events in this state will: /// 1. Execute C0 control characters /// 2. Ignore Delete characters /// 3. Collect Intermediate characters /// 4. Begin to ignore all remaining parameters when an invalid character is detected (CsiIgnore) /// 5. Store parameter data /// 6. Collect Control Sequence Private markers /// 7. Dispatch a control sequence with parameters for action /// </summary> /// <param name="ch"></param> private void EventCSIEntry(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionExecute(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionCollect(ch); this.EnterCSIIntermediate(); } else if (ASCIIChars.IsCSIInvalid(ch)) { this.EnterCSIIgnore(); } else if (ASCIIChars.IsNumericParamValue(ch) || ASCIIChars.IsParameterDelimiter(ch)) { this.ActionParam(ch); this.EnterCSIParam(); } else if (ASCIIChars.IsCSIPrivateMarker(ch)) { this.ActionCollect(ch); this.EnterCSIParam(); } else { this.ActionCSIDispatch(ch); this.EnterGround(); } }
/// <summary> /// - Processes a character event into a Action that occurs while in the OscParam state. /// Events in this state will: /// 1. Trigger the OSC action associated with the param on an OscTerminator /// 2. If we see a ESC, enter the OscTermination state. We'll wait for one /// more character before we dispatch the string. /// 3. Ignore OscInvalid characters. /// 4. Collect everything else into the OscString /// </summary> /// <param name="ch"></param> private void EventOSCString(byte ch) { if (ASCIIChars.IsOSCTerminator(ch)) { // 出现了OSC结束符,那么进入Ground状态 this.ActionOSCDispatch(ch); this.EnterGround(); } else if (ASCIIChars.IsEscape(ch)) { // OSC状态下出现了ESC字符,那么有两种情况会出现: // 1. ESC后面有ST字符,说明是OSC状态结束了 // 2. ESC后面没有ST字符,说明是ESC状态 // 所以这里定义一个OSCTermination状态来处理这两种状态 this.EnterOSCTermination(); } else if (ASCIIChars.IsOSCIndicator(ch)) { // OSC非法字符,忽略 this.ActionIgnore(ch); } else { // 剩下的就是OSC的有效字符,收集 this.oscString.Append((char)ch); } }
/// <summary> /// - Processes a character event into an Action that occurs while in the EscapeIntermediate state. /// Events in this state will: /// 1. Execute C0 control characters /// 2. Ignore Delete characters /// 3. Collect Intermediate characters /// 4. Dispatch an Escape action. /// </summary> /// <param name="ch"></param> private void EventEscapeIntermediate(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionExecute(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionCollect(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (this.isAnsiMode) { this.ActionEscDispatch(ch); this.EnterGround(); } else if (ASCIIChars.IsVt52CursorAddress(ch)) { this.EnterVt52Param(); } else { this.ActionVt52EscDispatch(ch); this.EnterGround(); } }
/// <summary> /// 当状态变成Escape的时候触发 /// </summary> /// <param name="ch"></param> private void EventEscape(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionExecute(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionCollect(ch); this.EnterEscapeIntermediate(); } else if (this.isAnsiMode) { if (ASCIIChars.IsCSIIndicator(ch)) { // 0x5B,进入到了csi entry状态 this.EnterCSIEntry(); } else if (ASCIIChars.IsOSCIndicator(ch)) { // 0x5D,进入到了osc状态 this.EnterOSCParam(); } else if (ASCIIChars.IsDCSIndicator(ch)) { // 0x50,进入到了dcs状态 this.EnterDCSEntry(); } else { this.ActionEscDispatch(ch); this.EnterGround(); } } else if (ASCIIChars.IsVt52CursorAddress(ch)) { // 判断是否是VT52模式下的移动光标指令, 当进入了VT52模式下才会触发 // 在VT52模式下只有移动光标的指令有参数,所以这里把移动光标的指令单独做处理 this.EnterVt52Param(); } else { // 这里是其他的不带参数的VT52控制字符 this.ActionVt52EscDispatch(ch); this.EnterGround(); } }
/// <summary> /// - Processes a character event into an Action that occurs while in the DcsPassThrough state. /// Events in this state will: /// 1. Pass through if character is valid. /// 2. Ignore everything else. /// The termination state is handled outside when an ESC is seen. /// </summary> /// <param name="ch"></param> private void EventDCSPassThrough(byte ch) { if (ASCIIChars.IsC0Code(ch) || ASCIIChars.IsDCSPassThroughValid(ch)) { if (!this.dcsStringHandler(ch)) { this.EnterDCSIgnore(); } } else { this.ActionIgnore(ch); } }
/// <summary> /// - Handle the two-character termination of a OSC sequence. /// Events in this state will: /// 1. Trigger the OSC action associated with the param on an OscTerminator /// 2. Otherwise treat this as a normal escape character event. /// </summary> /// <param name="ch"></param> private void EventOSCTermination(byte ch) { if (ASCIIChars.IsStringTermination(ch)) { // OSC状态下出现了ESC后,后面紧跟着ST字符,说明是OSC状态结束了 this.ActionOSCDispatch(ch); this.EnterGround(); } else { // OSC状态下出现了ESC后,后面没有ST字符,说明要Cancel OSC状态并直接进入ESC模式 this.EnterEscape(); this.EventEscape(ch); } }
/// <summary> /// 收集CSI状态下的Parameter字符 /// - Triggers the Param action to indicate that the state machine should store this character as a part of a parameter /// to a control sequence. /// </summary> /// <param name="ch"></param> private void ActionParam(byte ch) { if (this.parameters.Count == 0) { this.parameters.Add(0); } if (ASCIIChars.IsParameterDelimiter(ch)) { this.parameters.Add(0); } else { int last = this.parameters.Last(); this.parameters[this.parameters.Count - 1] = this.AccumulateTo(ch, last); } }
/// <summary> /// - Processes a character event into an Action that occurs while in the DcsIntermediate state. /// Events in this state will: /// 1. Ignore C0 control characters /// 2. Ignore Delete characters /// 3. Collect intermediate data. /// 4. Begin to ignore all remaining intermediates when an invalid character is detected (DcsIgnore) /// 5. Dispatch the Final character in preparation for parsing the data string /// </summary> /// <param name="ch"></param> private void EventDCSIntermediate(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionCollect(ch); } else if (ASCIIChars.IsIntermediateInvalid(ch)) { this.EnterDCSIgnore(); } else { this.ActionDCSDispatch(ch); } }
/// <summary> /// Processes a character event into an Action that occurs while in the CsiIgnore state. /// Events in this state will: /// 1. Execute C0 control characters /// 2. Ignore Delete characters /// 3. Collect Intermediate characters /// 4. Begin to ignore all remaining parameters when an invalid character is detected (CsiIgnore) /// 5. Return to Ground /// </summary> /// <param name="ch"></param> private void EventCSIIgnore(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionExecute(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsIntermediate(ch)) { this.ActionIgnore(ch); } else if (ASCIIChars.IsIntermediateInvalid(ch)) { this.ActionIgnore(ch); } else { this.EnterGround(); } }
/// <summary> /// 进入到了OSC状态,开始解析OSC命令 /// </summary> /// <param name="ch"></param> private void EventOSCParam(byte ch) { if (ASCIIChars.IsOSCTerminator(ch)) { // OSC状态下出现了BEL结束符 // 参考terminal的做法,进入Ground状态 this.EnterGround(); } else if (ASCIIChars.IsNumericParamValue(ch)) { // OSC状态下的数字,收集起来 this.ActionOSCParam(ch); } else if (ASCIIChars.IsOSCDelimiter(ch)) { // OSC状态下出现了分隔符,说明要开始收集字符串了 this.EnterOSCString(); } else { // 其他所有的字符都忽略 this.ActionIgnore(ch); } }
/// <summary> /// - Processes a character event into an Action that occurs while in the Vt52Param state. /// Events in this state will: /// 1. Execute C0 control characters /// 2. Ignore Delete characters /// 3. Store exactly two parameter characters /// 4. Dispatch a control sequence with parameters for action (always Direct Cursor Address) /// </summary> /// <param name="ch"></param> private void EventVt52Param(byte ch) { if (ASCIIChars.IsC0Code(ch)) { this.ActionExecute(ch); } else if (ASCIIChars.IsDelete(ch)) { this.ActionIgnore(ch); } else { this.parameters.Add(ch); if (this.parameters.Count == 2) { // The command character is processed before the parameter values, // but it will always be 'Y', the Direct Cursor Address command. // 到了这里说明Y指令的参数收集完了,可以执行了,因为Y指令是移动光标指令,有且只有两个参数 this.ActionVt52EscDispatch((byte)'Y'); this.EnterGround(); } } }
/// <summary> /// 解析终端字节流 /// </summary> /// <param name="bytes">要解析的字节流</param> public void ProcessCharacters(byte[] bytes) { int length = bytes.Length; for (int i = 0; i < length; i++) { byte ch = bytes[i]; // 在OSCString的状态下,ESC转义字符可以用作OSC状态的结束符,所以在这里不进入ESC状态 if (ASCIIChars.IsEscape(ch) && this.state != VTStates.OSCString) { this.EnterEscape(); } else { switch (this.state) { case VTStates.Ground: { this.EventGround(ch); break; } case VTStates.Escape: { this.EventEscape(ch); break; } case VTStates.EscapeIntermediate: { this.EventEscapeIntermediate(ch); break; } case VTStates.OSCParam: { this.EventOSCParam(ch); break; } case VTStates.OSCString: { this.EventOSCString(ch); break; } case VTStates.OSCTermination: { this.EventOSCTermination(ch); break; } case VTStates.CSIEntry: { this.EventCSIEntry(ch); break; } case VTStates.CSIIntermediate: { this.EventCSIIntermediate(ch); break; } case VTStates.CSIIgnore: { this.EventCSIIgnore(ch); break; } case VTStates.CSIParam: { this.EventCSIParam(ch); break; } case VTStates.DCSEntry: { this.EventDCSEntry(ch); break; } case VTStates.DCSIgnore: { this.EventDCSIgnore(ch); break; } case VTStates.DCSIntermediate: { this.EventDCSIntermediate(ch); break; } case VTStates.DCSParam: { this.EventDCSParam(ch); break; } case VTStates.DCSPassthrough: { this.EventDCSPassThrough(ch); break; } case VTStates.Vt52Param: { this.EventVt52Param(ch); break; } } } } }