mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-08 19:40:01 +02:00
[PowerDisplay] Add custom vcp code name map and fix some bugs (#45355)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request 1. Fix quick access not working bug 2. Add custom value mapping 3. Fix some vcp slider visibility bug demo for custom vcp value name mapping: <img width="1399" height="744" alt="image" src="https://github.com/user-attachments/assets/517e4dbb-409a-4e43-b15a-d0d31e59ce49" /> <img width="1379" height="337" alt="image" src="https://github.com/user-attachments/assets/18f6f389-089c-4441-ad9f-5c45cac53814" /> <img width="521" height="1152" alt="image" src="https://github.com/user-attachments/assets/27b5f796-66fa-4781-b16f-4770bebf3504" /> <img width="295" height="808" alt="image" src="https://github.com/user-attachments/assets/54eaf5b9-5d54-4531-a40b-de3113122715" /> <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed --------- Co-authored-by: Yu Leng <yuleng@microsoft.com>
This commit is contained in:
@@ -9,6 +9,8 @@
|
||||
#include <common/utils/winapi_error.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <common/utils/resources.h>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
@@ -48,6 +50,11 @@ private:
|
||||
HANDLE m_hRefreshEvent = nullptr;
|
||||
HANDLE m_hSendSettingsTelemetryEvent = nullptr;
|
||||
|
||||
// Toggle event handle and listener thread for Quick Access support
|
||||
HANDLE m_hToggleEvent = nullptr;
|
||||
HANDLE m_hStopEvent = nullptr; // Manual-reset event to signal thread termination
|
||||
std::thread m_toggleEventThread;
|
||||
|
||||
public:
|
||||
PowerDisplayModule()
|
||||
{
|
||||
@@ -62,16 +69,29 @@ public:
|
||||
m_hSendSettingsTelemetryEvent = CreateDefaultEvent(CommonSharedConstants::POWER_DISPLAY_SEND_SETTINGS_TELEMETRY_EVENT);
|
||||
Logger::trace(L"Created SEND_SETTINGS_TELEMETRY_EVENT: handle={}", reinterpret_cast<void*>(m_hSendSettingsTelemetryEvent));
|
||||
|
||||
if (!m_hRefreshEvent || !m_hSendSettingsTelemetryEvent)
|
||||
// Create Toggle event for Quick Access support
|
||||
// This allows Quick Access to launch PowerDisplay even when module is not enabled
|
||||
m_hToggleEvent = CreateDefaultEvent(CommonSharedConstants::TOGGLE_POWER_DISPLAY_EVENT);
|
||||
Logger::trace(L"Created TOGGLE_EVENT: handle={}", reinterpret_cast<void*>(m_hToggleEvent));
|
||||
|
||||
// Create manual-reset stop event for clean thread termination
|
||||
m_hStopEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
||||
Logger::trace(L"Created STOP_EVENT: handle={}", reinterpret_cast<void*>(m_hStopEvent));
|
||||
|
||||
if (!m_hRefreshEvent || !m_hSendSettingsTelemetryEvent || !m_hToggleEvent || !m_hStopEvent)
|
||||
{
|
||||
Logger::error(L"Failed to create one or more event handles: Refresh={}, SettingsTelemetry={}",
|
||||
Logger::error(L"Failed to create one or more event handles: Refresh={}, SettingsTelemetry={}, Toggle={}",
|
||||
reinterpret_cast<void*>(m_hRefreshEvent),
|
||||
reinterpret_cast<void*>(m_hSendSettingsTelemetryEvent));
|
||||
reinterpret_cast<void*>(m_hSendSettingsTelemetryEvent),
|
||||
reinterpret_cast<void*>(m_hToggleEvent));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info(L"All Windows Events created successfully");
|
||||
}
|
||||
|
||||
// Start toggle event listener thread for Quick Access support
|
||||
StartToggleEventListener();
|
||||
}
|
||||
|
||||
~PowerDisplayModule()
|
||||
@@ -81,6 +101,9 @@ public:
|
||||
disable();
|
||||
}
|
||||
|
||||
// Stop toggle event listener thread
|
||||
StopToggleEventListener();
|
||||
|
||||
// Clean up event handles
|
||||
if (m_hRefreshEvent)
|
||||
{
|
||||
@@ -92,6 +115,99 @@ public:
|
||||
CloseHandle(m_hSendSettingsTelemetryEvent);
|
||||
m_hSendSettingsTelemetryEvent = nullptr;
|
||||
}
|
||||
if (m_hToggleEvent)
|
||||
{
|
||||
CloseHandle(m_hToggleEvent);
|
||||
m_hToggleEvent = nullptr;
|
||||
}
|
||||
if (m_hStopEvent)
|
||||
{
|
||||
CloseHandle(m_hStopEvent);
|
||||
m_hStopEvent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void StartToggleEventListener()
|
||||
{
|
||||
if (!m_hToggleEvent || !m_hStopEvent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset stop event before starting thread
|
||||
ResetEvent(m_hStopEvent);
|
||||
|
||||
m_toggleEventThread = std::thread([this]() {
|
||||
Logger::info(L"Toggle event listener thread started");
|
||||
|
||||
HANDLE handles[] = { m_hToggleEvent, m_hStopEvent };
|
||||
constexpr DWORD TOGGLE_EVENT_INDEX = 0;
|
||||
constexpr DWORD STOP_EVENT_INDEX = 1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Wait indefinitely for either toggle event or stop event
|
||||
DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
|
||||
if (result == WAIT_OBJECT_0 + TOGGLE_EVENT_INDEX)
|
||||
{
|
||||
Logger::trace(L"Toggle event received");
|
||||
TogglePowerDisplay();
|
||||
}
|
||||
else if (result == WAIT_OBJECT_0 + STOP_EVENT_INDEX)
|
||||
{
|
||||
// Stop event signaled - exit the loop
|
||||
Logger::trace(L"Stop event received, exiting toggle listener");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// WAIT_FAILED or unexpected result
|
||||
Logger::warn(L"WaitForMultipleObjects returned unexpected result: {}", result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Logger::info(L"Toggle event listener thread stopped");
|
||||
});
|
||||
}
|
||||
|
||||
void StopToggleEventListener()
|
||||
{
|
||||
if (m_hStopEvent)
|
||||
{
|
||||
// Signal the stop event to wake up the waiting thread
|
||||
SetEvent(m_hStopEvent);
|
||||
}
|
||||
|
||||
if (m_toggleEventThread.joinable())
|
||||
{
|
||||
m_toggleEventThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggle PowerDisplay window visibility.
|
||||
/// If process is running, launches again to trigger redirect activation (OnActivated handles toggle).
|
||||
/// If process is not running, starts it via Named Pipe and sends toggle message.
|
||||
/// </summary>
|
||||
void TogglePowerDisplay()
|
||||
{
|
||||
if (m_processManager.is_running())
|
||||
{
|
||||
// Process running - launch to trigger single instance redirect, OnActivated will toggle
|
||||
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||
sei.fMask = SEE_MASK_FLAG_NO_UI;
|
||||
sei.lpFile = L"WinUI3Apps\\PowerToys.PowerDisplay.exe";
|
||||
sei.nShow = SW_SHOWNORMAL;
|
||||
ShellExecuteExW(&sei);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process not running - start and send toggle via Named Pipe
|
||||
m_processManager.send_message(CommonSharedConstants::POWER_DISPLAY_TOGGLE_MESSAGE);
|
||||
}
|
||||
Trace::ActivatePowerDisplay();
|
||||
}
|
||||
|
||||
virtual void destroy() override
|
||||
@@ -135,10 +251,7 @@ public:
|
||||
if (action_object.get_name() == L"Launch")
|
||||
{
|
||||
Logger::trace(L"Launch action received");
|
||||
|
||||
// Send Toggle message via Named Pipe (will start process if needed)
|
||||
m_processManager.send_message(CommonSharedConstants::POWER_DISPLAY_TOGGLE_MESSAGE);
|
||||
Trace::ActivatePowerDisplay();
|
||||
TogglePowerDisplay();
|
||||
}
|
||||
else if (action_object.get_name() == L"RefreshMonitors")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user