diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index a21a031b39..e9f9ccc8cc 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -14,14 +14,12 @@ Acceleratorkeys ACCEPTFILES accessibile accessibilityinsights -acf Acl aclapi AColumn acos acrt Actioncenter -Actionkeyword activatable ACTIVATEAPP activationaction @@ -144,10 +142,8 @@ bc bcc bck Bcl -bdaa bddac BEGINLABELEDIT -benjamhooper betadele betsegaw BGR @@ -184,7 +180,6 @@ bricelam BRIGHTGREEN Browsable bsd -bsearch BSODs bstr BText @@ -439,7 +434,6 @@ DELA deletethis delims DENORMAL -deondre depersist deprioritized deps @@ -637,7 +631,6 @@ EFFE efgh EFile egistry -Elems ELogo elseif Emoji @@ -660,7 +653,6 @@ epicgames ERASEBKGND EREOF EResize -eriawan errc errorlevel ERRORMESSAGE @@ -717,9 +709,7 @@ Favicon fcharset fd fda -FDFC feimage -FFB ffcd ffd FFDDDDDD @@ -731,7 +721,6 @@ FILEFLAGS FILEFLAGSMASK FILEOP FILEOS -filesfolder FILESUBTYPE FILESYSPATH filesystem @@ -799,7 +788,6 @@ Giftbox github githubusercontent gitignore -globalplugins globals gmx google @@ -817,7 +805,6 @@ HACCEL hangeul hanja hanselman -happlebao hardcoded HARDWAREINPUT hashcode @@ -853,9 +840,8 @@ hitinfo HIWORD hk HKCC -HKCU HKCR -HKE +HKCU hkey HKL HKLM @@ -929,6 +915,7 @@ IComparer ICONERROR ICONINFORMATION ICONQUESTION +Iconsempty Iconset IContext ICONWARNING @@ -1099,10 +1086,10 @@ ITemplate ITEMSTATEICONCLICK ITest ith -itsme IThrottled IThumbnail ITrigger +itsme IUI IUnknown IUri @@ -1122,7 +1109,6 @@ Jarryd javascript jfif jgeosdfsdsgmkedfgdfgdfgbkmhcgcflmi -jhutchings jjw jobject jp @@ -1133,7 +1119,6 @@ JPN json JSONOf jsonval -jsoref jsx junja jxr @@ -1366,7 +1351,6 @@ moz mozilla mpmc mru -msazure msbuild msc msclr @@ -1375,7 +1359,6 @@ mscorlib msdata msdn msedge -MSGBOX mshtmdid msi MSIHANDLE @@ -1438,7 +1421,7 @@ NESW netcore netcoreapp netframework -netfx +NETFX netsh netstandard Neue @@ -1550,7 +1533,7 @@ onedrive onedrivelogo ONITEM onstd -OOBE +oobe opencode opensource Openthe @@ -1745,7 +1728,7 @@ queryfocus QUERYOPEN QUEUESYNC qwertyuiopasdfghjklzxcvbnm -QWORD +qword qwrtyuiopsghjklzxvnm Radiobuttons RAII @@ -1791,7 +1774,6 @@ REMAPUNSUCCESSFUL Remotable REMOTEDISPLAY REMOTESESSION -removefolder Removelnk renamable RENAMEONCOLLISION @@ -1858,8 +1840,7 @@ RUNLEVEL runsettings runtimeclass runtimeconfig -Runtimes -Rutkas +runtimes rv rvalue rvm @@ -1889,10 +1870,9 @@ SEARCHFOR searchqueryhelper SEARCHREPLACEGROUP searchterm -Searcn Secur securityoverview -Segoe +segoe Sekan SENDCHANGE sendinput @@ -1995,7 +1975,6 @@ SLogo SMALLICON SMTO snd -snickler somil SORTDOWN SOURCECLIENTAREAONLY @@ -2114,7 +2093,6 @@ syslog SYSMENU systemd SYSTEMTIME -systray sz tadele Tahoma @@ -2315,7 +2293,6 @@ VDId vec VERBSONLY VERBW -verifybothfolderfilesequal verrsrc VERSIONINFO Versioning @@ -2382,7 +2359,6 @@ webpage website webview wekyb -welcomeoverview Whichdoes whitespaces WIC @@ -2497,7 +2473,6 @@ XElement XFile XIncrement XInstance -XJson xlink XLoc xml @@ -2518,7 +2493,6 @@ YDiff YESNO YIncrement yinwang -YJson YLogo yml YOffset diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs index 1fa0af4bd9..be32db0888 100644 --- a/installer/PowerToysSetup/Product.wxs +++ b/installer/PowerToysSetup/Product.wxs @@ -268,7 +268,10 @@ - + + + + @@ -683,6 +686,20 @@ + + + + + + + + + + + + + + @@ -778,6 +795,8 @@ + + diff --git a/src/common/SettingsAPI/settings_helpers.cpp b/src/common/SettingsAPI/settings_helpers.cpp index 3bd8dd12fd..646cd1a76f 100644 --- a/src/common/SettingsAPI/settings_helpers.cpp +++ b/src/common/SettingsAPI/settings_helpers.cpp @@ -5,6 +5,7 @@ namespace PTSettingsHelper { constexpr inline const wchar_t* settings_filename = L"\\settings.json"; constexpr inline const wchar_t* log_settings_filename = L"log_settings.json"; + constexpr inline const wchar_t* oobe_filename = L"oobe_settings.json"; std::wstring get_root_save_folder_location() { @@ -77,4 +78,34 @@ namespace PTSettingsHelper result = result.append(log_settings_filename); return result.wstring(); } + + bool get_oobe_opened_state() + { + std::filesystem::path oobePath(PTSettingsHelper::get_root_save_folder_location()); + oobePath = oobePath.append(oobe_filename); + if (std::filesystem::exists(oobePath)) + { + auto saved_settings = json::from_file(oobePath.c_str()); + if (!saved_settings.has_value()) + { + return false; + } + + bool opened = saved_settings->GetNamedBoolean(L"openedAtFirstLaunch", false); + return opened; + } + + return false; + } + + void save_oobe_opened_state() + { + std::filesystem::path oobePath(PTSettingsHelper::get_root_save_folder_location()); + oobePath = oobePath.append(oobe_filename); + + json::JsonObject obj; + obj.SetNamedValue(L"openedAtFirstLaunch", json::value(true)); + + json::to_file(oobePath.c_str(), obj); + } } diff --git a/src/common/SettingsAPI/settings_helpers.h b/src/common/SettingsAPI/settings_helpers.h index 2437620f5d..6e220f70ea 100644 --- a/src/common/SettingsAPI/settings_helpers.h +++ b/src/common/SettingsAPI/settings_helpers.h @@ -14,4 +14,7 @@ namespace PTSettingsHelper void save_general_settings(const json::JsonObject& settings); json::JsonObject load_general_settings(); std::wstring get_log_settings_file_location(); + + bool get_oobe_opened_state(); + void save_oobe_opened_state(); } diff --git a/src/common/interop/interop.cpp b/src/common/interop/interop.cpp index ab0eb2ebb1..8f682d17e9 100644 --- a/src/common/interop/interop.cpp +++ b/src/common/interop/interop.cpp @@ -138,5 +138,13 @@ public static String ^ PowerLauncherSharedEvent() { return gcnew String(CommonSharedConstants::POWER_LAUNCHER_SHARED_EVENT); } + + static String ^ ShowColorPickerSharedEvent() { + return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT); + } + + static String ^ ShowShortcutGuideSharedEvent() { + return gcnew String(CommonSharedConstants::SHOW_SHORTCUT_GUIDE_SHARED_EVENT); + } }; } diff --git a/src/common/interop/shared_constants.h b/src/common/interop/shared_constants.h index 5446057c92..c3e8b0fc71 100644 --- a/src/common/interop/shared_constants.h +++ b/src/common/interop/shared_constants.h @@ -13,6 +13,12 @@ namespace CommonSharedConstants // Path to the event used by PowerLauncher const wchar_t POWER_LAUNCHER_SHARED_EVENT[] = L"Local\\PowerToysRunInvokeEvent-30f26ad7-d36d-4c0e-ab02-68bb5ff3c4ab"; + // Path to the event used to show Color Picker + const wchar_t SHOW_COLOR_PICKER_SHARED_EVENT[] = L"Local\\ShowColorPickerEvent-8c46be2a-3e05-4186-b56b-4ae986ef2525"; + + // Path to the event used to show Shortcut Guide + const wchar_t SHOW_SHORTCUT_GUIDE_SHARED_EVENT[] = L"Local\\ShowShortcutGuideEvent-6982d682-7462-404f-95af-86ae3f089c4f"; + // Max DWORD for key code to disable keys. const int VK_DISABLED = 0x100; } \ No newline at end of file diff --git a/src/modules/colorPicker/ColorPickerUI/Helpers/NativeEventWaiter.cs b/src/modules/colorPicker/ColorPickerUI/Helpers/NativeEventWaiter.cs new file mode 100644 index 0000000000..e44d4d9867 --- /dev/null +++ b/src/modules/colorPicker/ColorPickerUI/Helpers/NativeEventWaiter.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.ComponentModel.Composition; +using System.Threading; +using System.Windows; +using interop; + +namespace ColorPicker.Helpers +{ + [Export(typeof(NativeEventWaiter))] + public class NativeEventWaiter + { + private AppStateHandler _appStateHandler; + + [ImportingConstructor] + public NativeEventWaiter(AppStateHandler appStateHandler) + { + _appStateHandler = appStateHandler; + WaitForEventLoop(Constants.ShowColorPickerSharedEvent(), _appStateHandler.ShowColorPicker); + } + + public static void WaitForEventLoop(string eventName, Action callback) + { + new Thread(() => + { + var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName); + while (true) + { + if (eventHandle.WaitOne()) + { + Logger.LogInfo("Successfully waited for SHOW_COLOR_PICKER_EVENT"); + Application.Current.Dispatcher.Invoke(callback); + } + } + }).Start(); + } + } +} diff --git a/src/modules/colorPicker/ColorPickerUI/ViewModels/MainViewModel.cs b/src/modules/colorPicker/ColorPickerUI/ViewModels/MainViewModel.cs index 1bc807bf64..23bd9cc30f 100644 --- a/src/modules/colorPicker/ColorPickerUI/ViewModels/MainViewModel.cs +++ b/src/modules/colorPicker/ColorPickerUI/ViewModels/MainViewModel.cs @@ -26,6 +26,7 @@ namespace ColorPicker.ViewModels private readonly ZoomWindowHelper _zoomWindowHelper; private readonly AppStateHandler _appStateHandler; private readonly IUserSettings _userSettings; + private readonly NativeEventWaiter _nativeEventWaiter; /// /// Backing field for @@ -48,11 +49,13 @@ namespace ColorPicker.ViewModels ZoomWindowHelper zoomWindowHelper, AppStateHandler appStateHandler, KeyboardMonitor keyboardMonitor, + NativeEventWaiter nativeEventWaiter, IUserSettings userSettings) { _zoomWindowHelper = zoomWindowHelper; _appStateHandler = appStateHandler; _userSettings = userSettings; + _nativeEventWaiter = nativeEventWaiter; if (mouseInfoProvider != null) { diff --git a/src/modules/shortcut_guide/d2d_window.cpp b/src/modules/shortcut_guide/d2d_window.cpp index 9eed55edd7..b1161e99a9 100644 --- a/src/modules/shortcut_guide/d2d_window.cpp +++ b/src/modules/shortcut_guide/d2d_window.cpp @@ -41,6 +41,7 @@ void D2DWindow::show(UINT x, UINT y, UINT width, UINT height) on_show(); SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0); ShowWindow(hwnd, SW_SHOWNORMAL); + SetForegroundWindow(hwnd); UpdateWindow(hwnd); } diff --git a/src/modules/shortcut_guide/native_event_waiter.cpp b/src/modules/shortcut_guide/native_event_waiter.cpp new file mode 100644 index 0000000000..b038ea4ffd --- /dev/null +++ b/src/modules/shortcut_guide/native_event_waiter.cpp @@ -0,0 +1,29 @@ +#include "pch.h" +#include "native_event_waiter.h" + +void NativeEventWaiter::run() +{ + while (!aborting) + { + auto result = WaitForSingleObject(event_handle, timeout); + if (!aborting && result == WAIT_OBJECT_0) + { + action(); + } + } +} + +NativeEventWaiter::NativeEventWaiter(const std::wstring& event_name, std::function action) +{ + event_handle = CreateEventW(NULL, FALSE, FALSE, event_name.c_str()); + this->action = action; + running_thread = std::thread([&]() { run(); }); +} + +NativeEventWaiter::~NativeEventWaiter() +{ + aborting = true; + SetEvent(event_handle); + running_thread.join(); + CloseHandle(event_handle); +} diff --git a/src/modules/shortcut_guide/native_event_waiter.h b/src/modules/shortcut_guide/native_event_waiter.h new file mode 100644 index 0000000000..14bf1a2d0d --- /dev/null +++ b/src/modules/shortcut_guide/native_event_waiter.h @@ -0,0 +1,20 @@ +#pragma once +#include "pch.h" +#include "common/interop/shared_constants.h" + +class NativeEventWaiter +{ + static const int timeout = 1000; + + HANDLE event_handle; + std::function action; + std::atomic aborting; + + void run(); + std::thread running_thread; + +public: + + NativeEventWaiter(const std::wstring& event_name, std::function action); + ~NativeEventWaiter(); +}; diff --git a/src/modules/shortcut_guide/shortcut_guide.cpp b/src/modules/shortcut_guide/shortcut_guide.cpp index 22cc94398c..48bf07d49d 100644 --- a/src/modules/shortcut_guide/shortcut_guide.cpp +++ b/src/modules/shortcut_guide/shortcut_guide.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -94,6 +95,8 @@ namespace ((style & WS_THICKFRAME) == WS_THICKFRAME); return result; } + + const LPARAM eventActivateWindow = 1; } OverlayWindow::OverlayWindow() @@ -212,6 +215,13 @@ void OverlayWindow::enable() instance->target_state->toggle_force_shown(); return 0; } + + if (msg == WM_APP && lparam == eventActivateWindow) + { + instance->target_state->toggle_force_shown(); + return 0; + } + if (msg != WM_HOTKEY) { return 0; @@ -260,6 +270,12 @@ void OverlayWindow::enable() } } RegisterHotKey(winkey_popup->get_window_handle(), alternative_switch_hotkey_id, alternative_switch_modifier_mask, alternative_switch_vk_code); + + auto show_action = [&]() { + PostMessageW(winkey_popup->get_window_handle(), WM_APP, 0, eventActivateWindow); + }; + + event_waiter = std::make_unique(CommonSharedConstants::SHOW_SHORTCUT_GUIDE_SHARED_EVENT, show_action); } _enabled = true; } @@ -276,6 +292,7 @@ void OverlayWindow::disable(bool trace_event) Trace::EnableShortcutGuide(false); } UnregisterHotKey(winkey_popup->get_window_handle(), alternative_switch_hotkey_id); + event_waiter.reset(); winkey_popup->hide(); target_state->exit(); target_state.reset(); diff --git a/src/modules/shortcut_guide/shortcut_guide.h b/src/modules/shortcut_guide/shortcut_guide.h index 393bb4ec2e..88b7a37a6e 100644 --- a/src/modules/shortcut_guide/shortcut_guide.h +++ b/src/modules/shortcut_guide/shortcut_guide.h @@ -1,6 +1,7 @@ #pragma once #include #include "overlay_window.h" +#include "native_event_waiter.h" #include "Generated Files/resource.h" @@ -44,6 +45,7 @@ private: std::unique_ptr winkey_popup; bool _enabled = false; HHOOK hook_handle; + std::unique_ptr event_waiter; void init_settings(); void disable(bool trace_event); diff --git a/src/modules/shortcut_guide/shortcut_guide.vcxproj b/src/modules/shortcut_guide/shortcut_guide.vcxproj index 7d1fdec6be..b165f02eba 100644 --- a/src/modules/shortcut_guide/shortcut_guide.vcxproj +++ b/src/modules/shortcut_guide/shortcut_guide.vcxproj @@ -67,6 +67,7 @@ + @@ -83,6 +84,7 @@ + diff --git a/src/modules/shortcut_guide/shortcut_guide.vcxproj.filters b/src/modules/shortcut_guide/shortcut_guide.vcxproj.filters index 7ee044a73d..6f093d1b3f 100644 --- a/src/modules/shortcut_guide/shortcut_guide.vcxproj.filters +++ b/src/modules/shortcut_guide/shortcut_guide.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + @@ -73,6 +76,9 @@ Header Files + + Header Files + diff --git a/src/runner/main.cpp b/src/runner/main.cpp index 6f08690bb4..b57daabf84 100644 --- a/src/runner/main.cpp +++ b/src/runner/main.cpp @@ -40,6 +40,7 @@ #include #include #include +#include extern updating::notifications::strings Strings; @@ -77,12 +78,8 @@ void open_menu_from_another_instance() PostMessageW(hwnd_main, WM_COMMAND, ID_SETTINGS_MENU_COMMAND, 0); } -int runner(bool isProcessElevated, bool openSettings) +int runner(bool isProcessElevated, bool openSettings, bool openOobe) { - std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location()); - logFilePath.append(LogSettings::runnerLogPath); - Logger::init(LogSettings::runnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); - Logger::info("Runner is starting. Elevated={}", isProcessElevated); DPIAware::EnableDPIAwarenessForThisProcess(); @@ -161,6 +158,11 @@ int runner(bool isProcessElevated, bool openSettings) open_settings_window(); } + if (openOobe) + { + open_oobe_window(); + } + result = run_message_loop(); } catch (std::runtime_error& err) @@ -336,6 +338,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine break; } + std::filesystem::path logFilePath(PTSettingsHelper::get_root_save_folder_location()); + logFilePath.append(LogSettings::runnerLogPath); + Logger::init(LogSettings::runnerLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location()); + wil::unique_mutex_nothrow msi_mutex; wil::unique_mutex_nothrow msix_mutex; @@ -401,6 +407,20 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } } + bool openOobe = false; + try + { + openOobe = !PTSettingsHelper::get_oobe_opened_state(); + if (openOobe) + { + PTSettingsHelper::save_oobe_opened_state(); + } + } + catch (const std::exception& e) + { + Logger::error("Failed to get or save OOBE state with an exception: {}", e.what()); + } + int result = 0; try { @@ -411,6 +431,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine auto general_settings = load_general_settings(); const bool openSettings = std::string(lpCmdLine).find("--open-settings") != std::string::npos; + // Apply the general settings but don't save it as the modules() variable has not been loaded yet apply_general_settings(general_settings, false); int rvalue = 0; @@ -420,7 +441,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine std::string(lpCmdLine).find("--dont-elevate") != std::string::npos)) { - result = runner(elevated, openSettings); + result = runner(elevated, openSettings, openOobe); } else { diff --git a/src/runner/settings_window.cpp b/src/runner/settings_window.cpp index 97a345a9ee..7d6d45c0f9 100644 --- a/src/runner/settings_window.cpp +++ b/src/runner/settings_window.cpp @@ -277,7 +277,7 @@ BOOL run_settings_non_elevated(LPCWSTR executable_path, LPWSTR executable_args, DWORD g_settings_process_id = 0; -void run_settings_window() +void run_settings_window(bool showOobeWindow) { g_isLaunchInProgress = true; @@ -303,7 +303,7 @@ void run_settings_window() executable_path.append(L"\\PowerToysSettings.exe"); } - // Arg 2: pipe server. Generate unique names for the pipes, if getting a UUID is possible. + // Args 2,3: pipe server. Generate unique names for the pipes, if getting a UUID is possible. std::wstring powertoys_pipe_name(L"\\\\.\\pipe\\powertoys_runner_"); std::wstring settings_pipe_name(L"\\\\.\\pipe\\powertoys_settings_"); UUID temp_uuid; @@ -327,10 +327,10 @@ void run_settings_window() uuid_chars = nullptr; } - // Arg 3: process pid. + // Arg 4: process pid. DWORD powertoys_pid = GetCurrentProcessId(); - // Arg 4: settings theme. + // Arg 5: settings theme. const std::wstring settings_theme_setting{ get_general_settings().theme }; std::wstring settings_theme = L"system"; if (settings_theme_setting == L"dark" || (settings_theme_setting == L"system" && WindowsColors::is_dark_mode())) @@ -338,33 +338,18 @@ void run_settings_window() settings_theme = L"dark"; } - // Arg 4: settings theme. GeneralSettings save_settings = get_general_settings(); + // Arg 6: elevated status bool isElevated{ get_general_settings().isElevated }; - std::wstring settings_elevatedStatus; - settings_elevatedStatus = isElevated; - - if (isElevated) - { - settings_elevatedStatus = L"true"; - } - else - { - settings_elevatedStatus = L"false"; - } - + std::wstring settings_elevatedStatus = isElevated ? L"true" : L"false"; + + // Arg 7: is user an admin bool isAdmin{ get_general_settings().isAdmin }; - std::wstring settings_isUserAnAdmin; + std::wstring settings_isUserAnAdmin = isAdmin ? L"true" : L"false"; - if (isAdmin) - { - settings_isUserAnAdmin = L"true"; - } - else - { - settings_isUserAnAdmin = L"false"; - } + // Arg 8: should oobe window be shown + std::wstring settings_showOobe = showOobeWindow ? L"true" : L"false"; // create general settings file to initialize the settings file with installation configurations like : // 1. Run on start up. @@ -384,7 +369,9 @@ void run_settings_window() executable_args.append(settings_elevatedStatus); executable_args.append(L" "); executable_args.append(settings_isUserAnAdmin); - + executable_args.append(L" "); + executable_args.append(settings_showOobe); + BOOL process_created = false; // Due to a bug in .NET, running the Settings process as non-elevated @@ -510,7 +497,9 @@ void open_settings_window() { if (!g_isLaunchInProgress) { - std::thread(run_settings_window).detach(); + std::thread([]() { + run_settings_window(false); + }).detach(); } } } @@ -526,3 +515,10 @@ void close_settings_window() } } } + +void open_oobe_window() +{ + std::thread([]() { + run_settings_window(true); + }).detach(); +} diff --git a/src/runner/settings_window.h b/src/runner/settings_window.h index 0f9048f16e..c4eb56bb7c 100644 --- a/src/runner/settings_window.h +++ b/src/runner/settings_window.h @@ -1,3 +1,5 @@ #pragma once void open_settings_window(); -void close_settings_window(); \ No newline at end of file +void close_settings_window(); + +void open_oobe_window(); \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeModuleRunEvent.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeModuleRunEvent.cs new file mode 100644 index 0000000000..4b0721d410 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeModuleRunEvent.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class OobeModuleRunEvent : EventBase, IEvent + { + public string ModuleName { get; set; } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSectionEvent.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSectionEvent.cs new file mode 100644 index 0000000000..bb3265773d --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSectionEvent.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class OobeSectionEvent : EventBase, IEvent + { + public string Section { get; set; } + + public double TimeOpenedMs { get; set; } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSettingsEvent.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSettingsEvent.cs new file mode 100644 index 0000000000..f0e7293ed3 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeSettingsEvent.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class OobeSettingsEvent : EventBase, IEvent + { + public string ModuleName { get; set; } + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeStartedEvent.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeStartedEvent.cs new file mode 100644 index 0000000000..771cdfc402 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI.Library/Telemetry/Events/OobeStartedEvent.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.Tracing; +using Microsoft.PowerToys.Telemetry; +using Microsoft.PowerToys.Telemetry.Events; + +namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events +{ + [EventData] + public class OobeStartedEvent : EventBase, IEvent + { + public bool OobeStarted { get; set; } = true; + + public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage; + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsColorPicker.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsColorPicker.png new file mode 100644 index 0000000000..b120ef4683 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsColorPicker.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFancyZones.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFancyZones.png new file mode 100644 index 0000000000..afa3f1739b Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFancyZones.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFileExplorerPreview.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFileExplorerPreview.png new file mode 100644 index 0000000000..337457d6ed Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsFileExplorerPreview.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsImageResizer.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsImageResizer.png new file mode 100644 index 0000000000..a4f82a5e00 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsImageResizer.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsKeyboardManager.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsKeyboardManager.png new file mode 100644 index 0000000000..2d6db29ff1 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsKeyboardManager.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerRename.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerRename.png new file mode 100644 index 0000000000..6400b89e2d Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerRename.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToys.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToys.png new file mode 100644 index 0000000000..a7b0109afd Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToys.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToysRun.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToysRun.png new file mode 100644 index 0000000000..24bfb98494 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsPowerToysRun.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsShortcutGuide.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsShortcutGuide.png new file mode 100644 index 0000000000..2613c44846 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsShortcutGuide.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsVideoConferenceMute.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsVideoConferenceMute.png new file mode 100644 index 0000000000..2b9e8dfdac Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/FluentIcons/FluentIconsVideoConferenceMute.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ColorPicker.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ColorPicker.gif new file mode 100644 index 0000000000..a926917aaf Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ColorPicker.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FancyZones.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FancyZones.gif new file mode 100644 index 0000000000..6395240d4f Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FancyZones.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FileExplorer.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FileExplorer.png new file mode 100644 index 0000000000..2fe02e0b8c Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/FileExplorer.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ImageResizer.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ImageResizer.gif new file mode 100644 index 0000000000..b82fa8f814 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/ImageResizer.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/KBM.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/KBM.gif new file mode 100644 index 0000000000..a59840c960 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/KBM.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/OOBEShortcutGuide.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/OOBEShortcutGuide.png new file mode 100644 index 0000000000..377b09325f Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/OOBEShortcutGuide.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/PowerRename.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/PowerRename.gif new file mode 100644 index 0000000000..31f9e112f7 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/PowerRename.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/Run.gif b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/Run.gif new file mode 100644 index 0000000000..2eb870b1d3 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/Run.gif differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/VideoConferenceMute.png b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/VideoConferenceMute.png new file mode 100644 index 0000000000..b7b47a01c2 Binary files /dev/null and b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Assets/Modules/OOBE/VideoConferenceMute.png differ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Helpers/NativeMethods.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Helpers/NativeMethods.cs index 4f91dd4b4b..176c10a735 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Helpers/NativeMethods.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Helpers/NativeMethods.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; namespace Microsoft.PowerToys.Settings.UI.Helpers { - internal static class NativeMethods + public static class NativeMethods { [DllImport("user32.dll")] internal static extern uint SendInput(uint nInputs, NativeKeyboardHelper.INPUT[] pInputs, int cbSize); @@ -14,7 +14,12 @@ namespace Microsoft.PowerToys.Settings.UI.Helpers [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] internal static extern short GetAsyncKeyState(int vKey); +#pragma warning disable CA1401 // P/Invokes should not be visible [DllImport("user32.dll")] public static extern bool ShowWindow(System.IntPtr hWnd, int nCmdShow); + + [DllImport("user32.dll")] + public static extern bool AllowSetForegroundWindow(int dwProcessId); +#pragma warning restore CA1401 // P/Invokes should not be visible } } diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj index 67370b3e30..fb1af0417a 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Microsoft.PowerToys.Settings.UI.csproj @@ -111,6 +111,42 @@ + + + + + OobeColorPicker.xaml + + + OobeFancyZones.xaml + + + OobeFileExplorer.xaml + + + OobeImageResizer.xaml + + + OobeKBM.xaml + + + OobeOverview.xaml + + + OobePowerRename.xaml + + + OobeRun.xaml + + + OobeShellPage.xaml + + + OobeShortcutGuide.xaml + + + OobeVideoConference.xaml + @@ -153,11 +189,30 @@ + + + + + + + + + + + + + + + + + + + @@ -216,6 +271,50 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -300,6 +399,7 @@ Microsoft.PowerToys.Settings.UI.Library + 14.0 diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Enums/PowerToysModulesEnum.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Enums/PowerToysModulesEnum.cs new file mode 100644 index 0000000000..10806e19fc --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Enums/PowerToysModulesEnum.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Enums +{ + public enum PowerToysModulesEnum + { + Overview = 0, + ColorPicker, + FancyZones, + ImageResizer, + KBM, + Run, + PowerRename, + FileExplorer, + ShortcutGuide, + VideoConference, + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobePowerToysModule.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobePowerToysModule.cs new file mode 100644 index 0000000000..76cd71fa23 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobePowerToysModule.cs @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events; +using Microsoft.PowerToys.Telemetry; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.ViewModel +{ + public class OobePowerToysModule + { + private System.Diagnostics.Stopwatch timeOpened = new System.Diagnostics.Stopwatch(); + + public string ModuleName { get; set; } + + public string Tag { get; set; } + + public bool IsNew { get; set; } + + public string Image { get; set; } + + public string Icon { get; set; } + + public string FluentIcon { get; set; } + + public string PreviewImageSource { get; set; } + + public string Description { get; set; } + + public string Link { get; set; } + + public string DescriptionLink { get; set; } + + public OobePowerToysModule() + { + } + + public OobePowerToysModule(OobePowerToysModule other) + { + if (other == null) + { + return; + } + + ModuleName = other.ModuleName; + Tag = other.Tag; + IsNew = other.IsNew; + Image = other.Image; + Icon = other.Icon; + FluentIcon = other.FluentIcon; + PreviewImageSource = other.PreviewImageSource; + Description = other.Description; + Link = other.Link; + DescriptionLink = other.DescriptionLink; + timeOpened = other.timeOpened; + } + + public void LogOpeningSettingsEvent() + { + PowerToysTelemetry.Log.WriteEvent(new OobeSettingsEvent() { ModuleName = this.ModuleName }); + } + + public void LogRunningModuleEvent() + { + PowerToysTelemetry.Log.WriteEvent(new OobeModuleRunEvent() { ModuleName = this.ModuleName }); + } + + public void LogOpeningModuleEvent() + { + timeOpened.Start(); + } + + public void LogClosingModuleEvent() + { + timeOpened.Stop(); + PowerToysTelemetry.Log.WriteEvent(new OobeSectionEvent() { Section = this.ModuleName, TimeOpenedMs = timeOpened.ElapsedMilliseconds }); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobeShellViewModel.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobeShellViewModel.cs new file mode 100644 index 0000000000..6159b58690 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/ViewModel/OobeShellViewModel.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.PowerToys.Settings.UI.OOBE.ViewModel +{ + public class OobeShellViewModel + { + public OobeShellViewModel() + { + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml new file mode 100644 index 0000000000..748d36dae2 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml.cs new file mode 100644 index 0000000000..6c1707ed8d --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeColorPicker.xaml.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeColorPicker : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeColorPicker() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.ColorPicker]); + DataContext = ViewModel; + } + + private void Start_ColorPicker_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.ColorPickerSharedEventCallback != null) + { + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, OobeShellPage.ColorPickerSharedEventCallback())) + { + eventHandle.Set(); + } + } + + ViewModel.LogRunningModuleEvent(); + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(ColorPickerPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml new file mode 100644 index 0000000000..10052406be --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml.cs new file mode 100644 index 0000000000..69101d40a3 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFancyZones.xaml.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeFancyZones : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeFancyZones() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.FancyZones]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(FancyZonesPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml new file mode 100644 index 0000000000..4d586eba86 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml.cs new file mode 100644 index 0000000000..0c1111f473 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeFileExplorer.xaml.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeFileExplorer : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeFileExplorer() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.FileExplorer]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(PowerPreviewPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml new file mode 100644 index 0000000000..942f7f8d3b --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml.cs new file mode 100644 index 0000000000..1cf0730d58 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeImageResizer.xaml.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeImageResizer : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeImageResizer() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.ImageResizer]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(ImageResizerPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml new file mode 100644 index 0000000000..35ba58e895 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml.cs new file mode 100644 index 0000000000..f917344ccb --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeKBM.xaml.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeKBM : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeKBM() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.KBM]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(KeyboardManagerPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml new file mode 100644 index 0000000000..d684b12aa7 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml.cs new file mode 100644 index 0000000000..e2dbb85461 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeOverview.xaml.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + public sealed partial class OobeOverview : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeOverview() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.Overview]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(GeneralPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml new file mode 100644 index 0000000000..204422e227 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml.cs new file mode 100644 index 0000000000..035b6aec2a --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobePowerRename.xaml.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobePowerRename : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobePowerRename() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.PowerRename]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(PowerRenamePage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml new file mode 100644 index 0000000000..3c6d9634d1 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml.cs new file mode 100644 index 0000000000..d67901fa98 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeRun.xaml.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeRun : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeRun() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.Run]); + DataContext = ViewModel; + } + + private void Start_Run_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.RunSharedEventCallback != null) + { + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, OobeShellPage.RunSharedEventCallback())) + { + eventHandle.Set(); + } + } + + ViewModel.LogRunningModuleEvent(); + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(PowerLauncherPage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml new file mode 100644 index 0000000000..9f0ee9296a --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml.cs new file mode 100644 index 0000000000..8a63b9701c --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShellPage.xaml.cs @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Windows.ApplicationModel.Resources; +using Windows.UI.Xaml.Controls; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + public sealed partial class OobeShellPage : UserControl + { + public static Func RunSharedEventCallback { get; set; } + + public static void SetRunSharedEventCallback(Func implementation) + { + RunSharedEventCallback = implementation; + } + + public static Func ColorPickerSharedEventCallback { get; set; } + + public static void SetColorPickerSharedEventCallback(Func implementation) + { + ColorPickerSharedEventCallback = implementation; + } + + public static Func ShortcutGuideSharedEventCallback { get; set; } + + public static void SetShortcutGuideSharedEventCallback(Func implementation) + { + ShortcutGuideSharedEventCallback = implementation; + } + + public static Action OpenMainWindowCallback { get; set; } + + public static void SetOpenMainWindowCallback(Action implementation) + { + OpenMainWindowCallback = implementation; + } + + /// + /// Gets view model. + /// + public OobeShellViewModel ViewModel { get; } = new OobeShellViewModel(); + + /// + /// Gets or sets a shell handler to be used to update contents of the shell dynamically from page within the frame. + /// + public static OobeShellPage OobeShellHandler { get; set; } + + public ObservableCollection Modules { get; } + + public OobeShellPage() + { + InitializeComponent(); + + DataContext = ViewModel; + OobeShellHandler = this; + + Modules = new ObservableCollection(); + ResourceLoader loader = ResourceLoader.GetForViewIndependentUse(); + + Modules.Insert((int)PowerToysModulesEnum.Overview, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_Welcome"), + Tag = "Overview", + IsNew = false, + Icon = "\uEF3C", + Image = "ms-appx:///Assets/Modules/ColorPicker.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerToys.png", + PreviewImageSource = "https://github.com/microsoft/PowerToys/raw/master/doc/images/overview/PT%20hero%20image.png", + DescriptionLink = "https://aka.ms/PowerToysOverview", + Link = "https://github.com/microsoft/PowerToys/releases/", + }); + Modules.Insert((int)PowerToysModulesEnum.ColorPicker, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_ColorPicker"), + Tag = "ColorPicker", + IsNew = false, + Icon = "\uEF3C", + Image = "ms-appx:///Assets/Modules/ColorPicker.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsColorPicker.png", + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/ColorPicker.gif", + Description = loader.GetString("Oobe_ColorPicker_Description"), + Link = "https://aka.ms/PowerToysOverview_ColorPicker", + }); + Modules.Insert((int)PowerToysModulesEnum.FancyZones, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_FancyZones"), + Tag = "FancyZones", + IsNew = false, + Icon = "\uE737", + Image = "ms-appx:///Assets/Modules/FancyZones.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsFancyZones.png", + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/FancyZones.gif", + Description = loader.GetString("Oobe_FancyZones_Description"), + Link = "https://aka.ms/PowerToysOverview_FancyZones", + }); + Modules.Insert((int)PowerToysModulesEnum.ImageResizer, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_ImageResizer"), + Tag = "ImageResizer", + IsNew = false, + Icon = "\uEB9F", + Image = "ms-appx:///Assets/Modules/ImageResizer.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsImageResizer.png", + Description = loader.GetString("Oobe_ImageResizer_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/ImageResizer.gif", + Link = "https://aka.ms/PowerToysOverview_ImageResizer", + }); + Modules.Insert((int)PowerToysModulesEnum.KBM, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_KBM"), + Tag = "KBM", + IsNew = false, + Icon = "\uE765", + Image = "ms-appx:///Assets/Modules/KeyboardManager.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsKeyboardManager.png", + Description = loader.GetString("Oobe_KBM_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/KBM.gif", + Link = "https://aka.ms/PowerToysOverview_KeyboardManager", + }); + Modules.Insert((int)PowerToysModulesEnum.Run, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_Run"), + Tag = "Run", + IsNew = false, + Icon = "\uE773", + Image = "ms-appx:///Assets/Modules/PowerLauncher.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerToysRun.png", + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/Run.gif", + Description = loader.GetString("Oobe_PowerRun_Description"), + Link = "https://aka.ms/PowerToysOverview_PowerToysRun", + }); + Modules.Insert((int)PowerToysModulesEnum.PowerRename, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_PowerRename"), + Tag = "PowerRename", + IsNew = false, + Icon = "\uE8AC", + Image = "ms-appx:///Assets/Modules/PowerRename.png", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsPowerRename.png", + Description = loader.GetString("Oobe_PowerRename_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/PowerRename.gif", + Link = "https://aka.ms/PowerToysOverview_PowerRename", + }); + Modules.Insert((int)PowerToysModulesEnum.FileExplorer, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_FileExplorer"), + Tag = "FileExplorer", + IsNew = false, + Icon = "\uEC50", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsFileExplorerPreview.png", + Image = "ms-appx:///Assets/Modules/PowerPreview.png", + Description = loader.GetString("Oobe_FileExplorer_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/FileExplorer.png", + Link = "https://aka.ms/PowerToysOverview_FileExplorerAddOns", + }); + Modules.Insert((int)PowerToysModulesEnum.ShortcutGuide, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_ShortcutGuide"), + Tag = "ShortcutGuide", + IsNew = false, + Icon = "\uEDA7", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsShortcutGuide.png", + Image = "ms-appx:///Assets/Modules/ShortcutGuide.png", + Description = loader.GetString("Oobe_ShortcutGuide_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/OOBEShortcutGuide.png", + Link = "https://aka.ms/PowerToysOverview_ShortcutGuide", + }); + /* Modules.Insert((int)PowerToysModulesEnum.VideoConference, new OobePowerToysModule() + { + ModuleName = loader.GetString("Oobe_VideoConference"), + Tag = "VideoConference", + IsNew = true, + Icon = "\uEC50", + FluentIcon = "ms-appx:///Assets/FluentIcons/FluentIconsVideoConferenceMute.png", + Image = "ms-appx:///Assets/Modules/VideoConference.png", + Description = loader.GetString("Oobe_VideoConference_Description"), + PreviewImageSource = "ms-appx:///Assets/Modules/OOBE/VideoConferenceMute.png", + Link = "https://aka.ms/PowerToysOverview_VideoConference", + }); */ + } + + public void OnClosing() + { + if (NavigationView.SelectedItem != null) + { + ((OobePowerToysModule)NavigationView.SelectedItem).LogClosingModuleEvent(); + } + } + + private void UserControl_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (Modules.Count > 0) + { + NavigationView.SelectedItem = Modules[(int)PowerToysModulesEnum.Overview]; + } + } + + [SuppressMessage("Usage", "CA1801:Review unused parameters", Justification = "Params are required for event handler signature requirements.")] + private void NavigationView_SelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) + { + OobePowerToysModule selectedItem = args.SelectedItem as OobePowerToysModule; + + switch (selectedItem.Tag) + { + case "Overview": NavigationFrame.Navigate(typeof(OobeOverview)); break; + case "ColorPicker": NavigationFrame.Navigate(typeof(OobeColorPicker)); break; + case "FancyZones": NavigationFrame.Navigate(typeof(OobeFancyZones)); break; + case "Run": NavigationFrame.Navigate(typeof(OobeRun)); break; + case "ImageResizer": NavigationFrame.Navigate(typeof(OobeImageResizer)); break; + case "KBM": NavigationFrame.Navigate(typeof(OobeKBM)); break; + case "PowerRename": NavigationFrame.Navigate(typeof(OobePowerRename)); break; + case "FileExplorer": NavigationFrame.Navigate(typeof(OobeFileExplorer)); break; + case "ShortcutGuide": NavigationFrame.Navigate(typeof(OobeShortcutGuide)); break; + case "VideoConference": NavigationFrame.Navigate(typeof(OobeVideoConference)); break; + } + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml new file mode 100644 index 0000000000..674c0bcfad --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml.cs new file mode 100644 index 0000000000..956c33384b --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeShortcutGuide.xaml.cs @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Threading; +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Microsoft.PowerToys.Settings.UI.Views; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeShortcutGuide : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeShortcutGuide() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.ShortcutGuide]); + DataContext = ViewModel; + } + + private void Start_ShortcutGuide_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.ShortcutGuideSharedEventCallback != null) + { + using (var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, OobeShellPage.ShortcutGuideSharedEventCallback())) + { + eventHandle.Set(); + } + } + + ViewModel.LogRunningModuleEvent(); + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + if (OobeShellPage.OpenMainWindowCallback != null) + { + OobeShellPage.OpenMainWindowCallback(typeof(ShortcutGuidePage)); + } + + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml new file mode 100644 index 0000000000..d80e1710d4 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml.cs new file mode 100644 index 0000000000..3723113964 --- /dev/null +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/OOBE/Views/OobeVideoConference.xaml.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.PowerToys.Settings.UI.OOBE.Enums; +using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; + +namespace Microsoft.PowerToys.Settings.UI.OOBE.Views +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + public sealed partial class OobeVideoConference : Page + { + public OobePowerToysModule ViewModel { get; set; } + + public OobeVideoConference() + { + this.InitializeComponent(); + ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModulesEnum.VideoConference]); + DataContext = ViewModel; + } + + private void SettingsLaunchButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) + { + ViewModel.LogOpeningSettingsEvent(); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + ViewModel.LogOpeningModuleEvent(); + } + + protected override void OnNavigatedFrom(NavigationEventArgs e) + { + ViewModel.LogClosingModuleEvent(); + } + } +} diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw index ec39763343..0bc54216b0 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Strings/en-us/Resources.resw @@ -977,4 +977,172 @@ You can include or remove each plugin from the global results, change the direct activation phrase and configure additional options. + + Let's get started! + + + Welcome to PowerToys! These overviews will help you quickly learn the basics of all our utilities. + + + Getting started + + + Launch + + + Learn more about + + + Color Picker is a system-wide color selection tool for Windows 10 that enables you to pick colors from any currently running application and automatically copies it in a configurable format to your clipboard. + + + FancyZones is a window manager that makes it easy to create complex window layouts and quickly position windows into those layouts. + + + PowerToys introduces add-ons to the Window’s File Explorer that will currently enable Markdown files (.md) and SVG icons (.svg) to be viewed in the preview pane. + + + Image Resizer is a Windows shell extension for simple bulk image-resizing. + + + Keyboard Manager allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts. + + + PowerRename enables you to perform simple bulk renaming, searching and replacing file names. + + + PowerToys Run is a quick launcher for power users that contains some additional features without sacrificing performance. + + + Shortcut Guide presents the user with a listing of available shortcuts for the current state of the desktop. + + + Video Conference Mute allows users to quickly mute the microphone and turn off the camera while on a conference call with a single keystroke, regardless of what application has focus on your computer. + + + For returning users, check out what is new on this latest version of + + + Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows 10 experience for greater productivity. +Take a moment to preview the various utilities listed or view our comprehensive documentation on + + + Microsoft Docs. + + + PowerToys in our release notes. + + + Win + Shift + C to open Color Picker. + + + To select a color with more precision, scroll the mouse wheel to zoom in. + + + Shift + drag while dragging the window to snap a window to a zone, and release the window in the desired zone. +Win + ` to open the FancyZones editor. + + + Snap a window to multiple zones by holding the Ctrl key (while also holding Shift) when dragging a window. + + + Open Windows File Explorer, select the View tab in the File Explorer ribbon, then select Preview Pane. +From there, simply click on a Markdown file or SVG icon in the File Explorer and observe the content on the preview pane! + + + How to create mappings + + + How to enable + + + How to launch + + + How to use + + + In File Explorer, right-clicking one or more image files and clicking on Resize pictures from the context menu. + + + Want a custom size? You can add them in the PowerToys Settings! + + + Launch PowerToys settings, navigate to the Keyboard Manager menu, and select either Remap a key or Remap a shortcut. + + + Want to only have a shortcut work for a single application? Use the Target App field when creating the shortcut remapping. + + + In File Explorer, right-clicking one or more selected files and clicking on PowerRename from the context menu. + + + PowerRename supports searching for files using regular expressions to enable more advanced renaming functionalities. + + + Alt + Space to open PowerToys and just start typing. + + + PowerToys runs supports various action keys to funnel search queries for a specific subset of results. Typing < searches for running processes only, ? will search only for file, or . for installed applications! See PowerToys documentation for the complete set of 'Action Keys' available. + + + Win + ? to open Shortcut Guide, press it again to close or press Esc. You can also launch it by holding the Win key for one second! + + + Tips & tricks + + + Win + N to toggle both your microphone and video +Win + Shift + A to toggle your microphone +Win + Shift + O to toggle your video + + + Color Picker + Do not localize this string + + + FancyZones + Do not localize this string + + + File Explorer add-ons + Do not localize this string + + + ImageResizer + Do not localize this string + + + Keyboard Manager + Do not localize this string + + + Overview + + + PowerRename + Do not localize this string + + + PowerToys Run + Do not localize this string + + + Shortcut Guide + Do not localize this string + + + Video Conference + Do not localize this string + + + Welcome to PowerToys + Do not localize 'PowerToys' + + + Settings + + + PowerToys Tour + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Styles/TextBlock.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Styles/TextBlock.xaml index f6f0f9fd7f..e8ee207831 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Styles/TextBlock.xaml +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Styles/TextBlock.xaml @@ -5,7 +5,7 @@ + + \ No newline at end of file diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml index 4c4ccae2ce..50d9348408 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml @@ -187,6 +187,10 @@ RelativePanel.Below="AboutImage" Orientation="Vertical" > + + + + diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs index 63bf95342a..d956327bf4 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/GeneralPage.xaml.cs @@ -122,5 +122,10 @@ namespace Microsoft.PowerToys.Settings.UI.Views { Helpers.StartProcessHelper.Start(Helpers.StartProcessHelper.ColorsSettings); } + + private void OobeButton_Click(object sender, RoutedEventArgs e) + { + ShellPage.OpenOobeWindowCallback(); + } } } diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml index 59e274a377..96a250ed32 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml @@ -105,6 +105,7 @@ diff --git a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml.cs b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml.cs index 9a82503ade..7ec85b843c 100644 --- a/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml.cs +++ b/src/settings-ui/Microsoft.PowerToys.Settings.UI/Views/ShellPage.xaml.cs @@ -2,8 +2,10 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using Microsoft.PowerToys.Settings.UI.Services; using Microsoft.PowerToys.Settings.UI.ViewModels; using Windows.Data.Json; using Windows.UI.Xaml.Controls; @@ -21,6 +23,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views /// message. public delegate void IPCMessageCallback(string msg); + /// + /// Declaration for the opening oobe window callback function. + /// + public delegate void OobeOpeningCallback(); + /// /// Gets or sets a shell handler to be used to update contents of the shell dynamically from page within the frame. /// @@ -41,6 +48,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views /// public static IPCMessageCallback CheckForUpdatesMsgCallback { get; set; } + /// + /// Gets or sets callback function for opening oobe window + /// + public static OobeOpeningCallback OpenOobeWindowCallback { get; set; } + /// /// Gets view model. /// @@ -114,6 +126,15 @@ namespace Microsoft.PowerToys.Settings.UI.Views CheckForUpdatesMsgCallback = implementation; } + /// + /// Set oobe opening callback function + /// + /// delegate function implementation. + public static void SetOpenOobeCallback(OobeOpeningCallback implementation) + { + OpenOobeWindowCallback = implementation; + } + public static void SetElevationStatus(bool isElevated) { IsElevated = isElevated; @@ -124,6 +145,11 @@ namespace Microsoft.PowerToys.Settings.UI.Views IsUserAnAdmin = isAdmin; } + public static void Navigate(Type type) + { + NavigationService.Navigate(type); + } + public void Refresh() { shellFrame.Navigate(typeof(GeneralPage)); diff --git a/src/settings-ui/PowerToys.Settings/App.xaml b/src/settings-ui/PowerToys.Settings/App.xaml index 7eff0b2507..deedff2ed9 100644 --- a/src/settings-ui/PowerToys.Settings/App.xaml +++ b/src/settings-ui/PowerToys.Settings/App.xaml @@ -1,7 +1,7 @@  + Startup="Application_Startup"> diff --git a/src/settings-ui/PowerToys.Settings/App.xaml.cs b/src/settings-ui/PowerToys.Settings/App.xaml.cs index 7eefca8e6c..56b244638f 100644 --- a/src/settings-ui/PowerToys.Settings/App.xaml.cs +++ b/src/settings-ui/PowerToys.Settings/App.xaml.cs @@ -2,7 +2,10 @@ // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Windows; +using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events; +using Microsoft.PowerToys.Telemetry; namespace PowerToys.Settings { @@ -11,5 +14,60 @@ namespace PowerToys.Settings /// public partial class App : Application { + private MainWindow settingsWindow; + + public bool ShowOobe { get; set; } + + public void OpenSettingsWindow(Type type) + { + if (settingsWindow == null) + { + settingsWindow = new MainWindow(); + } + + settingsWindow.Show(); + settingsWindow.NavigateToSection(type); + } + + private void InitHiddenSettingsWindow() + { + settingsWindow = new MainWindow(); + + // To avoid visual flickering, show the window with a size of 0,0 + // and don't show it in the taskbar + var originalHight = settingsWindow.Height; + var originalWidth = settingsWindow.Width; + settingsWindow.Height = 0; + settingsWindow.Width = 0; + settingsWindow.ShowInTaskbar = false; + + settingsWindow.Show(); + settingsWindow.Hide(); + + settingsWindow.Height = originalHight; + settingsWindow.Width = originalWidth; + settingsWindow.ShowInTaskbar = true; + } + + private void Application_Startup(object sender, StartupEventArgs e) + { + if (!ShowOobe) + { + settingsWindow = new MainWindow(); + settingsWindow.Show(); + } + else + { + PowerToysTelemetry.Log.WriteEvent(new OobeStartedEvent()); + + // Create the Settings window so that it's fully initialized and + // it will be ready to receive the notification if the user opens + // the Settings from the tray icon. + InitHiddenSettingsWindow(); + + OobeWindow oobeWindow = new OobeWindow(); + oobeWindow.Show(); + } + } } } diff --git a/src/settings-ui/PowerToys.Settings/MainWindow.xaml b/src/settings-ui/PowerToys.Settings/MainWindow.xaml index 0dffeae7be..0899c7ece7 100644 --- a/src/settings-ui/PowerToys.Settings/MainWindow.xaml +++ b/src/settings-ui/PowerToys.Settings/MainWindow.xaml @@ -7,7 +7,7 @@ xmlns:Controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls" xmlns:xaml="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost" mc:Ignorable="d" - Title="PowerToys Settings" MinWidth="480" Height="800" Width="1100" Closing="MainWindow_Closing"> + Title="PowerToys Settings" MinWidth="480" Height="800" Width="1100" Closing="MainWindow_Closing" Loaded="MainWindow_Loaded" Activated="MainWindow_Activated"> diff --git a/src/settings-ui/PowerToys.Settings/MainWindow.xaml.cs b/src/settings-ui/PowerToys.Settings/MainWindow.xaml.cs index 438c756a34..714035fb6c 100644 --- a/src/settings-ui/PowerToys.Settings/MainWindow.xaml.cs +++ b/src/settings-ui/PowerToys.Settings/MainWindow.xaml.cs @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation +// Copyright (c) Microsoft Corporation // The Microsoft Corporation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -16,6 +16,8 @@ namespace PowerToys.Settings // Interaction logic for MainWindow.xaml. public partial class MainWindow : Window { + private static Window inst; + private bool isOpen = true; public MainWindow() @@ -29,6 +31,23 @@ namespace PowerToys.Settings PowerToysTelemetry.Log.WriteEvent(new SettingsBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds }); } + public static void CloseHiddenWindow() + { + if (inst != null && inst.Visibility == Visibility.Hidden) + { + inst.Close(); + } + } + + public void NavigateToSection(Type type) + { + if (inst != null) + { + Activate(); + ShellPage.Navigate(type); + } + } + private void WindowsXamlHost_ChildChanged(object sender, EventArgs e) { // If sender is null, it could lead to a NullReferenceException. This might occur on restarting as admin (check https://github.com/microsoft/PowerToys/issues/7393 for details) @@ -63,6 +82,13 @@ namespace PowerToys.Settings Program.GetTwoWayIPCManager().Send(msg); }); + // open oobe + ShellPage.SetOpenOobeCallback(() => + { + var oobe = new OobeWindow(); + oobe.Show(); + }); + // receive IPC Message Program.IPCMessageReceivedCallback = (string msg) => { @@ -97,7 +123,15 @@ namespace PowerToys.Settings private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - isOpen = false; + if (OobeWindow.IsOpened) + { + e.Cancel = true; + ((Window)sender).Hide(); + } + else + { + isOpen = false; + } // XAML Islands: If the window is closed while minimized, exit the process. Required to avoid process not terminating issue - https://github.com/microsoft/PowerToys/issues/4430 if (WindowState == WindowState.Minimized) @@ -106,5 +140,18 @@ namespace PowerToys.Settings System.Threading.Tasks.Task.Run(() => { Environment.Exit(0); }); } } + + private void MainWindow_Loaded(object sender, RoutedEventArgs e) + { + inst = (Window)sender; + } + + private void MainWindow_Activated(object sender, EventArgs e) + { + if (((Window)sender).Visibility == Visibility.Hidden) + { + ((Window)sender).Visibility = Visibility.Visible; + } + } } } diff --git a/src/settings-ui/PowerToys.Settings/OobeWindow.xaml b/src/settings-ui/PowerToys.Settings/OobeWindow.xaml new file mode 100644 index 0000000000..b4d87d43d2 --- /dev/null +++ b/src/settings-ui/PowerToys.Settings/OobeWindow.xaml @@ -0,0 +1,19 @@ + + + + + diff --git a/src/settings-ui/PowerToys.Settings/OobeWindow.xaml.cs b/src/settings-ui/PowerToys.Settings/OobeWindow.xaml.cs new file mode 100644 index 0000000000..dec8fe81f7 --- /dev/null +++ b/src/settings-ui/PowerToys.Settings/OobeWindow.xaml.cs @@ -0,0 +1,88 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Windows; +using interop; +using Microsoft.PowerToys.Settings.UI.Helpers; +using Microsoft.PowerToys.Settings.UI.OOBE.Views; +using Microsoft.Toolkit.Wpf.UI.XamlHost; + +namespace PowerToys.Settings +{ + /// + /// Interaction logic for OobeWindow.xaml + /// + public partial class OobeWindow : Window + { + private static Window inst; + private OobeShellPage shellPage; + + public static bool IsOpened + { + get + { + return inst != null; + } + } + + public OobeWindow() + { + InitializeComponent(); + } + + private void Window_Closed(object sender, EventArgs e) + { + if (shellPage != null) + { + shellPage.OnClosing(); + } + + inst = null; + MainWindow.CloseHiddenWindow(); + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + if (inst != null) + { + inst.Close(); + } + + inst = this; + } + + private void WindowsXamlHost_ChildChanged(object sender, EventArgs e) + { + if (sender == null) + { + return; + } + + WindowsXamlHost windowsXamlHost = sender as WindowsXamlHost; + shellPage = windowsXamlHost.GetUwpInternalObject() as OobeShellPage; + + OobeShellPage.SetRunSharedEventCallback(() => + { + return Constants.PowerLauncherSharedEvent(); + }); + + OobeShellPage.SetColorPickerSharedEventCallback(() => + { + return Constants.ShowColorPickerSharedEvent(); + }); + + OobeShellPage.SetShortcutGuideSharedEventCallback(() => + { + NativeMethods.AllowSetForegroundWindow(PowerToys.Settings.Program.PowerToysPID); + return Constants.ShowShortcutGuideSharedEvent(); + }); + + OobeShellPage.SetOpenMainWindowCallback((Type type) => + { + ((App)Application.Current).OpenSettingsWindow(type); + }); + } + } +} diff --git a/src/settings-ui/PowerToys.Settings/Program.cs b/src/settings-ui/PowerToys.Settings/Program.cs index ec365eca28..5c5424c9f2 100644 --- a/src/settings-ui/PowerToys.Settings/Program.cs +++ b/src/settings-ui/PowerToys.Settings/Program.cs @@ -19,10 +19,12 @@ namespace PowerToys.Settings Theme, // used in the old settings ElevatedStatus, IsUserAdmin, + ShowOobeWindow, } // Quantity of arguments - private const int ArgumentsQty = 6; + private const int RequiredArgumentsQty = 6; + private const int RequiredAndOptionalArgumentsQty = 7; // Create an instance of the IPC wrapper. private static TwoWayPipeMessageIPCManaged ipcmanager; @@ -43,7 +45,7 @@ namespace PowerToys.Settings App app = new App(); app.InitializeComponent(); - if (args != null && args.Length >= ArgumentsQty) + if (args != null && args.Length >= RequiredArgumentsQty) { _ = int.TryParse(args[(int)Arguments.PTPid], out int powerToysPID); PowerToysPID = powerToysPID; @@ -51,6 +53,12 @@ namespace PowerToys.Settings IsElevated = args[(int)Arguments.ElevatedStatus] == "true"; IsUserAnAdmin = args[(int)Arguments.IsUserAdmin] == "true"; + if (args.Length == RequiredAndOptionalArgumentsQty) + { + // open oobe window + app.ShowOobe = args[(int)Arguments.ShowOobeWindow] == "true"; + } + RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () => { Environment.Exit(0);