Implement ConEmu's OSC 9;4 to set the taskbar progress indicator (#8055)

This commit implements the OSC 9;4 sequence per the [ConEmu style].

| sequence                   | description                                       |
| ------------               | ------------                                      |
| `ESC ] 9 ; 4 ; st ; pr ST` | Set progress state on taskbar and tab.            |
|                            | When `st` is:                                     |
|                            |                                                   |
|                            | `0`: remove progress.                             |
|                            | `1`: set progress value to `pr` (number, 0-100).  |
|                            | `2`: set the taskbar to the "Error" state         |
|                            | `3`: set the taskbar to the "Indeterminate" state |
|                            | `4`: set the taskbar to the "Warning" state       |

We've also extended this with:
* st 3: set indeterminate state
* st 4: set paused state

We handle multiple tabs sending the sequence by using the the last focused
control's taskbar state/progress.

Upon receiving the sequence in `TerminalApi`, we send an event that gets caught
by `TerminalPage`. `TerminalPage` then fires another event that gets caught by
`AppHost` and that's where we set the taskbar progress. 

Closes #3004 

[ConEmu style]: https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
This commit is contained in:
PankajBhojwani 2020-11-18 17:24:11 -05:00 committed by GitHub
parent c41e078e85
commit 16e8a84cfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 403 additions and 1 deletions

View File

@ -32,6 +32,8 @@ IInheritable
IMap
IObject
IStorage
ITaskbar
llabs
LCID
llabs
localtime
@ -42,6 +44,7 @@ NCHITTEST
NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
NOAGGREGATION
NOPROGRESS
NOREDIRECTIONBITMAP
oaidl
ocidl
@ -63,6 +66,7 @@ sregex
STDCPP
strchr
syscall
TBPF
THEMECHANGED
tmp
tx

View File

@ -1051,6 +1051,32 @@ namespace winrt::TerminalApp::implementation
}
}
// Method Description:
// - Gets the taskbar state value from the last active control
// Return Value:
// - The taskbar state of the last active control
size_t AppLogic::GetLastActiveControlTaskbarState()
{
if (_root)
{
return _root->GetLastActiveControlTaskbarState();
}
return {};
}
// Method Description:
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
size_t AppLogic::GetLastActiveControlTaskbarProgress()
{
if (_root)
{
return _root->GetLastActiveControlTaskbarProgress();
}
return {};
}
// Method Description:
// - Sets the initial commandline to process on startup, and attempts to
// parse it. Commands will be parsed into a list of ShortcutActions that

View File

@ -50,6 +50,9 @@ namespace winrt::TerminalApp::implementation
void WindowCloseButtonClicked();
size_t GetLastActiveControlTaskbarState();
size_t GetLastActiveControlTaskbarProgress();
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::UI::Xaml::Controls::ContentDialogResult> ShowDialog(winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
// -------------------------------- WinRT Events ---------------------------------
@ -110,6 +113,7 @@ namespace winrt::TerminalApp::implementation
FORWARDED_TYPED_EVENT(FocusModeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FocusModeChanged);
FORWARDED_TYPED_EVENT(FullscreenChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, FullscreenChanged);
FORWARDED_TYPED_EVENT(AlwaysOnTopChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, AlwaysOnTopChanged);
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
};
}

View File

@ -52,6 +52,9 @@ namespace TerminalApp
void TitlebarClicked();
void WindowCloseButtonClicked();
UInt64 GetLastActiveControlTaskbarState();
UInt64 GetLastActiveControlTaskbarProgress();
// See IDialogPresenter and TerminalPage's DialogPresenter for more
// information.
Windows.Foundation.IAsyncOperation<Windows.UI.Xaml.Controls.ContentDialogResult> ShowDialog(Windows.UI.Xaml.Controls.ContentDialog dialog);
@ -63,5 +66,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> FocusModeChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
}
}

View File

