Send the DCS passthrough sequence to the engine #10196

Closed
opened 2026-01-31 02:15:02 +00:00 by claunia · 9 comments
Owner

Originally created by @skyline75489 on GitHub (Aug 17, 2020).

Description of the new feature/enhancement

This is a followup of #6328 . Right now VT DCS sequences are recoginzed and sliently ignored. This is about actually doing something about it.

See also #120 #448 .

Originally created by @skyline75489 on GitHub (Aug 17, 2020). <!-- 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING: 1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement. 2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement. 3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number). 4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement. 5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement. All good? Then proceed! --> # Description of the new feature/enhancement This is a followup of #6328 . Right now VT DCS sequences are recoginzed and sliently ignored. This is about actually doing something about it. See also #120 #448 . <!-- A clear and concise description of what the problem is that the new feature would solve. Describe why and how a user would use this new functionality (if applicable). -->
Author
Owner

@zadjii-msft commented on GitHub (Aug 17, 2020):

I'm yanking triage off this one because yea duh we should do this. Thanks for filing!

@zadjii-msft commented on GitHub (Aug 17, 2020): I'm yanking triage off this one because _yea duh we should do this_. Thanks for filing!
Author
Owner

@skyline75489 commented on GitHub (Aug 30, 2020):

I've beening trying to make this work like what we did with OSC, that is collecting all the pass through character into a string named _dcsDataString and send it to engine when the DCS sequences terminates. The implementation is straight forward:

void StateMachine::_ActionDcsPassThrough(const wchar_t wch)
{
    _trace.TraceOnAction(L"DcsPassThrough");
    _trace.TraceOnExecute(wch);
    if (!_isDcsPassingThrough)
    {
        // The first character being passed through is the "final character", which combined with intermediates
        // defines the functionality of the DCS sequence. Here we treat it as part of the identifier.
        _identifier.AddIntermediate(wch);
        _isDcsPassingThrough = true;
    }
    else
    {
        _dcsDataString.push_back(wch);
    }
}

void StateMachine::_EventDcsTermination(const wchar_t wch)
{
    _trace.TraceOnEvent(L"DcsTermination");

    if (_isStringTerminatorIndicator(wch))
    {

        const auto success = _engine->ActionDcsDispatch(_identifier.Finalize(),
                                                        { _parameters.data(), _parameters.size() },
                                                        _dcsDataString);
        if (!success)
        {
            TermTelemetry::Instance().LogFailed(wch);
        }

        _EnterGround();
    }
    else
    {
        _EnterEscape();
        _EventEscape(wch);
    }
}

But when dealing with large sixel image outputs, the string collecting itself takes seconds to complete. I'm thinking maybe a direct pass through to the engine should help with the performance.

@skyline75489 commented on GitHub (Aug 30, 2020): I've beening trying to make this work like what we did with OSC, that is collecting all the pass through character into a string named `_dcsDataString` and send it to engine when the DCS sequences terminates. The implementation is straight forward: ```cpp void StateMachine::_ActionDcsPassThrough(const wchar_t wch) { _trace.TraceOnAction(L"DcsPassThrough"); _trace.TraceOnExecute(wch); if (!_isDcsPassingThrough) { // The first character being passed through is the "final character", which combined with intermediates // defines the functionality of the DCS sequence. Here we treat it as part of the identifier. _identifier.AddIntermediate(wch); _isDcsPassingThrough = true; } else { _dcsDataString.push_back(wch); } } ``` ```cpp void StateMachine::_EventDcsTermination(const wchar_t wch) { _trace.TraceOnEvent(L"DcsTermination"); if (_isStringTerminatorIndicator(wch)) { const auto success = _engine->ActionDcsDispatch(_identifier.Finalize(), { _parameters.data(), _parameters.size() }, _dcsDataString); if (!success) { TermTelemetry::Instance().LogFailed(wch); } _EnterGround(); } else { _EnterEscape(); _EventEscape(wch); } } ``` But when dealing with large sixel image outputs, the string collecting itself takes seconds to complete. I'm thinking maybe a direct pass through to the engine should help with the performance.
Author
Owner

