From 98806e27b1d467027d07ab7b0da9ee6073f5a600 Mon Sep 17 00:00:00 2001 From: Mike Griese Date: Thu, 15 Oct 2020 17:27:27 -0500 Subject: [PATCH] Add a setting to configure the audible bell (#7793) Adds a new setting, `bellStyle`, to be able to disable the audible bell added in #7679. Currently, this setting accepts two values: * `audible`: play a noise on a bell * `none`: Don't play a noise. In the future, we can add a `"bellStyle": "visible"` for flashing the Terminal instead of making a noise on bell. ## Validation Steps Performed Pressing Ctrl+G in cmd, and hitting enter is an easy way of triggering a bell. I set the setting to `none`, and presto, the bell stopped. Closes #2360 --- doc/cascadia/profiles.schema.json | 12 ++++++ src/cascadia/TerminalApp/Pane.cpp | 37 ++++++++++++++++++- src/cascadia/TerminalApp/Pane.h | 3 ++ src/cascadia/TerminalApp/TerminalPage.cpp | 15 -------- src/cascadia/TerminalApp/TerminalPage.h | 1 - .../TerminalSettingsModel/Profile.cpp | 3 ++ src/cascadia/TerminalSettingsModel/Profile.h | 2 + .../TerminalSettingsModel/Profile.idl | 8 ++++ .../TerminalSettingsSerializationHelpers.h | 8 ++++ 9 files changed, 72 insertions(+), 17 deletions(-) diff --git a/doc/cascadia/profiles.schema.json b/doc/cascadia/profiles.schema.json index ac8aebba4ae..ff6ac1e67ea 100644 --- a/doc/cascadia/profiles.schema.json +++ b/doc/cascadia/profiles.schema.json @@ -26,6 +26,13 @@ ], "type": "string" }, + "BellStyle": { + "enum": [ + "none", + "audible" + ], + "type": "string" + }, "ProfileGuid": { "default": "{}", "pattern": "^\\{[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\}$", @@ -717,6 +724,11 @@ ], "type": "string" }, + "bellStyle": { + "default": "audible", + "description": "Controls what happens when the application emits a BEL character. When set to \"audible\", the Terminal will play a sound. When set to \"none\", nothing will happen.", + "$ref": "#/definitions/BellStyle" + }, "closeOnExit": { "default": "graceful", "description": "Sets how the profile reacts to termination or failure to launch. Possible values:\n -\"graceful\" (close when exit is typed or the process exits normally)\n -\"always\" (always close)\n -\"never\" (never close).\ntrue and false are accepted as synonyms for \"graceful\" and \"never\" respectively.", diff --git a/src/cascadia/TerminalApp/Pane.cpp b/src/cascadia/TerminalApp/Pane.cpp index a57571b54fb..96f99a6d644 100644 --- a/src/cascadia/TerminalApp/Pane.cpp +++ b/src/cascadia/TerminalApp/Pane.cpp @@ -5,6 +5,8 @@ #include "Pane.h" #include "AppLogic.h" +#include + using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Graphics::Display; using namespace winrt::Windows::UI; @@ -42,6 +44,7 @@ Pane::Pane(const GUID& profile, const TermControl& control, const bool lastFocus _border.Child(_control); _connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler }); + _warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler }); // On the first Pane's creation, lookup resources we'll use to theme the // Pane, including the brushed to use for the focused/unfocused border @@ -309,7 +312,8 @@ bool Pane::NavigateFocus(const Direction& direction) // - // Return Value: // - -void Pane::_ControlConnectionStateChangedHandler(const TermControl& /*sender*/, const winrt::Windows::Foundation::IInspectable& /*args*/) +void Pane::_ControlConnectionStateChangedHandler(const TermControl& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*args*/) { std::unique_lock lock{ _createCloseLock }; // It's possible that this event handler started being executed, then before @@ -345,6 +349,31 @@ void Pane::_ControlConnectionStateChangedHandler(const TermControl& /*sender*/, } } +// Method Description: +// - Plays a warning note when triggered by the BEL control character, +// using the sound configured for the "Critical Stop" system event.` +// This matches the behavior of the Windows Console host. +// Arguments: +// - +void Pane::_ControlWarningBellHandler(const winrt::Windows::Foundation::IInspectable& /*sender*/, + const winrt::Windows::Foundation::IInspectable& /*eventArgs*/) +{ + if (!_IsLeaf()) + { + return; + } + const auto settings{ winrt::TerminalApp::implementation::AppLogic::CurrentAppSettings() }; + auto paneProfile = settings.FindProfile(_profile.value()); + if (paneProfile) + { + if (paneProfile.BellStyle() == winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible) + { + const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); + PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); + } + } +} + // Event Description: // - Called when our control gains focus. We'll use this to trigger our GotFocus // callback. The tab that's hosting us should have registered a callback which @@ -625,6 +654,7 @@ void Pane::_CloseChild(const bool closeFirst) // Add our new event handler before revoking the old one. _connectionStateChangedToken = _control.ConnectionStateChanged({ this, &Pane::_ControlConnectionStateChangedHandler }); + _warningBellToken = _control.WarningBell({ this, &Pane::_ControlWarningBellHandler }); // Revoke the old event handlers. Remove both the handlers for the panes // themselves closing, and remove their handlers for their controls @@ -634,6 +664,8 @@ void Pane::_CloseChild(const bool closeFirst) _secondChild->Closed(_secondClosedToken); closedChild->_control.ConnectionStateChanged(closedChild->_connectionStateChangedToken); remainingChild->_control.ConnectionStateChanged(remainingChild->_connectionStateChangedToken); + closedChild->_control.WarningBell(closedChild->_warningBellToken); + remainingChild->_control.WarningBell(remainingChild->_warningBellToken); // If either of our children was focused, we want to take that focus from // them. @@ -714,6 +746,7 @@ void Pane::_CloseChild(const bool closeFirst) oldFirst->Closed(oldFirstToken); oldSecond->Closed(oldSecondToken); closedChild->_control.ConnectionStateChanged(closedChild->_connectionStateChangedToken); + closedChild->_control.WarningBell(closedChild->_warningBellToken); // Reset our UI: _root.Children().Clear(); @@ -1412,6 +1445,8 @@ std::pair, std::shared_ptr> Pane::_Split(SplitState // revoke our handler - the child will take care of the control now. _control.ConnectionStateChanged(_connectionStateChangedToken); _connectionStateChangedToken.value = 0; + _control.WarningBell(_warningBellToken); + _warningBellToken.value = 0; // Remove our old GotFocus handler from the control. We don't what the // control telling us that it's now focused, we want it telling its new diff --git a/src/cascadia/TerminalApp/Pane.h b/src/cascadia/TerminalApp/Pane.h index ed4506176be..727e3e3f568 100644 --- a/src/cascadia/TerminalApp/Pane.h +++ b/src/cascadia/TerminalApp/Pane.h @@ -99,6 +99,7 @@ class Pane : public std::enable_shared_from_this winrt::event_token _connectionStateChangedToken{ 0 }; winrt::event_token _firstClosedToken{ 0 }; winrt::event_token _secondClosedToken{ 0 }; + winrt::event_token _warningBellToken{ 0 }; winrt::Windows::UI::Xaml::UIElement::GotFocus_revoker _gotFocusRevoker; @@ -130,6 +131,8 @@ class Pane : public std::enable_shared_from_this void _FocusFirstChild(); void _ControlConnectionStateChangedHandler(const winrt::Microsoft::Terminal::TerminalControl::TermControl& sender, const winrt::Windows::Foundation::IInspectable& /*args*/); + void _ControlWarningBellHandler(winrt::Windows::Foundation::IInspectable const& sender, + winrt::Windows::Foundation::IInspectable const& e); void _ControlGotFocusHandler(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e); diff --git a/src/cascadia/TerminalApp/TerminalPage.cpp b/src/cascadia/TerminalApp/TerminalPage.cpp index 68a7462d226..988664bdc69 100644 --- a/src/cascadia/TerminalApp/TerminalPage.cpp +++ b/src/cascadia/TerminalApp/TerminalPage.cpp @@ -7,7 +7,6 @@ #include "AppLogic.h" #include "../../types/inc/utils.hpp" -#include #include #include "TerminalPage.g.cpp" @@ -1122,8 +1121,6 @@ namespace winrt::TerminalApp::implementation // Add an event handler when the terminal wants to paste data from the Clipboard. term.PasteFromClipboard({ this, &TerminalPage::_PasteFromClipboardHandler }); - term.WarningBell({ this, &TerminalPage::_WarningBellHandler }); - term.OpenHyperlink({ this, &TerminalPage::_OpenHyperlinkHandler }); // Bind Tab events to the TermControl and the Tab's Pane @@ -1784,18 +1781,6 @@ namespace winrt::TerminalApp::implementation CATCH_LOG(); } - // Method Description: - // - Plays a warning note when triggered by the BEL control character, - // using the sound configured for the "Critical Stop" system event. - // This matches the behavior of the Windows Console host. - // Arguments: - // - - void TerminalPage::_WarningBellHandler(const IInspectable sender, const IInspectable eventArgs) - { - const auto soundAlias = reinterpret_cast(SND_ALIAS_SYSTEMHAND); - PlaySound(soundAlias, NULL, SND_ALIAS_ID | SND_ASYNC | SND_SENTRY); - } - void TerminalPage::_OpenHyperlinkHandler(const IInspectable /*sender*/, const Microsoft::Terminal::TerminalControl::OpenHyperlinkEventArgs eventArgs) { try diff --git a/src/cascadia/TerminalApp/TerminalPage.h b/src/cascadia/TerminalApp/TerminalPage.h index 8b28ab12397..13d4a3341e0 100644 --- a/src/cascadia/TerminalApp/TerminalPage.h +++ b/src/cascadia/TerminalApp/TerminalPage.h @@ -174,7 +174,6 @@ namespace winrt::TerminalApp::implementation winrt::fire_and_forget _PasteFromClipboardHandler(const IInspectable sender, const Microsoft::Terminal::TerminalControl::PasteFromClipboardEventArgs eventArgs); - void _WarningBellHandler(const IInspectable sender, const IInspectable eventArgs); void _OpenHyperlinkHandler(const IInspectable sender, const Microsoft::Terminal::TerminalControl::OpenHyperlinkEventArgs eventArgs); void _ShowCouldNotOpenDialog(winrt::hstring reason, winrt::hstring uri); bool _CopyText(const bool singleLine, const Windows::Foundation::IReference& formats); diff --git a/src/cascadia/TerminalSettingsModel/Profile.cpp b/src/cascadia/TerminalSettingsModel/Profile.cpp index bf3fdcf5ef2..df81b1ecd80 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.cpp +++ b/src/cascadia/TerminalSettingsModel/Profile.cpp @@ -57,6 +57,7 @@ static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageA static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" }; static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" }; static constexpr std::string_view TabColorKey{ "tabColor" }; +static constexpr std::string_view BellStyleKey{ "bellStyle" }; static const winrt::hstring DesktopWallpaperEnum{ L"DesktopWallpaper" }; @@ -243,6 +244,8 @@ void Profile::LayerJson(const Json::Value& json) JsonUtils::GetValueForKey(json, AntialiasingModeKey, _AntialiasingMode); JsonUtils::GetValueForKey(json, TabColorKey, _TabColor); + + JsonUtils::GetValueForKey(json, BellStyleKey, _BellStyle); } // Method Description: diff --git a/src/cascadia/TerminalSettingsModel/Profile.h b/src/cascadia/TerminalSettingsModel/Profile.h index eec8d1dda9a..14e0d02223e 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.h +++ b/src/cascadia/TerminalSettingsModel/Profile.h @@ -115,6 +115,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation GETSET_PROPERTY(Microsoft::Terminal::TerminalControl::CursorStyle, CursorShape, Microsoft::Terminal::TerminalControl::CursorStyle::Bar); GETSET_PROPERTY(uint32_t, CursorHeight, DEFAULT_CURSOR_HEIGHT); + GETSET_PROPERTY(winrt::Microsoft::Terminal::Settings::Model::BellStyle, BellStyle, winrt::Microsoft::Terminal::Settings::Model::BellStyle::Audible); + private: std::optional _Guid{ std::nullopt }; std::optional _ConnectionType{ std::nullopt }; diff --git a/src/cascadia/TerminalSettingsModel/Profile.idl b/src/cascadia/TerminalSettingsModel/Profile.idl index a81c95bfa59..453cc94b08b 100644 --- a/src/cascadia/TerminalSettingsModel/Profile.idl +++ b/src/cascadia/TerminalSettingsModel/Profile.idl @@ -10,6 +10,12 @@ namespace Microsoft.Terminal.Settings.Model Always }; + enum BellStyle + { + None, + Audible + }; + [default_interface] runtimeclass Profile { Profile(); Profile(Guid guid); @@ -66,5 +72,7 @@ namespace Microsoft.Terminal.Settings.Model Microsoft.Terminal.TerminalControl.CursorStyle CursorShape; UInt32 CursorHeight; + + BellStyle BellStyle; } } diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h index 9564646890b..6e925e5963b 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettingsSerializationHelpers.h @@ -47,6 +47,14 @@ JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::TerminalControl::ScrollbarState) }; }; +JSON_ENUM_MAPPER(::winrt::Microsoft::Terminal::Settings::Model::BellStyle) +{ + static constexpr std::array mappings = { + pair_type{ "none", ValueType::None }, + pair_type{ "audible", ValueType::Audible } + }; +}; + JSON_ENUM_MAPPER(std::tuple<::winrt::Windows::UI::Xaml::HorizontalAlignment, ::winrt::Windows::UI::Xaml::VerticalAlignment>) { // reduce repetition