Query Focus Assist state on Windows.

This commit is contained in:
John Preston 2021-04-23 08:00:17 +04:00
parent 3a28be1e16
commit 2730ab1596
5 changed files with 233 additions and 26 deletions

View File

@ -37,6 +37,11 @@ include(cmake/td_scheme.cmake)
include(cmake/td_ui.cmake) include(cmake/td_ui.cmake)
include(cmake/generate_appdata_changelog.cmake) include(cmake/generate_appdata_changelog.cmake)
if (WIN32)
include(cmake/generate_midl.cmake)
generate_midl(Telegram ${src_loc}/platform/win/windows_quiethours.idl)
endif()
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON) set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
target_link_libraries(Telegram target_link_libraries(Telegram

View File

@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/core_settings.h" #include "core/core_settings.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "windows_quiethours_h.h"
#include <Shobjidl.h> #include <Shobjidl.h>
#include <shellapi.h> #include <shellapi.h>
@ -632,7 +633,8 @@ namespace {
bool QuietHoursEnabled = false; bool QuietHoursEnabled = false;
DWORD QuietHoursValue = 0; DWORD QuietHoursValue = 0;
bool useQuietHoursRegistryEntry() { [[nodiscard]] bool UseQuietHoursRegistryEntry() {
static const bool result = [] {
// Taken from QSysInfo. // Taken from QSysInfo.
OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0,{ '\0' } }; OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0,{ '\0' } };
if (const auto library = GetModuleHandle(L"ntdll.dll")) { if (const auto library = GetModuleHandle(L"ntdll.dll")) {
@ -648,11 +650,13 @@ bool useQuietHoursRegistryEntry() {
return (result.dwMajorVersion == 10 return (result.dwMajorVersion == 10
&& result.dwMinorVersion == 0 && result.dwMinorVersion == 0
&& result.dwBuildNumber < 17134); && result.dwBuildNumber < 17134);
}();
return result;
} }
// Thanks https://stackoverflow.com/questions/35600128/get-windows-quiet-hours-from-win32-or-c-sharp-api // Thanks https://stackoverflow.com/questions/35600128/get-windows-quiet-hours-from-win32-or-c-sharp-api
void queryQuietHours() { void QueryQuietHours() {
if (!useQuietHoursRegistryEntry()) { if (!UseQuietHoursRegistryEntry()) {
// There are quiet hours in Windows starting from Windows 8.1 // There are quiet hours in Windows starting from Windows 8.1
// But there were several reports about the notifications being shut // But there were several reports about the notifications being shut
// down according to the registry while no quiet hours were enabled. // down according to the registry while no quiet hours were enabled.
@ -683,9 +687,82 @@ void queryQuietHours() {
} }
} }
bool FocusAssistBlocks = false;
void QueryFocusAssist() {
ComPtr<IQuietHoursSettings> quietHoursSettings;
auto hr = CoCreateInstance(
CLSID_QuietHoursSettings,
nullptr,
CLSCTX_LOCAL_SERVER,
IID_PPV_ARGS(&quietHoursSettings));
if (!SUCCEEDED(hr) || !quietHoursSettings) {
return;
}
auto profileId = LPWSTR{};
const auto guardProfileId = gsl::finally([&] {
if (profileId) CoTaskMemFree(profileId);
});
hr = quietHoursSettings->get_UserSelectedProfile(&profileId);
if (!SUCCEEDED(hr) || !profileId) {
return;
}
const auto profileName = QString::fromWCharArray(profileId);
if (profileName.endsWith(".unrestricted", Qt::CaseInsensitive)) {
if (FocusAssistBlocks) {
LOG(("Focus Assist: Unrestricted."));
FocusAssistBlocks = false;
}
return;
} else if (profileName.endsWith(".alarmsonly", Qt::CaseInsensitive)) {
if (!FocusAssistBlocks) {
LOG(("Focus Assist: Alarms Only."));
FocusAssistBlocks = true;
}
return;
}
const auto appUserModelId = std::wstring(AppUserModelId::getId());
auto blocked = true;
const auto guard = gsl::finally([&] {
if (FocusAssistBlocks != blocked) {
LOG(("Focus Assist: %1, AppUserModelId: %2, Blocks: %3"
).arg(profileName
).arg(QString::fromStdWString(appUserModelId)
).arg(Logs::b(blocked)));
FocusAssistBlocks = blocked;
}
});
ComPtr<IQuietHoursProfile> profile;
hr = quietHoursSettings->GetProfile(profileId, &profile);
if (!SUCCEEDED(hr) || !profile) {
return;
}
UINT32 count = 0;
auto apps = (LPWSTR*)nullptr;
const auto guardApps = gsl::finally([&] {
if (apps) CoTaskMemFree(apps);
});
hr = profile->GetAllowedApps(&count, &apps);
if (!SUCCEEDED(hr) || !apps) {
return;
}
for (UINT32 i = 0; i < count; i++) {
auto app = apps[i];
const auto guardApp = gsl::finally([&] {
if (app) CoTaskMemFree(app);
});
if (app == appUserModelId) {
blocked = false;
}
}
}
QUERY_USER_NOTIFICATION_STATE UserNotificationState = QUNS_ACCEPTS_NOTIFICATIONS; QUERY_USER_NOTIFICATION_STATE UserNotificationState = QUNS_ACCEPTS_NOTIFICATIONS;
void queryUserNotificationState() { void QueryUserNotificationState() {
if (Dlls::SHQueryUserNotificationState != nullptr) { if (Dlls::SHQueryUserNotificationState != nullptr) {
QUERY_USER_NOTIFICATION_STATE state; QUERY_USER_NOTIFICATION_STATE state;
if (SUCCEEDED(Dlls::SHQueryUserNotificationState(&state))) { if (SUCCEEDED(Dlls::SHQueryUserNotificationState(&state))) {
@ -697,24 +774,26 @@ void queryUserNotificationState() {
static constexpr auto kQuerySettingsEachMs = 1000; static constexpr auto kQuerySettingsEachMs = 1000;
crl::time LastSettingsQueryMs = 0; crl::time LastSettingsQueryMs = 0;
void querySystemNotificationSettings() { void QuerySystemNotificationSettings() {
auto ms = crl::now(); auto ms = crl::now();
if (LastSettingsQueryMs > 0 && ms <= LastSettingsQueryMs + kQuerySettingsEachMs) { if (LastSettingsQueryMs > 0 && ms <= LastSettingsQueryMs + kQuerySettingsEachMs) {
return; return;
} }
LastSettingsQueryMs = ms; LastSettingsQueryMs = ms;
queryQuietHours(); QueryQuietHours();
queryUserNotificationState(); QueryFocusAssist();
QueryUserNotificationState();
} }
} // namespace } // namespace
bool SkipAudio() { bool SkipAudio() {
querySystemNotificationSettings(); QuerySystemNotificationSettings();
if (UserNotificationState == QUNS_NOT_PRESENT if (UserNotificationState == QUNS_NOT_PRESENT
|| UserNotificationState == QUNS_PRESENTATION_MODE || UserNotificationState == QUNS_PRESENTATION_MODE
|| QuietHoursEnabled) { || QuietHoursEnabled
|| FocusAssistBlocks) {
return true; return true;
} }
if (const auto filter = EventFilter::GetInstance()) { if (const auto filter = EventFilter::GetInstance()) {
@ -726,12 +805,13 @@ bool SkipAudio() {
} }
bool SkipToast() { bool SkipToast() {
querySystemNotificationSettings(); QuerySystemNotificationSettings();
if (UserNotificationState == QUNS_PRESENTATION_MODE if (UserNotificationState == QUNS_PRESENTATION_MODE
|| UserNotificationState == QUNS_RUNNING_D3D_FULL_SCREEN || UserNotificationState == QUNS_RUNNING_D3D_FULL_SCREEN
//|| UserNotificationState == QUNS_BUSY //|| UserNotificationState == QUNS_BUSY
|| QuietHoursEnabled) { || QuietHoursEnabled
|| FocusAssistBlocks) {
return true; return true;
} }
return false; return false;

View File

@ -0,0 +1,79 @@
// © Rafael Rivera
// License: MIT
import "oaidl.idl";
[uuid(e0b5ef8b-a9b4-497a-8f71-08dd5c8ab2bf)]
library QuietHours
{
[uuid(f53321fa-34f8-4b7f-b9a3-361877cb94cf)]
coclass QuietHoursSettings
{
[default] interface IQuietHoursSettings;
}
[uuid(af86e2e0-b12d-4c6a-9c5a-d7aa65101e90)]
interface IQuietMoment : IUnknown
{
// Incomplete
}
[uuid(e813fe81-62b6-417d-b951-9d2e08486ac1)]
interface IQuietHoursProfile : IUnknown
{
[propget] HRESULT DisplayName([out, string, retval] LPWSTR* displayName);
[propget] HRESULT ProfileId([out, string, retval] LPWSTR* profileId);
HRESULT GetSetting(int setting, [out, retval] int* value);
HRESULT PutSetting(int setting, int value);
[propget] HRESULT IsCustomizable([out, retval] BOOL* result);
HRESULT GetAllowedContacts([out] UINT32* count, [out, retval] LPWSTR* allowedContacts);
HRESULT AddAllowedContact([in, string] LPWSTR allowedContact);
HRESULT RemoveAllowedContact([in, string] LPWSTR allowedContact);
HRESULT GetAllowedApps([out] UINT32* count, [out, retval] LPWSTR** allowedApps);
HRESULT AddAllowedApp([in, string] LPWSTR allowedApp);
HRESULT RemoveAllowedApp([in, string] LPWSTR allowedApp);
[propget] HRESULT Description([out, string, retval] LPWSTR* description);
[propget] HRESULT CustomizeLinkText([out, string, retval] LPWSTR* linkText);
[propget] HRESULT RestrictiveLevel([out, string, retval] LPWSTR* restrictiveLevel);
}
[uuid(cd86a976-8ea9-404b-a197-42e73dbaa901)]
interface IQuietHoursPinnedContactManager : IUnknown
{
HRESULT GetPinnedContactList([out] UINT32* count, [out, string, retval] LPWSTR* pinnedContacts);
}
[uuid(b0217783-87b7-422c-b902-5c148c14f150)]
interface IQuietMomentsManager : IUnknown
{
HRESULT GetAllQuietMomentModes([out] UINT32* count, [out, retval] UINT32** quietMomentModes);
HRESULT GetQuietMoment([in] UINT32 quietMomentId, [out, retval] IQuietMoment** quietMoment);
HRESULT TurnOffCurrentlyActiveQuietMoment();
HRESULT GetActiveQuietMoment([out, retval] UINT32* quietMomentId);
}
typedef struct _QH_PROFILE_DATA
{
char do_not_use__incomplete; // Incomplete
} QH_PROFILE_DATA;
[uuid(6bff4732-81ec-4ffb-ae67-b6c1bc29631f)]
interface IQuietHoursSettings : IUnknown
{
[propget] HRESULT UserSelectedProfile([out, string, retval] LPWSTR* profileId);
[propput] HRESULT UserSelectedProfile([in] LPWSTR profileId);
HRESULT GetProfile([in, string] LPWSTR profileId, [out, retval] IQuietHoursProfile**);
HRESULT GetAllProfileData(UINT32* count, QH_PROFILE_DATA*);
HRESULT GetDisplayNameForProfile([in, string] LPWSTR profileId, [out, string, retval] LPWSTR* displayName);
[propget] HRESULT QuietMomentsManager([out, retval] IQuietMomentsManager**);
[propget] HRESULT OffProfileId([out, string, retval] LPWSTR* profileId);
[propget] HRESULT ActiveQuietMomentProfile([out, string, retval] LPWSTR* profileId);
[propput] HRESULT ActiveQuietMomentProfile([in] LPWSTR profileId);
[propget] HRESULT ActiveProfile([out, string, retval] LPWSTR* profileId);
[propget] HRESULT QuietHoursPinnedContactManager([out, retval] IQuietHoursPinnedContactManager**);
[propput] HRESULT QuietMomentsShowSummaryEnabled([out, retval] BOOL* isEnabled);
HRESULT GetAlwaysAllowedApps([out] UINT32* count, [out, string, retval] LPWSTR** allowedApps);
HRESULT StartProcessing();
HRESULT StopProcessing();
}
}

View File

@ -0,0 +1,43 @@
# This file is part of Telegram Desktop,
# the official desktop application for the Telegram messaging service.
#
# For license and copyright information please follow this link:
# https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
function(generate_midl target_name idl_file)
set(gen_dst ${CMAKE_CURRENT_BINARY_DIR}/gen)
file(MAKE_DIRECTORY ${gen_dst})
get_filename_component(idl_file_name ${idl_file} NAME_WLE)
set(gen_timestamp ${gen_dst}/midl_${idl_file_name}.timestamp)
set(gen_files
${gen_dst}/${idl_file_name}_i.c
${gen_dst}/${idl_file_name}_h.h
)
if (build_win64)
set(env x64)
else()
set(env win32)
endif()
add_custom_command(
OUTPUT
${gen_timestamp}
BYPRODUCTS
${gen_files}
COMMAND
midl
/out ${gen_dst}
/h ${idl_file_name}_h.h
/env ${env}
/notlb
${idl_file}
COMMAND
echo 1> ${gen_timestamp}
COMMENT "Generating header from IDL (${target_name})"
DEPENDS
${idl_file}
)
generate_target(${target_name} midl ${gen_timestamp} "${gen_files}" ${gen_dst})
endfunction()

@ -1 +1 @@
Subproject commit 053ab218dfb65e9cbd7c7a1d9594fa886ba27f0b Subproject commit 3d256df61ebf4b92b79bf9eba39a33f7a885b1d3