@skyline75489 commented on GitHub (Sep 15, 2020):

Note from @j4james originally written in https://github.com/microsoft/terminal/pull/7578#discussion_r487517730

My assumption was that the parsing for the DCS command string would be handled in the dispatch classes - I don't think the state machine should need to know about all the different sequence formats. Once it's identified the operation from the final character, I think it should be streaming the command string straight through to the adapter so it can be processed immediately as the data arrives.

In the case of Sixel graphics, this would allow the adapter to render the image straight to the screen as the pixels are received. I think there are other DCS sequences, like music operations, that would have similar requirements. And yes, OSC might fall into this category too.

For the majority of simple operations that don't require streaming, though, there could be a default handler that just gathers everything up in a string, and passes that along once the string terminator is received.

@skyline75489 commented on GitHub (Sep 15, 2020): Note from @j4james originally written in https://github.com/microsoft/terminal/pull/7578#discussion_r487517730 >My assumption was that the parsing for the DCS command string would be handled in the dispatch classes - I don't think the state machine should need to know about all the different sequence formats. Once it's identified the operation from the final character, I think it should be streaming the command string straight through to the adapter so it can be processed immediately as the data arrives. >In the case of Sixel graphics, this would allow the adapter to render the image straight to the screen as the pixels are received. I think there are other DCS sequences, like music operations, that would have similar requirements. And yes, OSC might fall into this category too. >For the majority of simple operations that don't require streaming, though, there could be a default handler that just gathers everything up in a string, and passes that along once the string terminator is received.
Author
Owner

@j4james commented on GitHub (Sep 15, 2020):

So what I had in mind was that the state machine would dispatch any of the command string sequences (DCS, APC, etc.) as soon as it received the "final" character and could generate a full VTID. The dispatch method would not be able to process the command at that point, but based on the id it would return an instance of a consumer class. The state machine would save a copy of that, and pass on every subsequent character to that consumer until it received a string terminator, or some kind of error/abort state. At that point it would notify the consumer that it had reached the end of message and the command could be processed (or aborted).

If the dispatcher didn't recognize the VTID, it could return a kind of null consumer that would just ignore everything without wasting memory collecting bytes that were never going to be used. If it was a simple operation that just wanted the final string, it could return a generic consumer that would handle all the data collection automatically (similar to what is currently done with OSC), and then trigger a specified callback function/lambda with the final content. But for something like Sixel, which needs full control of the data, it would return a custom consumer class that could process each character as it was received.

OSC could potentially also follow this pattern, although the initial dispatching is more complicated because of the way the commands are identified. So perhaps that's something that's best left for a follow-up PR, once we've got the basic concept working. Another reason being it's going require a bunch of refactoring of all the existing OSC sequences, since the command string parsing would now be in the dispatch class rather than the state machine.

@j4james commented on GitHub (Sep 15, 2020): So what I had in mind was that the state machine would dispatch any of the command string sequences (DCS, APC, etc.) as soon as it received the "final" character and could generate a full VTID. The dispatch method would not be able to process the command at that point, but based on the id it would return an instance of a consumer class. The state machine would save a copy of that, and pass on every subsequent character to that consumer until it received a string terminator, or some kind of error/abort state. At that point it would notify the consumer that it had reached the end of message and the command could be processed (or aborted). If the dispatcher didn't recognize the VTID, it could return a kind of null consumer that would just ignore everything without wasting memory collecting bytes that were never going to be used. If it was a simple operation that just wanted the final string, it could return a generic consumer that would handle all the data collection automatically (similar to what is currently done with OSC), and then trigger a specified callback function/lambda with the final content. But for something like Sixel, which needs full control of the data, it would return a custom consumer class that could process each character as it was received. OSC could potentially also follow this pattern, although the initial dispatching is more complicated because of the way the commands are identified. So perhaps that's something that's best left for a follow-up PR, once we've got the basic concept working. Another reason being it's going require a bunch of refactoring of all the existing OSC sequences, since the command string parsing would now be in the dispatch class rather than the state machine.
Author
Owner