@ -1132,6 +1132,9 @@ namespace winrt::TerminalApp::implementation
term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler });
// Add an event handler for when the terminal wants to set a progress indicator on the taskbar
term.SetTaskbarProgress({ this, &TerminalPage::_SetTaskbarProgressHandler });
// Bind Tab events to the TermControl and the Tab's Pane
hostingTab.Initialize(term);
@ -1984,6 +1987,16 @@ namespace winrt::TerminalApp::implementation
return control.CopySelectionToClipboard(singleLine, formats);
}
// Method Description:
// - Send an event (which will be caught by AppHost) to set the progress indicator on the taskbar
// Arguments:
// - sender (not used)
// - eventArgs: the arguments specifying how to set the progress indicator
void TerminalPage::_SetTaskbarProgressHandler(const IInspectable /*sender*/, const IInspectable /*eventArgs*/)
{
_setTaskbarProgressHandlers(*this, nullptr);
}
// Method Description:
// - Paste text from the Windows Clipboard to the focused terminal
void TerminalPage::_PasteText()
@ -2365,6 +2378,32 @@ namespace winrt::TerminalApp::implementation
_dialogPresenter = dialogPresenter;
}
// Method Description:
// - Gets the taskbar state value from the last active control
// Return Value:
// - The taskbar state of the last active control
size_t TerminalPage::GetLastActiveControlTaskbarState()
{
if (auto control{ _GetActiveControl() })
{
return gsl::narrow_cast<size_t>(control.TaskbarState());
}
return {};
}
// Method Description:
// - Gets the taskbar progress value from the last active control
// Return Value:
// - The taskbar progress of the last active control
size_t TerminalPage::GetLastActiveControlTaskbarProgress()
{
if (auto control{ _GetActiveControl() })
{
return gsl::narrow_cast<size_t>(control.TaskbarProgress());
}
return {};
}
// Method Description:
// - This is the method that App will call when the titlebar
// has been clicked. It dismisses any open flyouts.
@ -2890,4 +2929,5 @@ namespace winrt::TerminalApp::implementation
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, FocusModeChanged, _focusModeChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, FullscreenChanged, _fullscreenChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, AlwaysOnTopChanged, _alwaysOnTopChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TerminalPage, SetTaskbarProgress, _setTaskbarProgressHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
}

View File

@ -71,6 +71,9 @@ namespace winrt::TerminalApp::implementation
winrt::TerminalApp::IDialogPresenter DialogPresenter() const;
void DialogPresenter(winrt::TerminalApp::IDialogPresenter dialogPresenter);
size_t GetLastActiveControlTaskbarState();
size_t GetLastActiveControlTaskbarProgress();
void ShowKeyboardServiceWarning();
winrt::hstring KeyboardServiceDisabledText();
@ -81,6 +84,7 @@ namespace winrt::TerminalApp::implementation
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(FocusModeChanged, _focusModeChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(FullscreenChanged, _fullscreenChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(AlwaysOnTopChanged, _alwaysOnTopChangedHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTaskbarProgress, _setTaskbarProgressHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
TYPED_EVENT(Initialized, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
private:
@ -195,6 +199,8 @@ namespace winrt::TerminalApp::implementation
void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri);
bool _CopyText(const bool singleLine, const Windows::Foundation::IReference<Microsoft::Terminal::TerminalControl::CopyFormat>& formats);
void _SetTaskbarProgressHandler(const IInspectable sender, const IInspectable eventArgs);
void _PasteText();
void _ControlNoticeRaisedHandler(const IInspectable sender, const Microsoft::Terminal::TerminalControl::NoticeEventArgs eventArgs);

View File

@ -29,6 +29,9 @@ namespace TerminalApp
void ShowKeyboardServiceWarning();
String KeyboardServiceDisabledText { get; };
UInt64 GetLastActiveControlTaskbarState();
UInt64 GetLastActiveControlTaskbarProgress();
event Windows.Foundation.TypedEventHandler<Object, String> TitleChanged;
event Windows.Foundation.TypedEventHandler<Object, LastTabClosedEventArgs> LastTabClosed;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.UIElement> SetTitleBarContent;
@ -36,5 +39,6 @@ namespace TerminalApp
event Windows.Foundation.TypedEventHandler<Object, Object> FullscreenChanged;
event Windows.Foundation.TypedEventHandler<Object, Object> AlwaysOnTopChanged;
event Windows.Foundation.TypedEventHandler<Object, Windows.UI.Xaml.RoutedEventArgs> Initialized;
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
}
}

View File

@ -105,6 +105,7 @@ namespace winrt::TerminalApp::implementation
if (lastFocusedControl)
{
lastFocusedControl.Focus(_focusState);
lastFocusedControl.TaskbarProgressChanged();
}
}
}

View File

@ -107,6 +107,8 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
auto pfnCopyToClipboard = std::bind(&TermControl::_CopyToClipboard, this, std::placeholders::_1);
_terminal->SetCopyToClipboardCallback(pfnCopyToClipboard);
_terminal->TaskbarProgressChangedCallback([&]() { TermControl::TaskbarProgressChanged(); });
// This event is explicitly revoked in the destructor: does not need weak_ref
auto onReceiveOutputFn = [this](const hstring str) {
_terminal->Write(str);
@ -3091,6 +3093,33 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
return coreColor.has_value() ? Windows::Foundation::IReference<winrt::Windows::UI::Color>(coreColor.value()) : nullptr;
}
// Method Description:
// - Sends an event (which will be caught by TerminalPage and forwarded to AppHost after)
// to set the progress indicator on the taskbar
winrt::fire_and_forget TermControl::TaskbarProgressChanged()
{
co_await resume_foreground(Dispatcher(), CoreDispatcherPriority::High);
_setTaskbarProgressHandlers(*this, nullptr);
}
// Method Description:
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state of this control
const size_t TermControl::TaskbarState() const noexcept
{
return _terminal->GetTaskbarState();
}
// Method Description:
// - Gets the internal taskbar progress value
// Return Value:
// - The taskbar progress of this control
const size_t TermControl::TaskbarProgress() const noexcept
{
return _terminal->GetTaskbarProgress();
}
// -------------------------------- WinRT Events ---------------------------------
// Winrt events need a method for adding a callback to the event and removing the callback.
// These macros will define them both for you.
@ -3101,6 +3130,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TermControl, PasteFromClipboard, _clipboardPasteHandlers, TerminalControl::TermControl, TerminalControl::PasteFromClipboardEventArgs);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TermControl, CopyToClipboard, _clipboardCopyHandlers, TerminalControl::TermControl, TerminalControl::CopyToClipboardEventArgs);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TermControl, OpenHyperlink, _openHyperlinkHandlers, TerminalControl::TermControl, TerminalControl::OpenHyperlinkEventArgs);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TermControl, SetTaskbarProgress, _setTaskbarProgressHandlers, TerminalControl::TermControl, IInspectable);
DEFINE_EVENT_WITH_TYPED_EVENT_HANDLER(TermControl, RaiseNotice, _raiseNoticeHandlers, TerminalControl::TermControl, TerminalControl::NoticeEventArgs);
// clang-format on
}

View File

@ -158,6 +158,10 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
Windows::Foundation::IReference<winrt::Windows::UI::Color> TabColor() noexcept;
winrt::fire_and_forget TaskbarProgressChanged();
const size_t TaskbarState() const noexcept;
const size_t TaskbarProgress() const noexcept;
// clang-format off
// -------------------------------- WinRT Events ---------------------------------
DECLARE_EVENT(TitleChanged, _titleChangedHandlers, TerminalControl::TitleChangedEventArgs);
@ -167,6 +171,7 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(PasteFromClipboard, _clipboardPasteHandlers, TerminalControl::TermControl, TerminalControl::PasteFromClipboardEventArgs);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(CopyToClipboard, _clipboardCopyHandlers, TerminalControl::TermControl, TerminalControl::CopyToClipboardEventArgs);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(OpenHyperlink, _openHyperlinkHandlers, TerminalControl::TermControl, TerminalControl::OpenHyperlinkEventArgs);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTaskbarProgress, _setTaskbarProgressHandlers, TerminalControl::TermControl, IInspectable);
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(RaiseNotice, _raiseNoticeHandlers, TerminalControl::TermControl, TerminalControl::NoticeEventArgs);
TYPED_EVENT(WarningBell, IInspectable, IInspectable);

View File

