general_settings.cpp
1 #include "pch.h" 2 #include "general_settings.h" 3 #include "auto_start_helper.h" 4 #include "tray_icon.h" 5 #include "quick_access_host.h" 6 #include "Generated files/resource.h" 7 #include "hotkey_conflict_detector.h" 8 9 #include <common/SettingsAPI/settings_helpers.h> 10 #include "powertoy_module.h" 11 #include <common/themes/windows_colors.h> 12 13 #include "trace.h" 14 #include "ai_detection.h" 15 #include <common/utils/elevation.h> 16 #include <common/version/version.h> 17 #include <common/utils/resources.h> 18 19 namespace 20 { 21 json::JsonValue create_empty_shortcut_array_value() 22 { 23 return json::JsonValue::Parse(L"[]"); 24 } 25 26 void ensure_ignored_conflict_properties_shape(json::JsonObject& obj) 27 { 28 if (!json::has(obj, L"ignored_shortcuts", json::JsonValueType::Array)) 29 { 30 obj.SetNamedValue(L"ignored_shortcuts", create_empty_shortcut_array_value()); 31 } 32 } 33 34 json::JsonObject create_default_ignored_conflict_properties() 35 { 36 json::JsonObject obj; 37 ensure_ignored_conflict_properties_shape(obj); 38 return obj; 39 } 40 41 DashboardSortOrder parse_dashboard_sort_order(const json::JsonObject& obj, DashboardSortOrder fallback) 42 { 43 if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::Number)) 44 { 45 const auto raw_value = static_cast<int>(obj.GetNamedNumber(L"dashboard_sort_order", static_cast<double>(static_cast<int>(fallback)))); 46 return raw_value == static_cast<int>(DashboardSortOrder::ByStatus) ? DashboardSortOrder::ByStatus : DashboardSortOrder::Alphabetical; 47 } 48 49 if (json::has(obj, L"dashboard_sort_order", json::JsonValueType::String)) 50 { 51 const auto raw = obj.GetNamedString(L"dashboard_sort_order"); 52 if (raw == L"ByStatus") 53 { 54 return DashboardSortOrder::ByStatus; 55 } 56 57 if (raw == L"Alphabetical") 58 { 59 return DashboardSortOrder::Alphabetical; 60 } 61 } 62 63 return fallback; 64 } 65 } 66 67 // TODO: would be nice to get rid of these globals, since they're basically cached json settings 68 static std::wstring settings_theme = L"system"; 69 static bool show_tray_icon = true; 70 static bool show_theme_adaptive_tray_icon = false; 71 static bool run_as_elevated = false; 72 static bool show_new_updates_toast_notification = true; 73 static bool download_updates_automatically = true; 74 static bool show_whats_new_after_updates = true; 75 static bool enable_experimentation = true; 76 static bool enable_warnings_elevated_apps = true; 77 static bool enable_quick_access = true; 78 static PowerToysSettings::HotkeyObject quick_access_shortcut; 79 static DashboardSortOrder dashboard_sort_order = DashboardSortOrder::Alphabetical; 80 static json::JsonObject ignored_conflict_properties = create_default_ignored_conflict_properties(); 81 82 json::JsonObject GeneralSettings::to_json() 83 { 84 json::JsonObject result; 85 86 auto ignoredProps = ignoredConflictProperties; 87 ensure_ignored_conflict_properties_shape(ignoredProps); 88 89 result.SetNamedValue(L"startup", json::value(isStartupEnabled)); 90 if (!startupDisabledReason.empty()) 91 { 92 result.SetNamedValue(L"startup_disabled_reason", json::value(startupDisabledReason)); 93 } 94 95 json::JsonObject enabled; 96 for (const auto& [name, isEnabled] : isModulesEnabledMap) 97 { 98 enabled.SetNamedValue(name, json::value(isEnabled)); 99 } 100 result.SetNamedValue(L"enabled", std::move(enabled)); 101 102 result.SetNamedValue(L"show_tray_icon", json::value(showSystemTrayIcon)); 103 result.SetNamedValue(L"show_theme_adaptive_tray_icon", json::value(showThemeAdaptiveTrayIcon)); 104 result.SetNamedValue(L"is_elevated", json::value(isElevated)); 105 result.SetNamedValue(L"run_elevated", json::value(isRunElevated)); 106 result.SetNamedValue(L"show_new_updates_toast_notification", json::value(showNewUpdatesToastNotification)); 107 result.SetNamedValue(L"download_updates_automatically", json::value(downloadUpdatesAutomatically)); 108 result.SetNamedValue(L"show_whats_new_after_updates", json::value(showWhatsNewAfterUpdates)); 109 result.SetNamedValue(L"enable_experimentation", json::value(enableExperimentation)); 110 result.SetNamedValue(L"dashboard_sort_order", json::value(static_cast<int>(dashboardSortOrder))); 111 result.SetNamedValue(L"is_admin", json::value(isAdmin)); 112 result.SetNamedValue(L"enable_warnings_elevated_apps", json::value(enableWarningsElevatedApps)); 113 result.SetNamedValue(L"enable_quick_access", json::value(enableQuickAccess)); 114 result.SetNamedValue(L"quick_access_shortcut", quickAccessShortcut.get_json()); 115 result.SetNamedValue(L"theme", json::value(theme)); 116 result.SetNamedValue(L"system_theme", json::value(systemTheme)); 117 result.SetNamedValue(L"powertoys_version", json::value(powerToysVersion)); 118 result.SetNamedValue(L"ignored_conflict_properties", json::value(ignoredProps)); 119 120 return result; 121 } 122 123 json::JsonObject load_general_settings() 124 { 125 auto loaded = PTSettingsHelper::load_general_settings(); 126 settings_theme = loaded.GetNamedString(L"theme", L"system"); 127 if (settings_theme != L"dark" && settings_theme != L"light") 128 { 129 settings_theme = L"system"; 130 } 131 show_tray_icon = loaded.GetNamedBoolean(L"show_tray_icon", true); 132 show_theme_adaptive_tray_icon = loaded.GetNamedBoolean(L"show_theme_adaptive_tray_icon", false); 133 run_as_elevated = loaded.GetNamedBoolean(L"run_elevated", false); 134 show_new_updates_toast_notification = loaded.GetNamedBoolean(L"show_new_updates_toast_notification", true); 135 download_updates_automatically = loaded.GetNamedBoolean(L"download_updates_automatically", true) && check_user_is_admin(); 136 show_whats_new_after_updates = loaded.GetNamedBoolean(L"show_whats_new_after_updates", true); 137 enable_experimentation = loaded.GetNamedBoolean(L"enable_experimentation", true); 138 enable_warnings_elevated_apps = loaded.GetNamedBoolean(L"enable_warnings_elevated_apps", true); 139 enable_quick_access = loaded.GetNamedBoolean(L"enable_quick_access", true); 140 if (json::has(loaded, L"quick_access_shortcut", json::JsonValueType::Object)) 141 { 142 quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(loaded.GetNamedObject(L"quick_access_shortcut")); 143 } 144 dashboard_sort_order = parse_dashboard_sort_order(loaded, dashboard_sort_order); 145 146 if (json::has(loaded, L"ignored_conflict_properties", json::JsonValueType::Object)) 147 { 148 ignored_conflict_properties = loaded.GetNamedObject(L"ignored_conflict_properties"); 149 } 150 else 151 { 152 ignored_conflict_properties = create_default_ignored_conflict_properties(); 153 } 154 155 ensure_ignored_conflict_properties_shape(ignored_conflict_properties); 156 157 return loaded; 158 } 159 160 GeneralSettings get_general_settings() 161 { 162 const bool is_user_admin = check_user_is_admin(); 163 GeneralSettings settings 164 { 165 .showSystemTrayIcon = show_tray_icon, 166 .showThemeAdaptiveTrayIcon = show_theme_adaptive_tray_icon, 167 .isElevated = is_process_elevated(), 168 .isRunElevated = run_as_elevated, 169 .isAdmin = is_user_admin, 170 .enableWarningsElevatedApps = enable_warnings_elevated_apps, 171 .enableQuickAccess = enable_quick_access, 172 .quickAccessShortcut = quick_access_shortcut, 173 .showNewUpdatesToastNotification = show_new_updates_toast_notification, 174 .downloadUpdatesAutomatically = download_updates_automatically && is_user_admin, 175 .showWhatsNewAfterUpdates = show_whats_new_after_updates, 176 .enableExperimentation = enable_experimentation, 177 .dashboardSortOrder = dashboard_sort_order, 178 .theme = settings_theme, 179 .systemTheme = WindowsColors::is_dark_mode() ? L"dark" : L"light", 180 .powerToysVersion = get_product_version(), 181 .ignoredConflictProperties = ignored_conflict_properties 182 }; 183 184 ensure_ignored_conflict_properties_shape(settings.ignoredConflictProperties); 185 186 settings.isStartupEnabled = is_auto_start_task_active_for_this_user(); 187 188 for (auto& [name, powertoy] : modules()) 189 { 190 settings.isModulesEnabledMap[name] = powertoy->is_enabled(); 191 } 192 193 return settings; 194 } 195 196 void apply_module_status_update(const json::JsonObject& module_config, bool save) 197 { 198 Logger::info(L"apply_module_status_update: {}", std::wstring{ module_config.ToString() }); 199 200 // Expected format: {"ModuleName": true/false} - only one module per update 201 auto iter = module_config.First(); 202 if (!iter.HasCurrent()) 203 { 204 Logger::warn(L"apply_module_status_update: Empty module config"); 205 return; 206 } 207 208 const auto& element = iter.Current(); 209 const auto value = element.Value(); 210 if (value.ValueType() != json::JsonValueType::Boolean) 211 { 212 Logger::warn(L"apply_module_status_update: Invalid value type for module status"); 213 return; 214 } 215 216 const std::wstring name{ element.Key().c_str() }; 217 if (modules().find(name) == modules().end()) 218 { 219 Logger::warn(L"apply_module_status_update: Module {} not found", name); 220 return; 221 } 222 223 PowertoyModule& powertoy = modules().at(name); 224 const bool module_inst_enabled = powertoy->is_enabled(); 225 bool target_enabled = value.GetBoolean(); 226 227 auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); 228 if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) 229 { 230 // Apply the GPO Rule. 231 target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; 232 } 233 234 if (module_inst_enabled == target_enabled) 235 { 236 Logger::info(L"apply_module_status_update: Module {} already in target state {}", name, target_enabled); 237 return; 238 } 239 240 if (target_enabled) 241 { 242 Logger::info(L"apply_module_status_update: Enabling powertoy {}", name); 243 powertoy->enable(); 244 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 245 hkmng.EnableHotkeyByModule(name); 246 247 // Trigger AI capability detection when ImageResizer is enabled 248 if (name == L"Image Resizer") 249 { 250 Logger::info(L"ImageResizer enabled, triggering AI capability detection"); 251 DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled 252 } 253 } 254 else 255 { 256 Logger::info(L"apply_module_status_update: Disabling powertoy {}", name); 257 powertoy->disable(); 258 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 259 hkmng.DisableHotkeyByModule(name); 260 } 261 // Sync the hotkey state with the module state, so it can be removed for disabled modules. 262 powertoy.UpdateHotkeyEx(); 263 264 if (save) 265 { 266 // Load existing settings and only update the specific module's enabled state 267 json::JsonObject current_settings = PTSettingsHelper::load_general_settings(); 268 269 json::JsonObject enabled; 270 if (current_settings.HasKey(L"enabled")) 271 { 272 enabled = current_settings.GetNamedObject(L"enabled"); 273 } 274 275 // Check if the saved state is different from the requested state 276 bool current_saved = enabled.HasKey(name) ? enabled.GetNamedBoolean(name, true) : true; 277 278 if (current_saved != target_enabled) 279 { 280 // Update only this module's enabled state 281 enabled.SetNamedValue(name, json::value(target_enabled)); 282 current_settings.SetNamedValue(L"enabled", enabled); 283 284 PTSettingsHelper::save_general_settings(current_settings); 285 286 GeneralSettings settings_for_trace = get_general_settings(); 287 Trace::SettingsChanged(settings_for_trace); 288 } 289 } 290 } 291 292 void apply_general_settings(const json::JsonObject& general_configs, bool save) 293 { 294 std::wstring old_settings_json_string; 295 if (save) 296 { 297 old_settings_json_string = get_general_settings().to_json().Stringify().c_str(); 298 } 299 300 Logger::info(L"apply_general_settings: {}", std::wstring{ general_configs.ToString() }); 301 run_as_elevated = general_configs.GetNamedBoolean(L"run_elevated", false); 302 303 enable_warnings_elevated_apps = general_configs.GetNamedBoolean(L"enable_warnings_elevated_apps", true); 304 305 bool new_enable_quick_access = general_configs.GetNamedBoolean(L"enable_quick_access", true); 306 Logger::info(L"apply_general_settings: enable_quick_access={}, new_enable_quick_access={}", enable_quick_access, new_enable_quick_access); 307 308 PowerToysSettings::HotkeyObject new_quick_access_shortcut; 309 if (json::has(general_configs, L"quick_access_shortcut", json::JsonValueType::Object)) 310 { 311 new_quick_access_shortcut = PowerToysSettings::HotkeyObject::from_json(general_configs.GetNamedObject(L"quick_access_shortcut")); 312 } 313 314 auto hotkey_equals = [](const PowerToysSettings::HotkeyObject& a, const PowerToysSettings::HotkeyObject& b) { 315 return a.get_code() == b.get_code() && 316 a.get_modifiers() == b.get_modifiers(); 317 }; 318 319 if (enable_quick_access != new_enable_quick_access || !hotkey_equals(quick_access_shortcut, new_quick_access_shortcut)) 320 { 321 enable_quick_access = new_enable_quick_access; 322 quick_access_shortcut = new_quick_access_shortcut; 323 324 if (enable_quick_access) 325 { 326 QuickAccessHost::start(); 327 } 328 else 329 { 330 QuickAccessHost::stop(); 331 } 332 update_quick_access_hotkey(enable_quick_access, quick_access_shortcut); 333 } 334 335 show_new_updates_toast_notification = general_configs.GetNamedBoolean(L"show_new_updates_toast_notification", true); 336 337 download_updates_automatically = general_configs.GetNamedBoolean(L"download_updates_automatically", true); 338 show_whats_new_after_updates = general_configs.GetNamedBoolean(L"show_whats_new_after_updates", true); 339 340 enable_experimentation = general_configs.GetNamedBoolean(L"enable_experimentation", true); 341 dashboard_sort_order = parse_dashboard_sort_order(general_configs, dashboard_sort_order); 342 343 // apply_general_settings is called by the runner's WinMain, so we can just force the run at startup gpo rule here. 344 auto gpo_run_as_startup = powertoys_gpo::getConfiguredRunAtStartupValue(); 345 346 if (json::has(general_configs, L"startup", json::JsonValueType::Boolean)) 347 { 348 bool startup = general_configs.GetNamedBoolean(L"startup"); 349 350 if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled) 351 { 352 startup = true; 353 } 354 else if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_disabled) 355 { 356 startup = false; 357 } 358 359 if (startup) 360 { 361 if (is_process_elevated()) 362 { 363 delete_auto_start_task_for_this_user(); 364 create_auto_start_task_for_this_user(run_as_elevated); 365 } 366 else 367 { 368 if (!is_auto_start_task_active_for_this_user()) 369 { 370 delete_auto_start_task_for_this_user(); 371 create_auto_start_task_for_this_user(false); 372 373 run_as_elevated = false; 374 } 375 else if (!general_configs.GetNamedBoolean(L"run_elevated", false)) 376 { 377 delete_auto_start_task_for_this_user(); 378 create_auto_start_task_for_this_user(false); 379 } 380 } 381 } 382 else 383 { 384 delete_auto_start_task_for_this_user(); 385 } 386 } 387 else 388 { 389 delete_auto_start_task_for_this_user(); 390 if (gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_enabled || gpo_run_as_startup == powertoys_gpo::gpo_rule_configured_not_configured) 391 { 392 create_auto_start_task_for_this_user(run_as_elevated); 393 } 394 } 395 396 if (json::has(general_configs, L"enabled")) 397 { 398 for (const auto& enabled_element : general_configs.GetNamedObject(L"enabled")) 399 { 400 const auto value = enabled_element.Value(); 401 if (value.ValueType() != json::JsonValueType::Boolean) 402 { 403 continue; 404 } 405 const std::wstring name{ enabled_element.Key().c_str() }; 406 const bool found = modules().find(name) != modules().end(); 407 if (!found) 408 { 409 continue; 410 } 411 PowertoyModule& powertoy = modules().at(name); 412 const bool module_inst_enabled = powertoy->is_enabled(); 413 bool target_enabled = value.GetBoolean(); 414 415 auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); 416 if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) 417 { 418 // Apply the GPO Rule. 419 target_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; 420 } 421 422 if (module_inst_enabled == target_enabled) 423 { 424 continue; 425 } 426 if (target_enabled) 427 { 428 Logger::info(L"apply_general_settings: Enabling powertoy {}", name); 429 powertoy->enable(); 430 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 431 hkmng.EnableHotkeyByModule(name); 432 433 // Trigger AI capability detection when ImageResizer is enabled 434 if (name == L"Image Resizer") 435 { 436 Logger::info(L"ImageResizer enabled, triggering AI capability detection"); 437 DetectAiCapabilitiesAsync(true); // Skip settings check since we know it's being enabled 438 } 439 } 440 else 441 { 442 Logger::info(L"apply_general_settings: Disabling powertoy {}", name); 443 powertoy->disable(); 444 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 445 hkmng.DisableHotkeyByModule(name); 446 } 447 // Sync the hotkey state with the module state, so it can be removed for disabled modules. 448 powertoy.UpdateHotkeyEx(); 449 } 450 } 451 452 if (json::has(general_configs, L"theme", json::JsonValueType::String)) 453 { 454 settings_theme = general_configs.GetNamedString(L"theme"); 455 } 456 457 if (json::has(general_configs, L"show_tray_icon", json::JsonValueType::Boolean)) 458 { 459 show_tray_icon = general_configs.GetNamedBoolean(L"show_tray_icon"); 460 set_tray_icon_visible(show_tray_icon); 461 } 462 463 if (json::has(general_configs, L"show_theme_adaptive_tray_icon", json::JsonValueType::Boolean)) 464 { 465 bool new_theme_adaptive = general_configs.GetNamedBoolean(L"show_theme_adaptive_tray_icon"); 466 Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon current={}, new={}", 467 show_theme_adaptive_tray_icon, new_theme_adaptive); 468 if (show_theme_adaptive_tray_icon != new_theme_adaptive) 469 { 470 show_theme_adaptive_tray_icon = new_theme_adaptive; 471 set_tray_icon_theme_adaptive(show_theme_adaptive_tray_icon); 472 } 473 else 474 { 475 Logger::info(L"apply_general_settings: show_theme_adaptive_tray_icon unchanged, skipping update"); 476 } 477 } 478 else 479 { 480 Logger::warn(L"apply_general_settings: show_theme_adaptive_tray_icon not found in config"); 481 } 482 483 if (json::has(general_configs, L"ignored_conflict_properties", json::JsonValueType::Object)) 484 { 485 ignored_conflict_properties = general_configs.GetNamedObject(L"ignored_conflict_properties"); 486 ensure_ignored_conflict_properties_shape(ignored_conflict_properties); 487 } 488 489 if (save) 490 { 491 GeneralSettings save_settings = get_general_settings(); 492 std::wstring new_settings_json_string = save_settings.to_json().Stringify().c_str(); 493 if (old_settings_json_string != new_settings_json_string) 494 { 495 PTSettingsHelper::save_general_settings(save_settings.to_json()); 496 Trace::SettingsChanged(save_settings); 497 } 498 } 499 } 500 501 void start_enabled_powertoys() 502 { 503 std::unordered_set<std::wstring> powertoys_to_disable; 504 std::unordered_map<std::wstring, powertoys_gpo::gpo_rule_configured_t> powertoys_gpo_configuration; 505 // Take into account default values supplied by modules themselves and gpo configurations 506 for (auto& [name, powertoy] : modules()) 507 { 508 auto gpo_rule = powertoy->gpo_policy_enabled_configuration(); 509 powertoys_gpo_configuration[name] = gpo_rule; 510 if (gpo_rule == powertoys_gpo::gpo_rule_configured_unavailable) 511 { 512 Logger::warn(L"start_enabled_powertoys: couldn't read the gpo rule for Powertoy {}", name); 513 } 514 if (gpo_rule == powertoys_gpo::gpo_rule_configured_wrong_value) 515 { 516 Logger::warn(L"start_enabled_powertoys: gpo rule for Powertoy {} is set to an unknown value", name); 517 } 518 519 if (!powertoy->is_enabled_by_default()) 520 powertoys_to_disable.emplace(name); 521 } 522 523 json::JsonObject general_settings; 524 try 525 { 526 general_settings = load_general_settings(); 527 if (general_settings.HasKey(L"enabled")) 528 { 529 json::JsonObject enabled = general_settings.GetNamedObject(L"enabled"); 530 for (const auto& disabled_element : enabled) 531 { 532 std::wstring disable_module_name{ static_cast<std::wstring_view>(disabled_element.Key()) }; 533 534 if (powertoys_gpo_configuration.find(disable_module_name) != powertoys_gpo_configuration.end() && (powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_enabled || powertoys_gpo_configuration[disable_module_name] == powertoys_gpo::gpo_rule_configured_disabled)) 535 { 536 // If gpo forces the enabled setting, no need to check the setting for this PowerToy. It will be applied later on this function. 537 continue; 538 } 539 540 // Disable explicitly disabled modules 541 if (!disabled_element.Value().GetBoolean()) 542 { 543 Logger::info(L"start_enabled_powertoys: Powertoy {} explicitly disabled", disable_module_name); 544 powertoys_to_disable.emplace(std::move(disable_module_name)); 545 } 546 // If module was scheduled for disable, but it's enabled in the settings - override default value 547 else if (auto it = powertoys_to_disable.find(disable_module_name); it != end(powertoys_to_disable)) 548 { 549 Logger::info(L"start_enabled_powertoys: Overriding default enabled value for {} powertoy", disable_module_name); 550 powertoys_to_disable.erase(it); 551 } 552 } 553 } 554 } 555 catch (...) 556 { 557 } 558 559 for (auto& [name, powertoy] : modules()) 560 { 561 bool should_powertoy_be_enabled = true; 562 563 auto gpo_rule = powertoys_gpo_configuration.find(name) != powertoys_gpo_configuration.end() ? powertoys_gpo_configuration[name] : powertoys_gpo::gpo_rule_configured_not_configured; 564 565 if (gpo_rule == powertoys_gpo::gpo_rule_configured_enabled || gpo_rule == powertoys_gpo::gpo_rule_configured_disabled) 566 { 567 // Apply the GPO Rule. 568 should_powertoy_be_enabled = gpo_rule == powertoys_gpo::gpo_rule_configured_enabled; 569 Logger::info(L"start_enabled_powertoys: GPO sets the enabled state for {} powertoy as {}", name, should_powertoy_be_enabled); 570 } 571 else if (powertoys_to_disable.contains(name)) 572 { 573 // Apply the settings or default information provided by the PowerToy on first run. 574 should_powertoy_be_enabled = false; 575 } 576 577 if (should_powertoy_be_enabled) 578 { 579 Logger::info(L"start_enabled_powertoys: Enabling powertoy {}", name); 580 powertoy->enable(); 581 auto& hkmng = HotkeyConflictDetector::HotkeyConflictManager::GetInstance(); 582 hkmng.EnableHotkeyByModule(name); 583 powertoy.UpdateHotkeyEx(); 584 } 585 } 586 } 587 588