@j4james commented on GitHub (Oct 10, 2020):

@skyline75489 Just as a follow up to your comment on the Sixel issue, I want to be clear that this DCS pass through thing is not something I'm currently working on, in case you were waiting on me. If nobody else takes it on, I will likely get to it eventually, because there are a whole lot of DCS operations I'd love to implement. But for now I've got other issues I want to tackle first. I also figured you're probably the best person to handle this at the moment, because the Sixel requirements will probably be key to shaping the API.

@j4james commented on GitHub (Oct 10, 2020): @skyline75489 Just as a follow up to your comment on the Sixel issue, I want to be clear that this DCS pass through thing is not something I'm currently working on, in case you were waiting on me. If nobody else takes it on, I will likely get to it eventually, because there are a whole lot of DCS operations I'd love to implement. But for now I've got other issues I want to tackle first. I also figured you're probably the best person to handle this at the moment, because the Sixel requirements will probably be key to shaping the API.
Author
Owner

@skyline75489 commented on GitHub (Oct 11, 2020):

@j4james I hear you loud and clear. Thanks for inspiring comments both in this thread and in #448 . I was stuck with my unfinished sixel implementation about a month ago, so I moved on to those OSC things. I think I'll give DCS/sixel another try when I have time.

@skyline75489 commented on GitHub (Oct 11, 2020): @j4james I hear you loud and clear. Thanks for inspiring comments both in this thread and in #448 . I was stuck with my unfinished sixel implementation about a month ago, so I moved on to those OSC things. I think I'll give DCS/sixel another try when I have time.
Author
Owner

@j4james commented on GitHub (Feb 18, 2021):

@skyline75489 If you aren't working on this, I'd be happy to take it on now. I've started working on the "soft fonts" feature (issue #9164) which has similar DCS requirements to Sixel, so I thought it would make a good test case for this.

For the "consumer class" that I mentioned in my initial proposal above, I realised we could probably get by with a simple std::function<bool(wchar_t)>, and then the dispatch handler could just return a lambda without necessarily requiring a separate class.

The way it would work, the state machine would just pass through all the characters from the DCS string to the returned function, and could indicate the end of the sequence by sending through an ST character. If we need to differentiate an abort from a successful termination, we could also send through a CAN control character, but I'm not sure that's really necessary.

@j4james commented on GitHub (Feb 18, 2021): @skyline75489 If you aren't working on this, I'd be happy to take it on now. I've started working on the "soft fonts" feature (issue #9164) which has similar `DCS` requirements to Sixel, so I thought it would make a good test case for this. For the "consumer class" that I mentioned in my initial proposal above, I realised we could probably get by with a simple `std::function<bool(wchar_t)>`, and then the dispatch handler could just return a lambda without necessarily requiring a separate class. The way it would work, the state machine would just pass through all the characters from the `DCS` string to the returned function, and could indicate the end of the sequence by sending through an `ST` character. If we need to differentiate an abort from a successful termination, we could also send through a `CAN` control character, but I'm not sure that's really necessary.
Author
Owner

@skyline75489 commented on GitHub (Feb 18, 2021):

Sure, go ahead 😄

I’m experimenting with DX renderer at the moment.

获取 Outlook for iOShttps://aka.ms/o0ukef

@skyline75489 commented on GitHub (Feb 18, 2021): Sure, go ahead 😄 I’m experimenting with DX renderer at the moment. 获取 Outlook for iOS<https://aka.ms/o0ukef>
Author
Owner

@ghost commented on GitHub (May 25, 2021):

:tada:This issue was addressed in #9307, which has now been successfully released as Windows Terminal Preview v1.9.1445.0.🎉

Handy links:

@ghost commented on GitHub (May 25, 2021): :tada:This issue was addressed in #9307, which has now been successfully released as `Windows Terminal Preview v1.9.1445.0`.:tada: Handy links: * [Release Notes](https://github.com/microsoft/terminal/releases/tag/v1.9.1445.0) * [Store Download](https://www.microsoft.com/store/apps/9n8g5rfz9xk3?cid=storebadge&ocid=badge)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#10196