@ -74,6 +74,7 @@ namespace Microsoft.Terminal.TerminalControl
event Windows.Foundation.TypedEventHandler<TermControl, CopyToClipboardEventArgs> CopyToClipboard;
event Windows.Foundation.TypedEventHandler<TermControl, PasteFromClipboardEventArgs> PasteFromClipboard;
event Windows.Foundation.TypedEventHandler<TermControl, OpenHyperlinkEventArgs> OpenHyperlink;
event Windows.Foundation.TypedEventHandler<TermControl, Object> SetTaskbarProgress;
event Windows.Foundation.TypedEventHandler<TermControl, NoticeEventArgs> RaiseNotice;
event Windows.Foundation.TypedEventHandler<Object, Object> WarningBell;
@ -105,6 +106,10 @@ namespace Microsoft.Terminal.TerminalControl
void SendInput(String input);
void ToggleRetroEffect();
void TaskbarProgressChanged();
UInt64 TaskbarState { get; };
UInt64 TaskbarProgress { get; };
Windows.Foundation.IReference<Windows.UI.Color> TabColor { get; };
event Windows.Foundation.TypedEventHandler<Object, Object> TabColorChanged;
}

View File

@ -63,6 +63,8 @@ namespace Microsoft::Terminal::Core
virtual bool AddHyperlink(std::wstring_view uri, std::wstring_view params) noexcept = 0;
virtual bool EndHyperlink() noexcept = 0;
virtual bool SetTaskbarProgress(const size_t state, const size_t progress) noexcept = 0;
protected:
ITerminalApi() = default;
};

View File

@ -50,7 +50,9 @@ Terminal::Terminal() :
_snapOnInput{ true },
_altGrAliasing{ true },
_blockSelection{ false },
_selection{ std::nullopt }
_selection{ std::nullopt },
_taskbarState{ 0 },
_taskbarProgress{ 0 }
{
auto dispatch = std::make_unique<TerminalDispatch>(*this);
auto engine = std::make_unique<OutputStateMachineEngine>(std::move(dispatch));
@ -1102,6 +1104,16 @@ void Terminal::SetBackgroundCallback(std::function<void(const COLORREF)> pfn) no
_pfnBackgroundColorChanged.swap(pfn);
}
// Method Description:
// - Allows settings a callback for settings the taskbar progress indicator
// Arguments:
// - pfn: a function callback that takes 2 size_t parameters, one indicating the progress state
// and the other indicating the progress value
void Microsoft::Terminal::Core::Terminal::TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept
{
_pfnTaskbarProgressChanged.swap(pfn);
}
void Terminal::_InitializeColorTable()
try
{
@ -1168,3 +1180,21 @@ BlinkingState& Terminal::GetBlinkingState() const noexcept
{
return _blinkingState;
}
// Method Description:
// - Gets the internal taskbar state value
// Return Value:
// - The taskbar state
const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarState() const noexcept
{
return _taskbarState;
}
// Method Description:
// - Gets the internal taskbar progress value
// Return Value:
// - The taskbar progress
const size_t Microsoft::Terminal::Core::Terminal::GetTaskbarProgress() const noexcept
{
return _taskbarProgress;
}

View File

@ -115,6 +115,8 @@ public:
bool AddHyperlink(std::wstring_view uri, std::wstring_view params) noexcept override;
bool EndHyperlink() noexcept override;
bool SetTaskbarProgress(const size_t state, const size_t progress) noexcept override;
#pragma endregion
#pragma region ITerminalInput
@ -185,6 +187,7 @@ public:
void SetScrollPositionChangedCallback(std::function<void(const int, const int, const int)> pfn) noexcept;
void SetCursorPositionChangedCallback(std::function<void()> pfn) noexcept;
void SetBackgroundCallback(std::function<void(const COLORREF)> pfn) noexcept;
void TaskbarProgressChangedCallback(std::function<void()> pfn) noexcept;
void SetCursorOn(const bool isOn);
bool IsCursorBlinkingAllowed() const noexcept;
@ -196,6 +199,9 @@ public:
Microsoft::Console::Render::BlinkingState& GetBlinkingState() const noexcept;
const size_t GetTaskbarState() const noexcept;
const size_t GetTaskbarProgress() const noexcept;
#pragma region TextSelection
// These methods are defined in TerminalSelection.cpp
enum class SelectionExpansionMode
@ -221,6 +227,7 @@ private:
std::function<void(const COLORREF)> _pfnBackgroundColorChanged;
std::function<void()> _pfnCursorPositionChanged;
std::function<void(const std::optional<til::color>)> _pfnTabColorChanged;
std::function<void()> _pfnTaskbarProgressChanged;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::StateMachine> _stateMachine;
std::unique_ptr<::Microsoft::Console::VirtualTerminal::TerminalInput> _terminalInput;
@ -240,6 +247,9 @@ private:
bool _altGrAliasing;
bool _suppressApplicationTitle;
size_t _taskbarState;
size_t _taskbarProgress;
size_t _hyperlinkPatternId;
#pragma region Text Selection

View File

@ -600,3 +600,21 @@ bool Terminal::EndHyperlink() noexcept
_buffer->SetCurrentAttributes(attr);
return true;
}
// Method Description:
// - Updates the taskbar progress indicator
// Arguments:
// - state: indicates the progress state
// - progress: indicates the progress value
// Return Value:
// - true
bool Terminal::SetTaskbarProgress(const size_t state, const size_t progress) noexcept
{
_taskbarState = state;
_taskbarProgress = progress;
if (_pfnTaskbarProgressChanged)
{
_pfnTaskbarProgressChanged();
}
return true;
}

