Repository: microsoft/terminal (language: cpp)

Issue:
Flash the pane dark when BEL is emitted and pane's appearance has a light background
<!-- 
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨

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

Pull request [Add a setting to flash the pane when BEL is emitted #9270](https://github.com/microsoft/terminal/pull/9270) implemented a visual BEL indictor on the working terminal pane. It's currently a white flash, which works well against a traditional dark-mode background. However, on a light appearance this basically only lightly flashes the text, making it a little hard to notice!
Is there a possibility this could be modified to work with higher contrast light-mode users? Thank you!

# Proposed technical implementation details (optional)

I'd probably set (and store?) an `isBackgroundLight` bool somewhere iff the background color of the pane is "light". If it is, and the BEL handler has the `window` flag set, the pane would flash _dark_ on a BEL instead of light. 

A quick way to find `isBackgroundLight` may be to just see if the average of `r`, `g` and `b` is higher than `127`. I can't imagine enough people have `#888888`-ish terminals for this to warrant being a manually-defined setting.



Discussion / hints:
That seems sensible to me!
(@carlos-zamora you think this is something that counts as an a11y bug?)
> (@carlos-zamora you think this is something that counts as an a11y bug?)

Yeah. It's basically a high-contrast bug, when you think about it (just not limited to high contrast mode itself). Similar to how we are expected to have a good enough contrast for text in SUI.

Fix patch:
diff --git a/.github/actions/spelling/expect/expect.txt b/.github/actions/spelling/expect/expect.txt
index 065cfd84a61..2fb03649dfc 100644
--- a/.github/actions/spelling/expect/expect.txt
+++ b/.github/actions/spelling/expect/expect.txt
@@ -1332,6 +1332,7 @@ LTLTLTLTL
 ltrim
 ltype
 LUID
+luma
 lval
 LVB
 LVERTICAL
diff --git a/src/cascadia/TerminalControl/TermControl.cpp b/src/cascadia/TerminalControl/TermControl.cpp
index 943190cfaf2..8db8af3e8b3 100644
--- a/src/cascadia/TerminalControl/TermControl.cpp
+++ b/src/cascadia/TerminalControl/TermControl.cpp
@@ -632,6 +632,17 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         // Firing it manually makes sure it does.
         _BackgroundBrush = RootGrid().Background();
         _PropertyChangedHandlers(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"BackgroundBrush" });
+
+        _isBackgroundLight = _isColorLight(bg);
+    }
+
+    bool TermControl::_isColorLight(til::color bg) noexcept
+    {
+        // Checks if the current background color is light enough
+        // to need a dark version of the visual bell indicator
+        // This is a poor man's Rec. 601 luma.
+        const auto l = 30 * bg.r + 59 * bg.g + 11 * bg.b;
+        return l > 12750;
     }
 
     // Method Description:
@@ -2699,15 +2710,25 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         // Initialize the animation if it does not exist
         // We only initialize here instead of in the ctor because depending on the bell style setting,
         // we may never need this animation
-        if (!_bellLightAnimation)
+        if (!_bellLightAnimation && !_isBackgroundLight)
         {
             _bellLightAnimation = Window::Current().Compositor().CreateScalarKeyFrameAnimation();
             // Add key frames and a duration to our bell light animation
-            _bellLightAnimation.InsertKeyFrame(0.0, 2.0);
-            _bellLightAnimation.InsertKeyFrame(1.0, 1.0);
+            _bellLightAnimation.InsertKeyFrame(0.0, 4.0);
+            _bellLightAnimation.InsertKeyFrame(1.0, 1.9);
             _bellLightAnimation.Duration(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(TerminalWarningBellInterval)));
         }
 
+        // Likewise, initialize the dark version of the animation only if required
+        if (!_bellDarkAnimation && _isBackgroundLight)
+        {
+            _bellDarkAnimation = Window::Current().Compositor().CreateScalarKeyFrameAnimation();
+            // reversing the order of the intensity values produces a similar effect as the light version
+            _bellDarkAnimation.InsertKeyFrame(0.0, 1.0);
+            _bellDarkAnimation.InsertKeyFrame(1.0, 2.0);
+            _bellDarkAnimation.Duration(winrt::Windows::Foundation::TimeSpan(std::chrono::milliseconds(TerminalWarningBellInterval)));
+        }
+
         // Similar to the animation, only initialize the timer here
         if (!_bellLightTimer)
         {
@@ -2726,7 +2747,15 @@ namespace winrt::Microsoft::Terminal::Control::implementation
 
             // Switch on the light and animate the intensity to fade out
             VisualBellLight::SetIsTarget(RootGrid(), true);
-            BellLight().CompositionLight().StartAnimation(L"Intensity", _bellLightAnimation);
+
+            if (_isBackgroundLight)
+            {
+                BellLight().CompositionLight().StartAnimation(L"Intensity", _bellDarkAnimation);
+            }
+            else
+            {
+                BellLight().CompositionLight().StartAnimation(L"Intensity", _bellLightAnimation);
+            }
         }
     }
 
diff --git a/src/cascadia/TerminalControl/TermControl.h b/src/cascadia/TerminalControl/TermControl.h
index 655fce03fdb..4e5891aa66d 100644
--- a/src/cascadia/TerminalControl/TermControl.h
+++ b/src/cascadia/TerminalControl/TermControl.h
@@ -201,6 +201,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         bool _pointerPressedInBounds{ false };
 
         winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellLightAnimation{ nullptr };
+        winrt::Windows::UI::Composition::ScalarKeyFrameAnimation _bellDarkAnimation{ nullptr };
         Windows::UI::Xaml::DispatcherTimer _bellLightTimer{ nullptr };
 
         std::optional<Windows::UI::Xaml::DispatcherTimer> _cursorTimer;
@@ -209,6 +210,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         winrt::Windows::UI::Xaml::Controls::SwapChainPanel::LayoutUpdated_revoker _layoutUpdatedRevoker;
         bool _showMarksInScrollbar{ false };
 
+        bool _isBackgroundLight{ false };
+
         inline bool _IsClosing() const noexcept
         {
 #ifndef NDEBUG
@@ -230,6 +233,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         void _InitializeBackgroundBrush();
         winrt::fire_and_forget _coreBackgroundColorChanged(const IInspectable& sender, const IInspectable& args);
         void _changeBackgroundColor(til::color bg);
+        static bool _isColorLight(til::color bg) noexcept;
         void _changeBackgroundOpacity();
 
         bool _InitializeTerminal();
diff --git a/src/cascadia/TerminalControl/XamlLights.cpp b/src/cascadia/TerminalControl/XamlLights.cpp
index dbdc66dfb39..c75d085a2da 100644
--- a/src/cascadia/TerminalControl/XamlLights.cpp
+++ b/src/cascadia/TerminalControl/XamlLights.cpp
@@ -44,7 +44,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         if (!CompositionLight())
         {
             auto spotLight{ Window::Current().Compositor().CreateAmbientLight() };
-            spotLight.Color(Windows::UI::Colors::White());
+            spotLight.Color(Windows::UI::Colors::Gray());
             CompositionLight(spotLight);
         }
     }


Test patch: