[PowerDisplay] Debounced + wheel-scrollable brightness/contrast/volume sliders#47756
Open
[PowerDisplay] Debounced + wheel-scrollable brightness/contrast/volume sliders#47756
Conversation
…ut handling Replaces the PointerCaptureLost + arrow-KeyUp wiring on the brightness, contrast, and volume sliders with a TwoWay binding plus a per-metric DispatcherQueueTimer debounce in MonitorViewModel. ValueChanged drives the setter; ScheduleCommit (re)starts a 200 ms timer (AppConstants.UI.SliderCommitDebounceMs) that fires the DDC/CI write once the user stops moving, coalescing intermediate values into a single hardware update. PointerCaptureLost was unreliable on touch (tap-on-track issues no capture, and Slider/Thumb sometimes don't bubble the event), leaving the value uncommitted. The debounce works identically across mouse drag, touch drag, tap-on-track, and held arrow keys. External / programmatic apply paths (SetBrightnessAsync etc., used by hotkeys, profile load, and hardware refresh) bypass the public setters and remain immediate. Pending debounced writes are dropped in Dispose to avoid racing a half-torn-down MonitorManager. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two attached properties on Slider: - helpers:SliderExtensions.IsMouseWheelEnabled - opt in to wheel input. - helpers:SliderExtensions.MouseWheelChange - per-notch delta (defaults to the slider's own SmallChange when unset). Wired on the brightness, contrast, and volume sliders with a step of 5. PointerWheelChanged is marked handled so the parent ScrollViewer does not also scroll. Combined with the existing 200 ms debounce, wheel input coalesces into a single DDC/CI write. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
11 tasks
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
is it possible to include controls for switching display signals per-monitor? a dropdown to select HDMI1-2/DP1-2 and other inputs from this tool would be very useful. That way we can ignore hardware buttons |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary of the Pull Request
The brightness / contrast / volume sliders in the PowerDisplay flyout previously committed to hardware (DDC/CI) only on
PointerCaptureLostplus arrow-keyKeyUp. That doesn't work reliably on touchscreens — tap-on-track issues no pointer capture, and the Slider / Thumb doesn't always bubblePointerCaptureLoston touch — so the value the user dialed in never reached the monitor.This PR replaces that wiring with the simpler approach we actually wanted: a TwoWay
Valuebinding plus a debounced commit in the view-model.ValueChangedruns the setter on every move, but a 200 msDispatcherQueueTimer(restarted on each change) collapses the entire interaction into a single DDC/CI write once the user stops sliding. Mouse, touch, tap-on-track, and held arrow keys all use the same code path.It also adds a small
SliderExtensionshelper (Toolkit-style attached properties) so the brightness / contrast / volume sliders can be adjusted by mouse-wheel scroll. The wheel event is marked handled so the parentScrollViewerdoes not also scroll, and the existing 200 ms debounce coalesces wheel input into a single DDC/CI write.PR Checklist
Detailed Description of the Pull Request / Additional comments
Debounced commit
MonitorViewModel.Brightness/Contrast/Volumesetters now: assign field →OnPropertyChanged()→ScheduleCommit(...)which (re)starts a per-metricDispatcherQueueTimer. OnTickthe closure callsSetBrightnessAsync(_brightness)(etc.), reading the latest field value so intermediate drag values are coalesced into one hardware write.SetBrightnessAsync/SetContrastAsync/SetVolumeAsync(used by hotkeys, profile load, hardware refresh) keep their immediate-apply behavior — they bypass the public setters, so a TwoWay source-update from one of those paths does not reschedule a commit.MonitorViewModel.Dispose()stops the three timers. Pending writes are intentionally dropped:Disposeonly runs when the monitor is gone (unplug / refresh) or the app is shutting down, in which case a hardware write would race a half-torn-downMonitorManager.AppConstants.UI.SliderCommitDebounceMs = 200is the single source of truth for the delay.Handle{Brightness|Contrast|Volume}{PointerCaptureLost|KeyUp}methods and the now-unusedIsArrowKeyhelper.using DispatcherQueueTimer = Microsoft.UI.Dispatching.DispatcherQueueTimer;alias avoids ambiguity withWindows.System.DispatcherQueueTimer.Wheel-scrollable sliders
PowerDisplay.Helpers.SliderExtensions— a Toolkit-stylepublic static class <Control>Extensionswith two attached properties:SliderExtensions.IsMouseWheelEnabled(bool) — opt in to wheel input.SliderExtensions.MouseWheelChange(double, defaultNaN→ falls back to the slider's ownSlider.SmallChange) — per-notch delta.notches = MouseWheelDelta / 120, clamps to[Minimum, Maximum], setsValue, and markse.Handled = trueso the enclosingMainScrollViewerdoesn't also scroll.MouseWheelChange="5"(20 notches for a full sweep).Microsoft.UI.Xaml.*) so the helper is straightforward to lift into the WinUI Community Toolkit later.Validation Steps Performed
tools/build/build.cmdagainstsrc/modules/powerdisplay/PowerDisplay/PowerDisplay.csproj— exit code 0.MainScrollViewer; wheel outside the sliders still scrolls.Minimum/Maximumclamps at the boundary.SetBrightnessAsyncpath).DisplayChangeWatcher-driven hardware refresh does not schedule a spurious commit.