View File

@ -3,6 +3,9 @@
#include "pch.h"
#include "TerminalDispatch.hpp"
#include "../../types/inc/utils.hpp"
using namespace Microsoft::Console;
using namespace ::Microsoft::Terminal::Core;
using namespace ::Microsoft::Console::VirtualTerminal;
@ -399,6 +402,60 @@ bool TerminalDispatch::EndHyperlink() noexcept
return _terminalApi.EndHyperlink();
}
// Method Description:
// - Performs a ConEmu action
// - Currently, the only action we support is setting the taskbar state/progress
// Arguments:
// - string: contains the parameters that define which action we do
// Return Value:
// - true
bool TerminalDispatch::DoConEmuAction(const std::wstring_view string) noexcept
{
unsigned int state = 0;
unsigned int progress = 0;
const auto parts = Utils::SplitString(string, L';');
unsigned int subParam = 0;
// For now, the only ConEmu action we support is setting the taskbar state/progress,
// which has a sub param value of 4
if (parts.size() < 1 || !Utils::StringToUint(til::at(parts, 0), subParam) || subParam != 4)
{
return false;
}
if (parts.size() >= 2)
{
// A state parameter is defined, parse it out
const auto stateSuccess = Utils::StringToUint(til::at(parts, 1), state);
if (!stateSuccess)
{
return false;
}
if (parts.size() >= 3)
{
// A progress parameter is also defined, parse it out
const auto progressSuccess = Utils::StringToUint(til::at(parts, 2), progress);
if (!progressSuccess)
{
return false;
}
}
}
if (state > TaskbarMaxState)
{
// state is out of bounds, return false
return false;
}
if (progress > TaskbarMaxProgress)
{
// progress is greater than the maximum allowed value, clamp it to the max
progress = TaskbarMaxProgress;
}
return _terminalApi.SetTaskbarProgress(state, progress);
}
// Routine Description:
// - Support routine for routing private mode parameters to be set/reset as flags
// Arguments:

View File

@ -4,6 +4,9 @@
#include "../../terminal/adapter/termDispatch.hpp"
#include "ITerminalApi.hpp"
static constexpr size_t TaskbarMaxState{ 4 };
static constexpr size_t TaskbarMaxProgress{ 100 };
class TerminalDispatch : public Microsoft::Console::VirtualTerminal::TermDispatch
{
public:
@ -67,6 +70,8 @@ public:
bool AddHyperlink(const std::wstring_view uri, const std::wstring_view params) noexcept override;
bool EndHyperlink() noexcept override;
bool DoConEmuAction(const std::wstring_view string) noexcept override;
private:
::Microsoft::Terminal::Core::ITerminalApi& _terminalApi;

View File

@ -38,6 +38,8 @@ namespace TerminalCoreUnitTests
TEST_METHOD(AddHyperlink);
TEST_METHOD(AddHyperlinkCustomId);
TEST_METHOD(AddHyperlinkCustomIdDifferentUri);
TEST_METHOD(SetTaskbarProgress);
};
};
@ -339,3 +341,50 @@ void TerminalCoreUnitTests::TerminalApiTest::AddHyperlinkCustomIdDifferentUri()
VERIFY_ARE_EQUAL(tbi.GetHyperlinkUriFromId(oldAttributes.GetHyperlinkId()), L"test.url");
VERIFY_ARE_NOT_EQUAL(oldAttributes.GetHyperlinkId(), tbi.GetCurrentAttributes().GetHyperlinkId());
}
void TerminalCoreUnitTests::TerminalApiTest::SetTaskbarProgress()
{
Terminal term;
DummyRenderTarget emptyRT;
term.Create({ 100, 100 }, 0, emptyRT);
auto& stateMachine = *(term._stateMachine);
// Initial values for taskbar state and progress should be 0
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set some values for taskbar state and progress through state machine
stateMachine.ProcessString(L"\x1b]9;4;1;50\x9c");
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(50));
// Reset to 0
stateMachine.ProcessString(L"\x1b]9;4;0;0\x9c");
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set an out of bounds value for state
stateMachine.ProcessString(L"\x1b]9;4;5;50\x9c");
// Nothing should have changed (dispatch should have returned false)
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Set an out of bounds value for progress
stateMachine.ProcessString(L"\x1b]9;4;1;999\x9c");
// Progress should have been clamped to 100
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(100));
// Don't specify any params
stateMachine.ProcessString(L"\x1b]9;4\x9c");
// State and progress should both be reset to 0
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(0));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(0));
// Specify additional params
stateMachine.ProcessString(L"\x1b]9;4;1;80;123\x9c");
// Additional params should be ignored, state and progress still set normally
VERIFY_ARE_EQUAL(term.GetTaskbarState(), gsl::narrow<size_t>(1));
VERIFY_ARE_EQUAL(term.GetTaskbarProgress(), gsl::narrow<size_t>(80));
}

View File

@ -79,6 +79,23 @@ bool AppHost::OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, cons
return false;
}
// Method Description:
// - Event handler to update the taskbar progress indicator
// - Upon receiving the event, we ask the underlying logic for the taskbar state/progress values
// of the last active control
// Arguments:
// - sender: not used
// - args: not used
void AppHost::SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/)
{
if (_logic)
{
const auto state = gsl::narrow_cast<size_t>(_logic.GetLastActiveControlTaskbarState());
const auto progress = gsl::narrow_cast<size_t>(_logic.GetLastActiveControlTaskbarProgress());
_window->SetTaskbarProgress(state, progress);
}
}
// Method Description:
// - Retrieve any commandline args passed on the commandline, and pass them to
// the app logic for processing.
@ -171,6 +188,7 @@ void AppHost::Initialize()
_logic.TitleChanged({ this, &AppHost::AppTitleChanged });
_logic.LastTabClosed({ this, &AppHost::LastTabClosed });
_logic.SetTaskbarProgress({ this, &AppHost::SetTaskbarProgress });
_window->UpdateTitle(_logic.Title());

View File

@ -18,6 +18,7 @@ public:
void LastTabClosed(const winrt::Windows::Foundation::IInspectable& sender, const winrt::TerminalApp::LastTabClosedEventArgs& args);
void Initialize();
bool OnDirectKeyEvent(const uint32_t vkey, const uint8_t scanCode, const bool down);
void SetTaskbarProgress(const winrt::Windows::Foundation::IInspectable& sender, const winrt::Windows::Foundation::IInspectable& args);
private:
bool _useNonClientArea;

View File

@ -261,6 +261,15 @@ void IslandWindow::Initialize()
_rootGrid = winrt::Windows::UI::Xaml::Controls::Grid();
_source.Content(_rootGrid);
// initialize the taskbar object
if (auto taskbar = wil::CoCreateInstanceNoThrow<ITaskbarList3>(CLSID_TaskbarList))
{
if (SUCCEEDED(taskbar->HrInit()))
{
_taskbar = std::move(taskbar);
}
}
}
void IslandWindow::OnSize(const UINT width, const UINT height)
@ -576,6 +585,48 @@ void IslandWindow::SetAlwaysOnTop(const bool alwaysOnTop)
}
}
// Method Description:
// - Sets the taskbar progress indicator
// - We follow the ConEmu style for the state and progress values,
// more details at https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
// Arguments:
// - state: indicates the progress state
// - progress: indicates the progress value
void IslandWindow::SetTaskbarProgress(const size_t state, const size_t progress)
{
if (_taskbar)
{
switch (state)
{
case 0:
// removes the taskbar progress indicator
_taskbar->SetProgressState(_window.get(), TBPF_NOPROGRESS);
break;
case 1:
// sets the progress value to value given by the 'progress' parameter
_taskbar->SetProgressState(_window.get(), TBPF_NORMAL);
_taskbar->SetProgressValue(_window.get(), progress, 100);
break;
case 2:
// sets the progress indicator to an error state
_taskbar->SetProgressState(_window.get(), TBPF_ERROR);
_taskbar->SetProgressValue(_window.get(), progress, 100);
break;
case 3:
// sets the progress indicator to an indeterminate state
_taskbar->SetProgressState(_window.get(), TBPF_INDETERMINATE);
break;
case 4:
// sets the progress indicator to a pause state
_taskbar->SetProgressState(_window.get(), TBPF_PAUSED);
_taskbar->SetProgressValue(_window.get(), progress, 100);
break;
default:
break;
}
}
}
// From GdiEngine::s_SetWindowLongWHelper
void _SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept
{

View File

@ -35,6 +35,8 @@ public:
void FullscreenChanged(const bool fullscreen);
void SetAlwaysOnTop(const bool alwaysOnTop);
void SetTaskbarProgress(const size_t state, const size_t progress);
#pragma endregion
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
@ -74,6 +76,8 @@ protected:
LONG _getDesiredWindowStyle() const;
wil::com_ptr<ITaskbarList3> _taskbar;
void _OnGetMinMaxInfo(const WPARAM wParam, const LPARAM lParam);
long _calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize);

View File

@ -29,6 +29,7 @@ Abstract:
#include <cstring>
#include <shellscalingapi.h>
#include <windowsx.h>
#include <ShObjIdl.h>
// Manually include til after we include Windows.Foundation to give it winrt superpowers
#define BLOCK_TIL

View File

@ -122,6 +122,8 @@ public:
virtual bool AddHyperlink(const std::wstring_view uri, const std::wstring_view params) = 0;
virtual bool EndHyperlink() = 0;
virtual bool DoConEmuAction(const std::wstring_view string) = 0;
};
inline Microsoft::Console::VirtualTerminal::ITermDispatch::~ITermDispatch() {}
#pragma warning(pop)

View File

@ -2383,6 +2383,16 @@ bool AdaptDispatch::EndHyperlink()
return _pConApi->PrivateEndHyperlink();
}
// Method Description:
// - Ascribes to the ITermDispatch interface
// - Not actually used in conhost
// Return Value:
// - false (so that the command gets flushed to terminal)
bool AdaptDispatch::DoConEmuAction(const std::wstring_view /*string*/) noexcept
{
return false;
}
// Routine Description:
// - Determines whether we should pass any sequence that manipulates
// TerminalInput's input generator through the PTY. It encapsulates

View File

@ -123,6 +123,8 @@ namespace Microsoft::Console::VirtualTerminal
bool AddHyperlink(const std::wstring_view uri, const std::wstring_view params) override;
bool EndHyperlink() override;
bool DoConEmuAction(const std::wstring_view string) noexcept override;
private:
enum class ScrollDirection
{

View File

@ -116,4 +116,6 @@ public:
bool AddHyperlink(const std::wstring_view /*uri*/, const std::wstring_view /*params*/) noexcept override { return false; }
bool EndHyperlink() noexcept override { return false; }
bool DoConEmuAction(const std::wstring_view /*string*/) noexcept override { return false; }
};

View File

@ -733,6 +733,11 @@ bool OutputStateMachineEngine::ActionOscDispatch(const wchar_t /*wch*/,
}
break;
}
case OscActionCodes::ConEmuAction:
{
success = _dispatch->DoConEmuAction(string);
break;
}
default:
// If no functions to call, overall dispatch was a failure.
success = false;

View File

@ -160,6 +160,7 @@ namespace Microsoft::Console::VirtualTerminal
SetWindowProperty = 3, // Not implemented
SetColor = 4,
Hyperlink = 8,
ConEmuAction = 9,
SetForegroundColor = 10,
SetBackgroundColor = 11,
SetCursorColor = 12,

View File

@ -1456,6 +1456,11 @@ public:
return true;
}
bool DoConEmuAction(const std::wstring_view /*string*/) noexcept override
{
return true;
}
size_t _cursorDistance;
size_t _line;
size_t _column;