mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-16 09:16:49 +01:00
Compare commits
16 Commits
shawn/fixI
...
leilzh/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef538ff62e | ||
|
|
ee64ba5abc | ||
|
|
03aec1a9a7 | ||
|
|
335dcbaae8 | ||
|
|
6515985823 | ||
|
|
36a64cae90 | ||
|
|
30f832ac65 | ||
|
|
e0c0e7bb76 | ||
|
|
dfede67993 | ||
|
|
1438a628ad | ||
|
|
1b6b446915 | ||
|
|
78b0139bc3 | ||
|
|
709c4bbf6b | ||
|
|
bb3435322f | ||
|
|
d43e1d8cb2 | ||
|
|
1a145fd136 |
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@@ -1810,7 +1810,6 @@ TILEDWINDOW
|
||||
TILLSON
|
||||
timedate
|
||||
timediff
|
||||
timeunion
|
||||
timeutil
|
||||
TITLEBARINFO
|
||||
Titlecase
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
"WinUI3Apps\\PowerToys.FileLocksmithUI.dll",
|
||||
"WinUI3Apps\\PowerToys.FileLocksmithContextMenu.dll",
|
||||
"FileLocksmithContextMenuPackage.msix",
|
||||
"FileLocksmithCLI.exe",
|
||||
|
||||
"WinUI3Apps\\Peek.Common.dll",
|
||||
"WinUI3Apps\\Peek.FilePreviewer.dll",
|
||||
|
||||
@@ -68,14 +68,13 @@ jobs:
|
||||
|
||||
- template: .\steps-restore-nuget.yml
|
||||
|
||||
- task: NuGetCommand@2
|
||||
- task: MSBuild@1
|
||||
displayName: Restore solution-level NuGet packages
|
||||
inputs:
|
||||
command: restore
|
||||
feedsToUse: config
|
||||
configPath: nuget.config
|
||||
restoreSolution: PowerToys.slnx
|
||||
restoreDirectory: '$(Build.SourcesDirectory)\packages'
|
||||
solution: PowerToys.slnx
|
||||
msbuildArguments: '/t:restore /p:RestorePackagesConfig=true'
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
|
||||
# Build all UI test projects if no specific modules are specified
|
||||
- ${{ if eq(length(parameters.uiTestModules), 0) }}:
|
||||
|
||||
@@ -694,6 +694,30 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Light Switch
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.LightSwitch_EnableLightSwitch</td>
|
||||
<td>Triggered when Light Switch is enabled or disabled.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.LightSwitch_ShortcutInvoked</td>
|
||||
<td>Occurs when the shortcut for Light Switch is invoked.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.LightSwitch_ScheduleModeToggled</td>
|
||||
<td>Occurs when a new schedule mode is selected for Light Switch.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.LightSwitch_ThemeTargetChanged</td>
|
||||
<td>Occurs when the options for targeting the system or apps is updated.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Mouse Highlighter
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
|
||||
@@ -420,6 +420,7 @@
|
||||
</Project>
|
||||
</Folder>
|
||||
<Folder Name="/modules/FileLocksmith/">
|
||||
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/FileLocksmithCLI.vcxproj" Id="49D456D3-F485-45AF-8875-45B44F193DDC" />
|
||||
<Project Path="src/modules/FileLocksmith/FileLocksmithContextMenu/FileLocksmithContextMenu.vcxproj" Id="799a50d8-de89-4ed1-8ff8-ad5a9ed8c0ca" />
|
||||
<Project Path="src/modules/FileLocksmith/FileLocksmithExt/FileLocksmithExt.vcxproj" Id="57175ec7-92a5-4c1e-8244-e3fbca2a81de" />
|
||||
<Project Path="src/modules/FileLocksmith/FileLocksmithLib/FileLocksmithLib.vcxproj" Id="9d52fd25-ef90-4f9a-a015-91efc5daf54f" />
|
||||
@@ -429,6 +430,9 @@
|
||||
<Platform Solution="*|x64" Project="x64" />
|
||||
</Project>
|
||||
</Folder>
|
||||
<Folder Name="/modules/FileLocksmith/Tests/">
|
||||
<Project Path="src/modules/FileLocksmith/FileLocksmithCLI/tests/FileLocksmithCLIUnitTests.vcxproj" Id="A1B2C3D4-E5F6-7890-1234-567890ABCDEF" />
|
||||
</Folder>
|
||||
<Folder Name="/modules/Hosts/">
|
||||
<Project Path="src/modules/Hosts/Hosts/Hosts.csproj">
|
||||
<Platform Solution="*|ARM64" Project="ARM64" />
|
||||
|
||||
@@ -58,8 +58,8 @@ string validUIDisplayString = Resources.ValidUIDisplayString;
|
||||
## More On Coding Guidance
|
||||
Please review these brief docs below relating to our coding standards, etc.
|
||||
|
||||
* [Coding Style](./style.md)
|
||||
* [Code Organization](./readme.md)
|
||||
* [Coding Style](development/style.md)
|
||||
* [Code Organization](readme.md)
|
||||
|
||||
|
||||
[VS Resource Editor]: https://learn.microsoft.com/cpp/windows/resource-editors?view=vs-2019
|
||||
|
||||
@@ -57,7 +57,7 @@ Once you've discussed your proposed feature/fix/etc. with a team member, and an
|
||||
## Rules
|
||||
|
||||
- **Follow the pattern of what you already see in the code.**
|
||||
- [Coding style](style.md).
|
||||
- [Coding style](development/style.md).
|
||||
- Try to package new functionality/components into libraries that have nicely defined interfaces.
|
||||
- Package new functionality into classes or refactor existing functionality into a class as you extend the code.
|
||||
- When adding new classes/methods/changing existing code, add new unit tests or update the existing tests.
|
||||
|
||||
@@ -50,6 +50,8 @@ Contact the developers of a plugin directly for assistance with a specific plugi
|
||||
| [Hotkeys](https://github.com/ruslanlap/PowerToysRun-Hotkeys) | [ruslanlap](https://github.com/ruslanlap) | Create, manage, and trigger custom keyboard shortcuts directly from PowerToys Run. |
|
||||
| [RandomGen](https://github.com/ruslanlap/PowerToysRun-RandomGen) | [ruslanlap](https://github.com/ruslanlap) | 🎲 Generate random data instantly with a single keystroke. Perfect for developers, testers, designers, and anyone who needs quick access to random data. Features include secure passwords, PINs, names, business data, dates, numbers, GUIDs, color codes, and more. Especially useful for designers who need random color codes and placeholder content. |
|
||||
| [Open With Cursor](https://github.com/VictorNoxx/PowerToys-Run-Cursor/) | [VictorNoxx](https://github.com/VictorNoxx) | Open Visual Studio, VS Code recents with Cursor AI |
|
||||
| [Open With Antigravity](https://github.com/artickc/PowerToys-Run-Antygravity) | [artickc](https://github.com/artickc) | Open Visual Studio, VS Code recents with Antigravity AI |
|
||||
| [Project Launcher Plugin](https://github.com/artickc/ProjectLauncherPowerToysPlugin) | [artickc](https://github.com/artickc) | Access your projects using Project Launcher and PowerToys Run |
|
||||
| [CheatSheets](https://github.com/ruslanlap/PowerToysRun-CheatSheets) | [ruslanlap](https://github.com/ruslanlap) | 📚 Find cheat sheets and command examples instantly from tldr pages, cheat.sh, and devhints.io. Features include favorites system, categories, offline mode, and smart caching. |
|
||||
| [QuickAI](https://github.com/ruslanlap/PowerToysRun-QuickAi) | [ruslanlap](https://github.com/ruslanlap) | AI-powered assistance with instant, smart responses from multiple providers (Groq, Together, Fireworks, OpenRouter, Cohere) |
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Microsoft.PowerToys.FilePreviewCommon
|
||||
var softlineBreak = new Markdig.Extensions.Hardlines.SoftlineBreakAsHardlineExtension();
|
||||
|
||||
MarkdownPipelineBuilder pipelineBuilder;
|
||||
pipelineBuilder = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseEmojiAndSmiley().UseYamlFrontMatter().UseMathematics();
|
||||
pipelineBuilder = new MarkdownPipelineBuilder().UseAdvancedExtensions().UseEmojiAndSmiley().UseYamlFrontMatter().UseMathematics().DisableHtml();
|
||||
pipelineBuilder.Extensions.Add(extension);
|
||||
pipelineBuilder.Extensions.Add(softlineBreak);
|
||||
|
||||
|
||||
@@ -466,27 +466,39 @@
|
||||
TextChanged="EditVariableDialogValueTxtBox_TextChanged"
|
||||
TextWrapping="Wrap" />
|
||||
<MenuFlyoutSeparator Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<ItemsControl
|
||||
<ListView
|
||||
x:Name="EditVariableValuesList"
|
||||
Margin="0,-8,0,12"
|
||||
HorizontalAlignment="Stretch"
|
||||
AllowDrop="True"
|
||||
CanDragItems="True"
|
||||
CanReorderItems="True"
|
||||
DragItemsCompleted="EditVariableValuesList_DragItemsCompleted"
|
||||
ItemsSource="{Binding ValuesList, Mode=TwoWay}"
|
||||
Visibility="{Binding ShowAsList, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="40" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<FontIcon
|
||||
Grid.Column="0"
|
||||
Margin="0,0,8,0"
|
||||
FontSize="16"
|
||||
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
Glyph="" />
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
Background="Transparent"
|
||||
BorderBrush="Transparent"
|
||||
LostFocus="EditVariableValuesListTextBox_LostFocus"
|
||||
Text="{Binding Text}" />
|
||||
<Button
|
||||
x:Uid="More_Options_Button"
|
||||
Grid.Column="1"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Content=""
|
||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||
@@ -523,8 +535,8 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ContentDialog>
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace EnvironmentVariablesUILib
|
||||
{
|
||||
public sealed partial class EnvironmentVariablesMainPage : Page
|
||||
{
|
||||
private const string ValueListSeparator = ";";
|
||||
|
||||
private sealed class RelayCommandParameter
|
||||
{
|
||||
public RelayCommandParameter(Variable variable, VariablesSet set)
|
||||
@@ -440,7 +442,7 @@ namespace EnvironmentVariablesUILib
|
||||
variable.ValuesList.Move(index, index - 1);
|
||||
}
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
}
|
||||
|
||||
@@ -461,7 +463,7 @@ namespace EnvironmentVariablesUILib
|
||||
variable.ValuesList.Move(index, index + 1);
|
||||
}
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
}
|
||||
|
||||
@@ -476,7 +478,7 @@ namespace EnvironmentVariablesUILib
|
||||
var variable = EditVariableDialog.DataContext as Variable;
|
||||
variable.ValuesList.Remove(listItem);
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
}
|
||||
|
||||
@@ -492,7 +494,7 @@ namespace EnvironmentVariablesUILib
|
||||
var index = variable.ValuesList.IndexOf(listItem);
|
||||
variable.ValuesList.Insert(index, new Variable.ValuesListItem { Text = string.Empty });
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.TextChanged -= EditVariableDialogValueTxtBox_TextChanged;
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
EditVariableDialogValueTxtBox.TextChanged += EditVariableDialogValueTxtBox_TextChanged;
|
||||
@@ -510,7 +512,7 @@ namespace EnvironmentVariablesUILib
|
||||
var index = variable.ValuesList.IndexOf(listItem);
|
||||
variable.ValuesList.Insert(index + 1, new Variable.ValuesListItem { Text = string.Empty });
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.TextChanged -= EditVariableDialogValueTxtBox_TextChanged;
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
EditVariableDialogValueTxtBox.TextChanged += EditVariableDialogValueTxtBox_TextChanged;
|
||||
@@ -532,7 +534,7 @@ namespace EnvironmentVariablesUILib
|
||||
listItem.Text = (sender as TextBox)?.Text;
|
||||
var variable = EditVariableDialog.DataContext as Variable;
|
||||
|
||||
var newValues = string.Join(";", variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList?.Select(x => x.Text).ToArray());
|
||||
EditVariableDialogValueTxtBox.TextChanged -= EditVariableDialogValueTxtBox_TextChanged;
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
EditVariableDialogValueTxtBox.TextChanged += EditVariableDialogValueTxtBox_TextChanged;
|
||||
@@ -548,5 +550,16 @@ namespace EnvironmentVariablesUILib
|
||||
CancelAddVariable();
|
||||
ConfirmAddVariableBtn.IsEnabled = false;
|
||||
}
|
||||
|
||||
private void EditVariableValuesList_DragItemsCompleted(ListViewBase sender, DragItemsCompletedEventArgs args)
|
||||
{
|
||||
if (EditVariableDialog.DataContext is Variable variable && variable.ValuesList != null)
|
||||
{
|
||||
var newValues = string.Join(ValueListSeparator, variable.ValuesList.Select(x => x.Text));
|
||||
EditVariableDialogValueTxtBox.TextChanged -= EditVariableDialogValueTxtBox_TextChanged;
|
||||
EditVariableDialogValueTxtBox.Text = newValues;
|
||||
EditVariableDialogValueTxtBox.TextChanged += EditVariableDialogValueTxtBox_TextChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
248
src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.cpp
Normal file
248
src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
#include "pch.h"
|
||||
#include "CLILogic.h"
|
||||
#include <common/utils/json.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include "resource.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T>
|
||||
DWORD_PTR ToDwordPtr(T val)
|
||||
{
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
return reinterpret_cast<DWORD_PTR>(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
return static_cast<DWORD_PTR>(val);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::wstring FormatString(IStringProvider& strings, UINT id, Args... args)
|
||||
{
|
||||
std::wstring format = strings.GetString(id);
|
||||
if (format.empty()) return L"";
|
||||
|
||||
DWORD_PTR arguments[] = { ToDwordPtr(args)..., 0 };
|
||||
|
||||
LPWSTR buffer = nullptr;
|
||||
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
format.c_str(),
|
||||
0,
|
||||
0,
|
||||
reinterpret_cast<LPWSTR>(&buffer),
|
||||
0,
|
||||
reinterpret_cast<va_list*>(arguments));
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
std::wstring result(buffer);
|
||||
LocalFree(buffer);
|
||||
return result;
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
std::wstring get_usage(IStringProvider& strings)
|
||||
{
|
||||
return strings.GetString(IDS_USAGE);
|
||||
}
|
||||
|
||||
std::wstring get_json(const std::vector<ProcessResult>& results)
|
||||
{
|
||||
json::JsonObject root;
|
||||
json::JsonArray processes;
|
||||
|
||||
for (const auto& result : results)
|
||||
{
|
||||
json::JsonObject process;
|
||||
process.SetNamedValue(L"pid", json::JsonValue::CreateNumberValue(result.pid));
|
||||
process.SetNamedValue(L"name", json::JsonValue::CreateStringValue(result.name));
|
||||
process.SetNamedValue(L"user", json::JsonValue::CreateStringValue(result.user));
|
||||
|
||||
json::JsonArray files;
|
||||
for (const auto& file : result.files)
|
||||
{
|
||||
files.Append(json::JsonValue::CreateStringValue(file));
|
||||
}
|
||||
process.SetNamedValue(L"files", files);
|
||||
|
||||
processes.Append(process);
|
||||
}
|
||||
|
||||
root.SetNamedValue(L"processes", processes);
|
||||
return root.Stringify().c_str();
|
||||
}
|
||||
|
||||
std::wstring get_text(const std::vector<ProcessResult>& results, IStringProvider& strings)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
if (results.empty())
|
||||
{
|
||||
ss << strings.GetString(IDS_NO_PROCESSES);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
ss << strings.GetString(IDS_HEADER);
|
||||
for (const auto& result : results)
|
||||
{
|
||||
ss << result.pid << L"\t"
|
||||
<< result.user << L"\t"
|
||||
<< result.name << std::endl;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::wstring kill_processes(const std::vector<ProcessResult>& results, IProcessTerminator& terminator, IStringProvider& strings)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
for (const auto& result : results)
|
||||
{
|
||||
if (terminator.terminate(result.pid))
|
||||
{
|
||||
ss << FormatString(strings, IDS_TERMINATED, result.pid, result.name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << FormatString(strings, IDS_FAILED_TERMINATE, result.pid, result.name.c_str());
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IProcessTerminator& terminator, IStringProvider& strings)
|
||||
{
|
||||
Logger::info("Parsing arguments");
|
||||
if (argc < 2)
|
||||
{
|
||||
Logger::warn("No arguments provided");
|
||||
return { 1, get_usage(strings) };
|
||||
}
|
||||
|
||||
bool json_output = false;
|
||||
bool kill = false;
|
||||
bool wait = false;
|
||||
int timeout_ms = -1;
|
||||
std::vector<std::wstring> paths;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::wstring arg = argv[i];
|
||||
if (arg == L"--json")
|
||||
{
|
||||
json_output = true;
|
||||
}
|
||||
else if (arg == L"--kill")
|
||||
{
|
||||
kill = true;
|
||||
}
|
||||
else if (arg == L"--wait")
|
||||
{
|
||||
wait = true;
|
||||
}
|
||||
else if (arg == L"--timeout")
|
||||
{
|
||||
if (i + 1 < argc)
|
||||
{
|
||||
try
|
||||
{
|
||||
timeout_ms = std::stoi(argv[++i]);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
Logger::error("Invalid timeout value");
|
||||
return { 1, strings.GetString(IDS_ERROR_INVALID_TIMEOUT) };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::error("Timeout argument missing");
|
||||
return { 1, strings.GetString(IDS_ERROR_TIMEOUT_ARG) };
|
||||
}
|
||||
}
|
||||
else if (arg == L"--help")
|
||||
{
|
||||
return { 0, get_usage(strings) };
|
||||
}
|
||||
else
|
||||
{
|
||||
paths.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (paths.empty())
|
||||
{
|
||||
Logger::error("No paths specified");
|
||||
return { 1, strings.GetString(IDS_ERROR_NO_PATHS) };
|
||||
}
|
||||
|
||||
Logger::info("Processing {} paths", paths.size());
|
||||
|
||||
if (wait)
|
||||
{
|
||||
std::wstringstream ss;
|
||||
if (json_output)
|
||||
{
|
||||
Logger::warn("Wait is incompatible with JSON output");
|
||||
ss << strings.GetString(IDS_WARN_JSON_WAIT);
|
||||
json_output = false;
|
||||
}
|
||||
|
||||
ss << strings.GetString(IDS_WAITING);
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
while (true)
|
||||
{
|
||||
auto results = finder.find(paths);
|
||||
if (results.empty())
|
||||
{
|
||||
Logger::info("Files unlocked");
|
||||
ss << strings.GetString(IDS_UNLOCKED);
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeout_ms >= 0)
|
||||
{
|
||||
auto current_time = std::chrono::steady_clock::now();
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(current_time - start_time).count();
|
||||
if (elapsed > timeout_ms)
|
||||
{
|
||||
Logger::warn("Timeout waiting for files to be unlocked");
|
||||
ss << strings.GetString(IDS_TIMEOUT);
|
||||
return { 1, ss.str() };
|
||||
}
|
||||
}
|
||||
|
||||
Sleep(200);
|
||||
}
|
||||
return { 0, ss.str() };
|
||||
}
|
||||
|
||||
auto results = finder.find(paths);
|
||||
Logger::info("Found {} processes locking the files", results.size());
|
||||
std::wstringstream output_ss;
|
||||
|
||||
if (kill)
|
||||
{
|
||||
Logger::info("Killing processes");
|
||||
output_ss << kill_processes(results, terminator, strings);
|
||||
// Re-check after killing
|
||||
results = finder.find(paths);
|
||||
Logger::info("Remaining processes: {}", results.size());
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
{
|
||||
output_ss << get_json(results) << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_ss << get_text(results, strings);
|
||||
}
|
||||
|
||||
return { 0, output_ss.str() };
|
||||
}
|
||||
31
src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.h
Normal file
31
src/modules/FileLocksmith/FileLocksmithCLI/CLILogic.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "FileLocksmithLib/FileLocksmith.h"
|
||||
#include <Windows.h>
|
||||
|
||||
struct CommandResult
|
||||
{
|
||||
int exit_code;
|
||||
std::wstring output;
|
||||
};
|
||||
|
||||
struct IProcessFinder
|
||||
{
|
||||
virtual std::vector<ProcessResult> find(const std::vector<std::wstring>& paths) = 0;
|
||||
virtual ~IProcessFinder() = default;
|
||||
};
|
||||
|
||||
struct IProcessTerminator
|
||||
{
|
||||
virtual bool terminate(DWORD pid) = 0;
|
||||
virtual ~IProcessTerminator() = default;
|
||||
};
|
||||
|
||||
struct IStringProvider
|
||||
{
|
||||
virtual std::wstring GetString(UINT id) = 0;
|
||||
virtual ~IStringProvider() = default;
|
||||
};
|
||||
|
||||
CommandResult run_command(int argc, wchar_t* argv[], IProcessFinder& finder, IProcessTerminator& terminator, IStringProvider& strings);
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "resource.h"
|
||||
#include <windows.h>
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_USAGE "Usage: FileLocksmithCLI.exe [options] <path1> [path2] ...\nOptions:\n --kill Kill processes locking the files\n --json Output results in JSON format\n --wait Wait for files to be unlocked\n --timeout Timeout in milliseconds for --wait\n --help Show this help message\n"
|
||||
IDS_NO_PROCESSES "No processes found locking the file(s).\n"
|
||||
IDS_HEADER "PID\tUser\tProcess\n"
|
||||
IDS_TERMINATED "Terminated process %1!d! (%2)\n"
|
||||
IDS_FAILED_TERMINATE "Failed to terminate process %1!d! (%2)\n"
|
||||
IDS_FAILED_OPEN "Failed to open process %1!d! (%2)\n"
|
||||
IDS_ERROR_NO_PATHS "Error: No paths specified.\n"
|
||||
IDS_WARN_JSON_WAIT "Warning: --wait is incompatible with --json. Ignoring --json.\n"
|
||||
IDS_WAITING "Waiting for files to be unlocked...\n"
|
||||
IDS_UNLOCKED "Files unlocked.\n"
|
||||
IDS_TIMEOUT "Timeout waiting for files to be unlocked.\n"
|
||||
IDS_ERROR_INVALID_TIMEOUT "Error: Invalid timeout value.\n"
|
||||
IDS_ERROR_TIMEOUT_ARG "Error: --timeout requires an argument.\n"
|
||||
END
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{49D456D3-F485-45AF-8875-45B44F193DDC}</ProjectGuid>
|
||||
<RootNamespace>FileLocksmithCLI</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>FileLocksmithCLI</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\$(Platform)\$(Configuration)</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\..\..;$(ProjectDir)..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..;$(ProjectDir)..\..\..;$(ProjectDir)..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CLILogic.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CLILogic.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="FileLocksmithCLI.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileLocksmithLib\FileLocksmithLib.vcxproj">
|
||||
<Project>{9d52fd25-ef90-4f9a-a015-91efc5daf54f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\common\version\version.vcxproj">
|
||||
<Project>{1248566c-272a-43c0-88d6-e6675d569a09}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CLILogic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CLILogic.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
71
src/modules/FileLocksmith/FileLocksmithCLI/main.cpp
Normal file
71
src/modules/FileLocksmith/FileLocksmithCLI/main.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "pch.h"
|
||||
#include "CLILogic.h"
|
||||
#include "FileLocksmithLib/FileLocksmith.h"
|
||||
#include <iostream>
|
||||
#include "resource.h"
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/logger_helper.h>
|
||||
|
||||
struct RealProcessFinder : IProcessFinder
|
||||
{
|
||||
std::vector<ProcessResult> find(const std::vector<std::wstring>& paths) override
|
||||
{
|
||||
return find_processes_recursive(paths);
|
||||
}
|
||||
};
|
||||
|
||||
struct RealProcessTerminator : IProcessTerminator
|
||||
{
|
||||
bool terminate(DWORD pid) override
|
||||
{
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
|
||||
if (hProcess)
|
||||
{
|
||||
bool result = TerminateProcess(hProcess, 0);
|
||||
CloseHandle(hProcess);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct RealStringProvider : IStringProvider
|
||||
{
|
||||
std::wstring GetString(UINT id) override
|
||||
{
|
||||
wchar_t buffer[4096];
|
||||
int len = LoadStringW(GetModuleHandle(NULL), id, buffer, ARRAYSIZE(buffer));
|
||||
if (len > 0)
|
||||
{
|
||||
return std::wstring(buffer, len);
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef UNIT_TEST
|
||||
int wmain(int argc, wchar_t* argv[])
|
||||
{
|
||||
winrt::init_apartment();
|
||||
LoggerHelpers::init_logger(L"FileLocksmithCLI", L"", LogSettings::fileLocksmithLoggerName);
|
||||
Logger::info("FileLocksmithCLI started");
|
||||
|
||||
RealProcessFinder finder;
|
||||
RealProcessTerminator terminator;
|
||||
RealStringProvider strings;
|
||||
|
||||
auto result = run_command(argc, argv, finder, terminator, strings);
|
||||
|
||||
if (result.exit_code != 0)
|
||||
{
|
||||
Logger::error("Command failed with exit code {}", result.exit_code);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::info("Command succeeded");
|
||||
}
|
||||
|
||||
std::wcout << result.output;
|
||||
return result.exit_code;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/FileLocksmith/FileLocksmithCLI/pch.cpp
Normal file
1
src/modules/FileLocksmith/FileLocksmithCLI/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
22
src/modules/FileLocksmith/FileLocksmithCLI/pch.h
Normal file
22
src/modules/FileLocksmith/FileLocksmithCLI/pch.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
#include <Psapi.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include <winrt/base.h>
|
||||
|
||||
#endif // PCH_H
|
||||
16
src/modules/FileLocksmith/FileLocksmithCLI/resource.h
Normal file
16
src/modules/FileLocksmith/FileLocksmithCLI/resource.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// resource.h
|
||||
#pragma once
|
||||
|
||||
#define IDS_USAGE 101
|
||||
#define IDS_NO_PROCESSES 102
|
||||
#define IDS_HEADER 103
|
||||
#define IDS_TERMINATED 104
|
||||
#define IDS_FAILED_TERMINATE 105
|
||||
#define IDS_FAILED_OPEN 106
|
||||
#define IDS_ERROR_NO_PATHS 107
|
||||
#define IDS_WARN_JSON_WAIT 108
|
||||
#define IDS_WAITING 109
|
||||
#define IDS_UNLOCKED 110
|
||||
#define IDS_TIMEOUT 111
|
||||
#define IDS_ERROR_INVALID_TIMEOUT 112
|
||||
#define IDS_ERROR_TIMEOUT_ARG 113
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "pch.h"
|
||||
#include "CppUnitTest.h"
|
||||
#include "../CLILogic.h"
|
||||
#include <map>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace FileLocksmithCLIUnitTests
|
||||
{
|
||||
struct MockProcessFinder : IProcessFinder
|
||||
{
|
||||
std::vector<ProcessResult> results;
|
||||
std::vector<ProcessResult> find(const std::vector<std::wstring>& paths) override
|
||||
{
|
||||
(void)paths;
|
||||
return results;
|
||||
}
|
||||
};
|
||||
|
||||
struct MockProcessTerminator : IProcessTerminator
|
||||
{
|
||||
bool shouldSucceed = true;
|
||||
std::vector<DWORD> terminatedPids;
|
||||
bool terminate(DWORD pid) override
|
||||
{
|
||||
terminatedPids.push_back(pid);
|
||||
return shouldSucceed;
|
||||
}
|
||||
};
|
||||
|
||||
struct MockStringProvider : IStringProvider
|
||||
{
|
||||
std::map<UINT, std::wstring> strings;
|
||||
std::wstring GetString(UINT id) override
|
||||
{
|
||||
if (strings.count(id)) return strings[id];
|
||||
return L"String_" + std::to_wstring(id);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(CLITests)
|
||||
{
|
||||
public:
|
||||
|
||||
TEST_METHOD(TestNoArgs)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe" };
|
||||
auto result = run_command(1, argv, finder, terminator, strings);
|
||||
|
||||
Assert::AreEqual(1, result.exit_code);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestHelp)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe", (wchar_t*)L"--help" };
|
||||
auto result = run_command(2, argv, finder, terminator, strings);
|
||||
|
||||
Assert::AreEqual(0, result.exit_code);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestFindProcesses)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
finder.results = { { L"process", 123, L"user", { L"file1" } } };
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe", (wchar_t*)L"file1" };
|
||||
auto result = run_command(2, argv, finder, terminator, strings);
|
||||
|
||||
Assert::AreEqual(0, result.exit_code);
|
||||
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
|
||||
Assert::IsTrue(result.output.find(L"process") != std::wstring::npos);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestJsonOutput)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
finder.results = { { L"process", 123, L"user", { L"file1" } } };
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe", (wchar_t*)L"file1", (wchar_t*)L"--json" };
|
||||
auto result = run_command(3, argv, finder, terminator, strings);
|
||||
|
||||
Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(result.output.c_str());
|
||||
|
||||
Assert::AreEqual(0, result.exit_code);
|
||||
Assert::IsTrue(result.output.find(L"\"pid\"") != std::wstring::npos);
|
||||
Assert::IsTrue(result.output.find(L"123") != std::wstring::npos);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestKill)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
finder.results = { { L"process", 123, L"user", { L"file1" } } };
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe", (wchar_t*)L"file1", (wchar_t*)L"--kill" };
|
||||
auto result = run_command(3, argv, finder, terminator, strings);
|
||||
|
||||
Assert::AreEqual(0, result.exit_code);
|
||||
Assert::AreEqual((size_t)1, terminator.terminatedPids.size());
|
||||
Assert::AreEqual((DWORD)123, terminator.terminatedPids[0]);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestTimeout)
|
||||
{
|
||||
MockProcessFinder finder;
|
||||
// Always return results so it waits
|
||||
finder.results = { { L"process", 123, L"user", { L"file1" } } };
|
||||
MockProcessTerminator terminator;
|
||||
MockStringProvider strings;
|
||||
|
||||
wchar_t* argv[] = { (wchar_t*)L"exe", (wchar_t*)L"file1", (wchar_t*)L"--wait", (wchar_t*)L"--timeout", (wchar_t*)L"100" };
|
||||
auto result = run_command(5, argv, finder, terminator, strings);
|
||||
|
||||
Assert::AreEqual(1, result.exit_code);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A1B2C3D4-E5F6-7890-1234-567890ABCDEF}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>FileLocksmithCLIUnitTests</RootNamespace>
|
||||
<ProjectName>FileLocksmithCLI.UnitTests</ProjectName>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\..\..\..\deps\spdlog.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<OutDir>..\..\..\..\..\$(Platform)\$(Configuration)\tests\FileLocksmithCLI\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\;..\..\;..\..\..\..\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;UNIT_TEST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<DisableSpecificWarnings>26466;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>shlwapi.lib;ntdll.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileLocksmithCLITests.cpp" />
|
||||
<ClCompile Include="..\CLILogic.cpp">
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\FileLocksmithLib\FileLocksmithLib.vcxproj">
|
||||
<Project>{9d52fd25-ef90-4f9a-a015-91efc5daf54f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
|
||||
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\common\version\version.vcxproj">
|
||||
<Project>{1248566c-272a-43c0-88d6-e6675d569a09}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
1
src/modules/FileLocksmith/FileLocksmithCLI/tests/pch.cpp
Normal file
1
src/modules/FileLocksmith/FileLocksmithCLI/tests/pch.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
9
src/modules/FileLocksmith/FileLocksmithCLI/tests/pch.h
Normal file
9
src/modules/FileLocksmith/FileLocksmithCLI/tests/pch.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <winrt/base.h>
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "CppUnitTest.h"
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ProcessResult.h"
|
||||
|
||||
// Second version, checks handles towards files and all subfiles and folders of given dirs, if any.
|
||||
std::vector<ProcessResult> find_processes_recursive(const std::vector<std::wstring>& paths);
|
||||
|
||||
// Gives the full path of the executable, given the process id
|
||||
std::wstring pid_to_full_path(DWORD pid);
|
||||
@@ -34,9 +34,9 @@
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;FILELOCKSMITH_LIB_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>../../..;../..;</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\FileLocksmithLibInterop;../../..;../..;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
@@ -50,9 +50,9 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;FILELOCKSMITH_LIB_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>../../..;../..;</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\FileLocksmithLibInterop;../../..;../..;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
@@ -68,13 +68,15 @@
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="Trace.h" />
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="IPC.cpp" />
|
||||
<ClCompile Include="Settings.cpp" />
|
||||
<ClCompile Include="Trace.cpp" />
|
||||
<ClCompile Include="FileLocksmithLib.cpp" />
|
||||
<ClCompile Include="..\FileLocksmithLibInterop\FileLocksmith.cpp" />
|
||||
<ClCompile Include="..\FileLocksmithLibInterop\NtdllBase.cpp" />
|
||||
<ClCompile Include="..\FileLocksmithLibInterop\NtdllExtensions.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
|
||||
@@ -38,6 +38,15 @@
|
||||
<ClCompile Include="FileLocksmithLib.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileLocksmith.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NtdllBase.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NtdllExtensions.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
||||
12
src/modules/FileLocksmith/FileLocksmithLib/ProcessResult.h
Normal file
12
src/modules/FileLocksmith/FileLocksmithLib/ProcessResult.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <Windows.h>
|
||||
|
||||
struct ProcessResult
|
||||
{
|
||||
std::wstring name;
|
||||
DWORD pid;
|
||||
std::wstring user;
|
||||
std::vector<std::wstring> files;
|
||||
};
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Settings.h"
|
||||
#include "Constants.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <common/utils/json.h>
|
||||
#include <common/SettingsAPI/settings_helpers.h>
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
|
||||
#endif //PCH_H
|
||||
@@ -18,4 +18,6 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
#ifndef FILELOCKSMITH_LIB_STATIC
|
||||
#include <winrt/PowerToys.Interop.h>
|
||||
#endif
|
||||
|
||||
@@ -405,6 +405,7 @@ public:
|
||||
{
|
||||
m_enabled = true;
|
||||
Logger::info(L"Enabling Light Switch module...");
|
||||
Trace::Enable(true);
|
||||
|
||||
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||
std::wstring args = L"--pid " + std::to_wstring(powertoys_pid);
|
||||
@@ -482,7 +483,8 @@ public:
|
||||
CloseHandle(m_process);
|
||||
m_process = nullptr;
|
||||
}
|
||||
|
||||
|
||||
Trace::Enable(false);
|
||||
StopToggleListener();
|
||||
}
|
||||
|
||||
@@ -539,6 +541,8 @@ public:
|
||||
if (m_enabled)
|
||||
{
|
||||
Logger::trace(L"Light Switch hotkey pressed");
|
||||
Trace::ShortcutInvoked();
|
||||
|
||||
if (!is_process_running())
|
||||
{
|
||||
enable();
|
||||
|
||||
@@ -19,12 +19,21 @@ void Trace::UnregisterProvider()
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::MyEvent()
|
||||
void Trace::Enable(bool enabled) noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"PowerToyName_MyEvent",
|
||||
"LightSwitch_EnableLightSwitch",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(enabled, "Enabled"));
|
||||
}
|
||||
|
||||
void Trace::ShortcutInvoked() noexcept
|
||||
{
|
||||
TraceLoggingWrite(
|
||||
g_hProvider,
|
||||
"LightSwitch_ShortcutInvoked",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
}
|
||||
|
||||
@@ -11,5 +11,6 @@ class Trace
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void MyEvent();
|
||||
static void Enable(bool enabled) noexcept;
|
||||
static void ShortcutInvoked() noexcept;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "LightSwitchStateManager.h"
|
||||
#include <LightSwitchUtils.h>
|
||||
#include <NightLightRegistryObserver.h>
|
||||
#include <trace.h>
|
||||
|
||||
SERVICE_STATUS g_ServiceStatus = {};
|
||||
SERVICE_STATUS_HANDLE g_StatusHandle = nullptr;
|
||||
@@ -357,6 +358,8 @@ DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
|
||||
int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||
{
|
||||
Trace::LightSwitch::RegisterProvider();
|
||||
|
||||
if (powertoys_gpo::getConfiguredLightSwitchEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
|
||||
{
|
||||
wchar_t msg[160];
|
||||
@@ -364,12 +367,14 @@ int APIENTRY wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
|
||||
msg,
|
||||
L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
|
||||
Logger::info(msg);
|
||||
Trace::LightSwitch::UnregisterProvider();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int argc = 0;
|
||||
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
int rc = _tmain(argc, argv); // reuse your existing logic
|
||||
LocalFree(argv);
|
||||
|
||||
Trace::LightSwitch::UnregisterProvider();
|
||||
return rc;
|
||||
}
|
||||
@@ -80,6 +80,7 @@
|
||||
<ClCompile Include="SettingsConstants.cpp" />
|
||||
<ClCompile Include="ThemeHelper.cpp" />
|
||||
<ClCompile Include="ThemeScheduler.cpp" />
|
||||
<ClCompile Include="trace.cpp" />
|
||||
<ClCompile Include="WinHookEventIDs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -94,6 +95,7 @@
|
||||
<ClInclude Include="SettingsObserver.h" />
|
||||
<ClInclude Include="ThemeHelper.h" />
|
||||
<ClInclude Include="ThemeScheduler.h" />
|
||||
<ClInclude Include="trace.h" />
|
||||
<ClInclude Include="WinHookEventIDs.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<ClCompile Include="NightLightRegistryObserver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ThemeScheduler.h">
|
||||
@@ -68,6 +71,9 @@
|
||||
<ClInclude Include="NightLightRegistryObserver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="trace.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <logger.h>
|
||||
#include <LightSwitchService/trace.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -151,6 +152,7 @@ void LightSwitchSettings::LoadSettings()
|
||||
if (m_settings.scheduleMode != newMode)
|
||||
{
|
||||
m_settings.scheduleMode = newMode;
|
||||
Trace::LightSwitch::ScheduleModeToggled(val);
|
||||
NotifyObservers(SettingId::ScheduleMode);
|
||||
}
|
||||
}
|
||||
@@ -220,6 +222,8 @@ void LightSwitchSettings::LoadSettings()
|
||||
}
|
||||
}
|
||||
|
||||
bool themeTargetChanged = false;
|
||||
|
||||
// ChangeSystem
|
||||
if (const auto jsonVal = values.get_bool_value(L"changeSystem"))
|
||||
{
|
||||
@@ -227,6 +231,7 @@ void LightSwitchSettings::LoadSettings()
|
||||
if (m_settings.changeSystem != val)
|
||||
{
|
||||
m_settings.changeSystem = val;
|
||||
themeTargetChanged = true;
|
||||
NotifyObservers(SettingId::ChangeSystem);
|
||||
}
|
||||
}
|
||||
@@ -238,9 +243,16 @@ void LightSwitchSettings::LoadSettings()
|
||||
if (m_settings.changeApps != val)
|
||||
{
|
||||
m_settings.changeApps = val;
|
||||
themeTargetChanged = true;
|
||||
NotifyObservers(SettingId::ChangeApps);
|
||||
}
|
||||
}
|
||||
|
||||
// For ChangeSystem/ChangeApps changes, log telemetry
|
||||
if (themeTargetChanged)
|
||||
{
|
||||
Trace::LightSwitch::ThemeTargetChanged(m_settings.changeApps, m_settings.changeSystem);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
43
src/modules/LightSwitch/LightSwitchService/trace.cpp
Normal file
43
src/modules/LightSwitch/LightSwitchService/trace.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "pch.h"
|
||||
#include "trace.h"
|
||||
|
||||
// Telemetry strings should not be localized.
|
||||
#define LoggingProviderKey "Microsoft.PowerToys"
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
g_hProvider,
|
||||
LoggingProviderKey,
|
||||
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||
TraceLoggingOptionProjectTelemetry());
|
||||
|
||||
void Trace::LightSwitch::RegisterProvider()
|
||||
{
|
||||
TraceLoggingRegister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::LightSwitch::UnregisterProvider()
|
||||
{
|
||||
TraceLoggingUnregister(g_hProvider);
|
||||
}
|
||||
|
||||
void Trace::LightSwitch::ScheduleModeToggled(const std::wstring& newMode) noexcept
|
||||
{
|
||||
TraceLoggingWriteWrapper(
|
||||
g_hProvider,
|
||||
"LightSwitch_ScheduleModeToggled",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingWideString(newMode.c_str(), "NewMode"));
|
||||
}
|
||||
|
||||
void Trace::LightSwitch::ThemeTargetChanged(bool changeApps, bool changeSystem) noexcept
|
||||
{
|
||||
TraceLoggingWriteWrapper(
|
||||
g_hProvider,
|
||||
"LightSwitch_ThemeTargetChanged",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingBoolean(changeApps, "ChangeApps"),
|
||||
TraceLoggingBoolean(changeSystem, "ChangeSystem"));
|
||||
}
|
||||
17
src/modules/LightSwitch/LightSwitchService/trace.h
Normal file
17
src/modules/LightSwitch/LightSwitchService/trace.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/Telemetry/TraceBase.h>
|
||||
#include <string>
|
||||
|
||||
class Trace
|
||||
{
|
||||
public:
|
||||
class LightSwitch : public telemetry::TraceBase
|
||||
{
|
||||
public:
|
||||
static void RegisterProvider();
|
||||
static void UnregisterProvider();
|
||||
static void ScheduleModeToggled(const std::wstring& newMode) noexcept;
|
||||
static void ThemeTargetChanged(bool changeApps, bool changeSystem) noexcept;
|
||||
};
|
||||
};
|
||||
@@ -77,10 +77,8 @@ protected:
|
||||
int m_sonarRadius = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_RADIUS;
|
||||
int m_sonarZoomFactor = FIND_MY_MOUSE_DEFAULT_SPOTLIGHT_INITIAL_ZOOM;
|
||||
DWORD m_fadeDuration = FIND_MY_MOUSE_DEFAULT_ANIMATION_DURATION_MS;
|
||||
int m_finalAlphaNumerator = 100; // legacy (root now always animates to 1.0; kept for GDI fallback compatibility)
|
||||
std::vector<std::wstring> m_excludedApps;
|
||||
int m_shakeMinimumDistance = FIND_MY_MOUSE_DEFAULT_SHAKE_MINIMUM_DISTANCE;
|
||||
static constexpr int FinalAlphaDenominator = 100;
|
||||
winrt::Microsoft::UI::Dispatching::DispatcherQueueController m_dispatcherQueueController{ nullptr };
|
||||
|
||||
// Don't consider movements started past these milliseconds to detect shaking.
|
||||
@@ -155,7 +153,7 @@ private:
|
||||
void DetectShake();
|
||||
bool KeyboardInputCanActivate();
|
||||
|
||||
void StartSonar();
|
||||
void StartSonar(FindMyMouseActivationMethod activationMethod);
|
||||
void StopSonar();
|
||||
};
|
||||
|
||||
@@ -275,7 +273,7 @@ LRESULT SuperSonar<D>::BaseWndProc(UINT message, WPARAM wParam, LPARAM lParam) n
|
||||
{
|
||||
if (m_sonarStart == NoSonar)
|
||||
{
|
||||
StartSonar();
|
||||
StartSonar(FindMyMouseActivationMethod::Shortcut);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -384,7 +382,7 @@ void SuperSonar<D>::OnSonarKeyboardInput(RAWINPUT const& input)
|
||||
IsEqual(m_lastKeyPos, ptCursor))
|
||||
{
|
||||
m_sonarState = SonarState::ControlDown2;
|
||||
StartSonar();
|
||||
StartSonar(m_activationMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -451,7 +449,7 @@ void SuperSonar<D>::DetectShake()
|
||||
if (diagonal > 0 && distanceTravelled / diagonal > (m_shakeFactor / 100.f))
|
||||
{
|
||||
m_movementHistory.clear();
|
||||
StartSonar();
|
||||
StartSonar(m_activationMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,7 +517,7 @@ void SuperSonar<D>::OnSonarMouseInput(RAWINPUT const& input)
|
||||
}
|
||||
|
||||
template<typename D>
|
||||
void SuperSonar<D>::StartSonar()
|
||||
void SuperSonar<D>::StartSonar(FindMyMouseActivationMethod activationMethod)
|
||||
{
|
||||
// Don't activate if game mode is on.
|
||||
if (m_doNotActivateOnGameMode && detect_game_mode())
|
||||
@@ -532,7 +530,7 @@ void SuperSonar<D>::StartSonar()
|
||||
return;
|
||||
}
|
||||
|
||||
Trace::MousePointerFocused();
|
||||
Trace::MousePointerFocused(static_cast<int>(activationMethod));
|
||||
// Cover the entire virtual screen.
|
||||
// HACK: Draw with 1 pixel off. Otherwise, Windows glitches the task bar transparency when a transparent window fill the whole screen.
|
||||
SetWindowPos(m_hwnd, HWND_TOPMOST, GetSystemMetrics(SM_XVIRTUALSCREEN) + 1, GetSystemMetrics(SM_YVIRTUALSCREEN) + 1, GetSystemMetrics(SM_CXVIRTUALSCREEN) - 2, GetSystemMetrics(SM_CYVIRTUALSCREEN) - 2, 0);
|
||||
@@ -816,13 +814,16 @@ private:
|
||||
// Dim color (source)
|
||||
m_dimColorBrush = m_compositor.CreateColorBrush(m_backgroundColor);
|
||||
// Radial gradient mask (center transparent, outer opaque)
|
||||
// Fixed feather width: 1px for radius < 300, 2px for radius >= 300
|
||||
const float featherPixels = (m_sonarRadius >= 300) ? 2.0f : 1.0f;
|
||||
const float featherOffset = 1.0f - featherPixels / (rDip * zoom);
|
||||
m_spotlightMaskGradient = m_compositor.CreateRadialGradientBrush();
|
||||
m_spotlightMaskGradient.MappingMode(muxc::CompositionMappingMode::Absolute);
|
||||
m_maskStopCenter = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopCenter.Offset(0.0f);
|
||||
m_maskStopCenter.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
|
||||
m_maskStopInner = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopInner.Offset(0.995f);
|
||||
m_maskStopInner.Offset(featherOffset);
|
||||
m_maskStopInner.Color(winrt::Windows::UI::ColorHelper::FromArgb(0, 0, 0, 0));
|
||||
m_maskStopOuter = m_compositor.CreateColorGradientStop();
|
||||
m_maskStopOuter.Offset(1.0f);
|
||||
@@ -852,23 +853,7 @@ private:
|
||||
m_root.ImplicitAnimations(collection);
|
||||
|
||||
// 6) Spotlight radius shrinks as opacity increases (expression animation)
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(
|
||||
expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius));
|
||||
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression);
|
||||
// Also animate spotlight geometry radius for visual consistency
|
||||
if (m_circleGeometry)
|
||||
{
|
||||
auto radiusExpression2 = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression2.SetReferenceParameter(L"Root", m_root);
|
||||
radiusExpression2.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression2);
|
||||
}
|
||||
SetupRadiusAnimations(rDip * zoom, rDip, featherPixels);
|
||||
|
||||
// Composition created successfully
|
||||
return true;
|
||||
@@ -887,6 +872,41 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to setup radius and feather expression animations
|
||||
void SetupRadiusAnimations(float startRadiusDip, float endRadiusDip, float featherPixels)
|
||||
{
|
||||
// Radius expression: shrinks from startRadiusDip to endRadiusDip as opacity goes 0->1
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(
|
||||
expressionText, ARRAYSIZE(expressionText),
|
||||
L"Lerp(Vector2(%.1f, %.1f), Vector2(%.1f, %.1f), Root.Opacity)",
|
||||
startRadiusDip, startRadiusDip, endRadiusDip, endRadiusDip));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression);
|
||||
|
||||
// Feather expression: maintains fixed pixel width as radius changes
|
||||
auto featherExpression = m_compositor.CreateExpressionAnimation();
|
||||
featherExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t featherExpressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(
|
||||
featherExpressionText, ARRAYSIZE(featherExpressionText),
|
||||
L"1.0f - %.1ff / Lerp(%.1ff, %.1ff, Root.Opacity)",
|
||||
featherPixels, startRadiusDip, endRadiusDip));
|
||||
featherExpression.Expression(featherExpressionText);
|
||||
m_maskStopInner.StartAnimation(L"Offset", featherExpression);
|
||||
|
||||
// Circle geometry radius for visual consistency
|
||||
if (m_circleGeometry)
|
||||
{
|
||||
auto radiusExpression2 = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression2.SetReferenceParameter(L"Root", m_root);
|
||||
radiusExpression2.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression2);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateIslandSize()
|
||||
{
|
||||
if (!m_island)
|
||||
@@ -964,27 +984,21 @@ public:
|
||||
const float scale = static_cast<float>(m_surface.XamlRoot().RasterizationScale());
|
||||
const float rDip = m_sonarRadiusFloat / scale;
|
||||
const float zoom = static_cast<float>(m_sonarZoomFactor);
|
||||
const float featherPixels = (m_sonarRadius >= 300) ? 2.0f : 1.0f;
|
||||
const float startRadiusDip = rDip * zoom;
|
||||
m_spotlightMaskGradient.StopAnimation(L"EllipseRadius");
|
||||
m_spotlightMaskGradient.EllipseCenter({ rDip * zoom, rDip * zoom });
|
||||
if (m_spotlight)
|
||||
{
|
||||
m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom });
|
||||
m_circleShape.Offset({ rDip * zoom, rDip * zoom });
|
||||
}
|
||||
auto radiusExpression = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression.SetReferenceParameter(L"Root", m_root);
|
||||
wchar_t expressionText[256];
|
||||
winrt::check_hresult(StringCchPrintfW(expressionText, ARRAYSIZE(expressionText), L"Lerp(Vector2(%d, %d), Vector2(%d, %d), Root.Opacity)", m_sonarRadius * m_sonarZoomFactor, m_sonarRadius * m_sonarZoomFactor, m_sonarRadius, m_sonarRadius));
|
||||
radiusExpression.Expression(expressionText);
|
||||
m_spotlightMaskGradient.StartAnimation(L"EllipseRadius", radiusExpression);
|
||||
m_maskStopInner.StopAnimation(L"Offset");
|
||||
if (m_circleGeometry)
|
||||
{
|
||||
m_circleGeometry.StopAnimation(L"Radius");
|
||||
auto radiusExpression2 = m_compositor.CreateExpressionAnimation();
|
||||
radiusExpression2.SetReferenceParameter(L"Root", m_root);
|
||||
radiusExpression2.Expression(expressionText);
|
||||
m_circleGeometry.StartAnimation(L"Radius", radiusExpression2);
|
||||
}
|
||||
m_spotlightMaskGradient.EllipseCenter({ startRadiusDip, startRadiusDip });
|
||||
if (m_spotlight)
|
||||
{
|
||||
m_spotlight.Size({ rDip * 2 * zoom, rDip * 2 * zoom });
|
||||
m_circleShape.Offset({ startRadiusDip, startRadiusDip });
|
||||
}
|
||||
SetupRadiusAnimations(startRadiusDip, rDip, featherPixels);
|
||||
}
|
||||
});
|
||||
if (!enqueueSucceeded)
|
||||
@@ -1018,202 +1032,6 @@ private:
|
||||
muxc::ScalarKeyFrameAnimation m_animation{ nullptr };
|
||||
};
|
||||
|
||||
template<typename D>
|
||||
struct GdiSonar : SuperSonar<D>
|
||||
{
|
||||
LRESULT WndProc(UINT message, WPARAM wParam, LPARAM lParam) noexcept
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, 0, LWA_ALPHA);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
switch (wParam)
|
||||
{
|
||||
case TIMER_ID_FADE:
|
||||
OnFadeTimer();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
this->Shim()->OnPaint();
|
||||
break;
|
||||
}
|
||||
return this->BaseWndProc(message, wParam, lParam);
|
||||
}
|
||||
|
||||
void BeforeMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
void AfterMoveSonar() { this->Shim()->InvalidateSonar(); }
|
||||
|
||||
void SetSonarVisibility(bool visible)
|
||||
{
|
||||
m_alphaTarget = visible ? MaxAlpha : 0;
|
||||
m_fadeStart = GetTickCount() - FadeFramePeriod;
|
||||
SetTimer(this->m_hwnd, TIMER_ID_FADE, FadeFramePeriod, nullptr);
|
||||
OnFadeTimer();
|
||||
}
|
||||
|
||||
void OnFadeTimer()
|
||||
{
|
||||
auto now = GetTickCount();
|
||||
auto step = (int)((now - m_fadeStart) * MaxAlpha / this->m_fadeDuration);
|
||||
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha < m_alphaTarget)
|
||||
{
|
||||
m_alpha += step;
|
||||
if (m_alpha > m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
else if (m_alpha > m_alphaTarget)
|
||||
{
|
||||
m_alpha -= step;
|
||||
if (m_alpha < m_alphaTarget)
|
||||
m_alpha = m_alphaTarget;
|
||||
}
|
||||
SetLayeredWindowAttributes(this->m_hwnd, 0, (BYTE)m_alpha, LWA_ALPHA);
|
||||
this->Shim()->InvalidateSonar();
|
||||
if (m_alpha == m_alphaTarget)
|
||||
{
|
||||
KillTimer(this->m_hwnd, TIMER_ID_FADE);
|
||||
if (m_alpha == 0)
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_HIDE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowWindow(this->m_hwnd, SW_SHOWNOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int CurrentSonarRadius()
|
||||
{
|
||||
int range = MaxAlpha - m_alpha;
|
||||
int radius = this->m_sonarRadius + this->m_sonarRadius * range * (this->m_sonarZoomFactor - 1) / MaxAlpha;
|
||||
return radius;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr DWORD FadeFramePeriod = 10;
|
||||
int MaxAlpha = SuperSonar<D>::m_finalAlphaNumerator * 255 / SuperSonar<D>::FinalAlphaDenominator;
|
||||
static constexpr DWORD TIMER_ID_FADE = 101;
|
||||
|
||||
private:
|
||||
int m_alpha = 0;
|
||||
int m_alphaTarget = 0;
|
||||
DWORD m_fadeStart = 0;
|
||||
};
|
||||
|
||||
struct GdiSpotlight : GdiSonar<GdiSpotlight>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
rc.left = this->m_sonarPos.x - radius;
|
||||
rc.top = this->m_sonarPos.y - radius;
|
||||
rc.right = this->m_sonarPos.x + radius;
|
||||
rc.bottom = this->m_sonarPos.y + radius;
|
||||
InvalidateRect(this->m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
auto spotlight = CreateRoundRectRgn(
|
||||
this->m_sonarPos.x - radius, this->m_sonarPos.y - radius, this->m_sonarPos.x + radius, this->m_sonarPos.y + radius, radius * 2, radius * 2);
|
||||
|
||||
FillRgn(ps.hdc, spotlight, static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH)));
|
||||
Sleep(1000 / 60);
|
||||
ExtSelectClipRgn(ps.hdc, spotlight, RGN_DIFF);
|
||||
FillRect(ps.hdc, &ps.rcPaint, static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
|
||||
DeleteObject(spotlight);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
struct GdiCrosshairs : GdiSonar<GdiCrosshairs>
|
||||
{
|
||||
void InvalidateSonar()
|
||||
{
|
||||
RECT rc;
|
||||
auto radius = CurrentSonarRadius();
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
|
||||
GetClientRect(m_hwnd, &rc);
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
InvalidateRect(m_hwnd, &rc, FALSE);
|
||||
}
|
||||
|
||||
void OnPaint()
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(this->m_hwnd, &ps);
|
||||
|
||||
auto radius = CurrentSonarRadius();
|
||||
RECT rc;
|
||||
|
||||
HBRUSH white = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
|
||||
|
||||
rc.left = m_sonarPos.x - radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x + radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y - radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y + radius;
|
||||
FillRect(ps.hdc, &rc, white);
|
||||
|
||||
HBRUSH black = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
|
||||
|
||||
// Top left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Top right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = ps.rcPaint.top;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = m_sonarPos.y - radius;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom left
|
||||
rc.left = ps.rcPaint.left;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = m_sonarPos.x - radius;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
// Bottom right
|
||||
rc.left = m_sonarPos.x + radius;
|
||||
rc.top = m_sonarPos.y + radius;
|
||||
rc.right = ps.rcPaint.right;
|
||||
rc.bottom = ps.rcPaint.bottom;
|
||||
FillRect(ps.hdc, &rc, black);
|
||||
|
||||
EndPaint(this->m_hwnd, &ps);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma endregion Super_Sonar_Base_Code
|
||||
|
||||
#pragma region Super_Sonar_API
|
||||
@@ -1284,4 +1102,4 @@ HWND GetSonarHwnd() noexcept
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#pragma endregion Super_Sonar_API
|
||||
#pragma endregion Super_Sonar_API
|
||||
@@ -154,4 +154,4 @@
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -22,11 +22,12 @@ void Trace::EnableFindMyMouse(const bool enabled) noexcept
|
||||
}
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
void Trace::MousePointerFocused() noexcept
|
||||
void Trace::MousePointerFocused(const int activationMethod) noexcept
|
||||
{
|
||||
TraceLoggingWriteWrapper(
|
||||
g_hProvider,
|
||||
"FindMyMouse_MousePointerFocused",
|
||||
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
|
||||
TraceLoggingInt32(activationMethod, "ActivationMethod"));
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@ public:
|
||||
static void EnableFindMyMouse(const bool enabled) noexcept;
|
||||
|
||||
// Log that the user activated the module by focusing the mouse pointer
|
||||
static void MousePointerFocused() noexcept;
|
||||
// activationMethod: 0 = DoubleLeftControlKey, 1 = DoubleRightControlKey, 2 = ShakeMouse, 3 = Shortcut
|
||||
static void MousePointerFocused(const int activationMethod) noexcept;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,12 +18,12 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using MouseWithoutBorders.Core;
|
||||
using Newtonsoft.Json;
|
||||
using StreamJsonRpc;
|
||||
|
||||
#if !MM_HELPER
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
#endif
|
||||
|
||||
using SystemClipboard = System.Windows.Forms.Clipboard;
|
||||
@@ -246,11 +246,11 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
CancellationToken cancellationToken = _serverTaskCancellationSource.Token;
|
||||
|
||||
IpcChannel<ClipboardHelper>.StartIpcServer(ChannelName + "/" + RemoteObjectName, cancellationToken);
|
||||
Common.IpcChannelCreated = true;
|
||||
IpcChannelHelper.IpcChannelCreated = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Common.IpcChannelCreated = false;
|
||||
IpcChannelHelper.IpcChannelCreated = false;
|
||||
Common.ShowToolTip("Error setting up clipboard sharing, clipboard sharing will not work!", 5000, ToolTipIcon.Error);
|
||||
Logger.Log(e);
|
||||
}
|
||||
@@ -405,7 +405,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.ContainsFileDropList), () => { return SystemClipboard.ContainsFileDropList(); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsFileDropList), () => { return SystemClipboard.ContainsFileDropList(); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -427,7 +427,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.ContainsImage), () => { return SystemClipboard.ContainsImage(); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsImage), () => { return SystemClipboard.ContainsImage(); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -449,7 +449,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.ContainsText), () => { return SystemClipboard.ContainsText(); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.ContainsText), () => { return SystemClipboard.ContainsText(); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -471,7 +471,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.GetFileDropList), () => { return SystemClipboard.GetFileDropList(); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetFileDropList), () => { return SystemClipboard.GetFileDropList(); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -493,7 +493,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.GetImage), () => { return SystemClipboard.GetImage(); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetImage), () => { return SystemClipboard.GetImage(); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -515,7 +515,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
|
||||
try
|
||||
{
|
||||
rv = Common.Retry(nameof(SystemClipboard.GetText), () => { return SystemClipboard.GetText(format); }, (log) => Log(log));
|
||||
rv = IpcChannelHelper.Retry(nameof(SystemClipboard.GetText), () => { return SystemClipboard.GetText(format); }, (log) => Log(log));
|
||||
}
|
||||
catch (ExternalException e)
|
||||
{
|
||||
@@ -539,7 +539,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Common.Retry(
|
||||
_ = IpcChannelHelper.Retry(
|
||||
nameof(SystemClipboard.SetImage),
|
||||
() =>
|
||||
{
|
||||
@@ -568,7 +568,7 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Common.Retry(
|
||||
_ = IpcChannelHelper.Retry(
|
||||
nameof(SystemClipboard.SetText),
|
||||
() =>
|
||||
{
|
||||
@@ -600,44 +600,4 @@ WellKnownSidType.AuthenticatedUserSid, null);
|
||||
{
|
||||
internal const int QUIT_CMD = 0x409;
|
||||
}
|
||||
|
||||
internal sealed partial class Common
|
||||
{
|
||||
internal static bool IpcChannelCreated { get; set; }
|
||||
|
||||
internal static T Retry<T>(string name, Func<T> func, Action<string> log, Action preRetry = null)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
T rv = func();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
log($"Trace: {name} has been successful after {count} retry.");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
count++;
|
||||
|
||||
preRetry?.Invoke();
|
||||
|
||||
if (count > 10)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1036,7 +1036,7 @@ internal static class Clipboard
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Common.Retry(
|
||||
_ = IpcChannelHelper.Retry(
|
||||
nameof(SystemClipboard.SetFileDropList),
|
||||
() =>
|
||||
{
|
||||
@@ -1073,7 +1073,7 @@ internal static class Clipboard
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Common.Retry(
|
||||
_ = IpcChannelHelper.Retry(
|
||||
nameof(SystemClipboard.SetImage),
|
||||
() =>
|
||||
{
|
||||
@@ -1104,7 +1104,7 @@ internal static class Clipboard
|
||||
{
|
||||
try
|
||||
{
|
||||
_ = Common.Retry(
|
||||
_ = IpcChannelHelper.Retry(
|
||||
nameof(SystemClipboard.SetText),
|
||||
() =>
|
||||
{
|
||||
|
||||
1654
src/modules/MouseWithoutBorders/App/Core/Common.cs
Normal file
1654
src/modules/MouseWithoutBorders/App/Core/Common.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -295,9 +295,9 @@ internal static class Helper
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Common.IpcChannelCreated)
|
||||
if (!IpcChannelHelper.IpcChannelCreated)
|
||||
{
|
||||
Logger.TelemetryLogTrace($"{nameof(Common.IpcChannelCreated)} = {Common.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
Logger.TelemetryLogTrace($"{nameof(IpcChannelHelper.IpcChannelCreated)} = {IpcChannelHelper.IpcChannelCreated}. {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
53
src/modules/MouseWithoutBorders/App/Core/IpcChannelHelper.cs
Normal file
53
src/modules/MouseWithoutBorders/App/Core/IpcChannelHelper.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
#if !MM_HELPER
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
#endif
|
||||
|
||||
namespace MouseWithoutBorders.Core;
|
||||
|
||||
internal static class IpcChannelHelper
|
||||
{
|
||||
internal static bool IpcChannelCreated { get; set; }
|
||||
|
||||
internal static T Retry<T>(string name, Func<T> func, Action<string> log, Action preRetry = null)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
T rv = func();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
log($"Trace: {name} has been successful after {count} retry.");
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
count++;
|
||||
|
||||
preRetry?.Invoke();
|
||||
|
||||
if (count > 10)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
Application.DoEvents();
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
@@ -198,7 +198,6 @@ internal static class Logger
|
||||
}
|
||||
|
||||
Logger.DumpProgramLogs(sb, level);
|
||||
Logger.DumpOtherLogs(sb, level);
|
||||
Logger.DumpStaticTypes(sb, level);
|
||||
|
||||
log = string.Format(
|
||||
@@ -240,19 +239,16 @@ internal static class Logger
|
||||
_ = Logger.PrivateDump(sb, AllLogs, "[Program logs]\r\n===============\r\n", 0, level, false);
|
||||
}
|
||||
|
||||
internal static void DumpOtherLogs(StringBuilder sb, int level)
|
||||
{
|
||||
_ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, level, false);
|
||||
}
|
||||
|
||||
internal static void DumpStaticTypes(StringBuilder sb, int level)
|
||||
{
|
||||
var staticTypes = new List<Type>
|
||||
{
|
||||
typeof(Clipboard),
|
||||
typeof(Common),
|
||||
typeof(DragDrop),
|
||||
typeof(Encryption),
|
||||
typeof(Event),
|
||||
typeof(IpcChannelHelper),
|
||||
typeof(InitAndCleanup),
|
||||
typeof(Helper),
|
||||
typeof(Launch),
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
public partial class SetupPage2b : SettingsFormPage
|
||||
|
||||
@@ -15,6 +15,8 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
internal partial class FrmAbout : System.Windows.Forms.Form, IDisposable
|
||||
|
||||
@@ -6,6 +6,8 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
public partial class FrmMessage : System.Windows.Forms.Form
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
<Compile Include="..\Class\IClipboardHelper.cs">
|
||||
<Link>IClipboardHelper.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Core\IpcChannelHelper.cs">
|
||||
<Link>IpcChannelHelper.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,9 +1,38 @@
|
||||
[Program logs]
|
||||
===============
|
||||
= System.String[]
|
||||
[Other Logs]
|
||||
[Clipboard]
|
||||
===============
|
||||
Comma = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
Star = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
NullSeparator = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
lastClipboardEventTime = 0
|
||||
clipboardCopiedTime = 0
|
||||
<LastIDWithClipboardData>k__BackingField = NONE
|
||||
<NextClipboardViewer>k__BackingField = 0
|
||||
<IsClipboardDataImage>k__BackingField = False
|
||||
lastClipboardObject =
|
||||
<HasSwitchedMachineSinceLastCopy>k__BackingField = False
|
||||
ClipboardThreadOldLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
BIG_CLIPBOARD_DATA_TIMEOUT = 30000
|
||||
MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
|
||||
MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
|
||||
TEXT_HEADER_SIZE = 12
|
||||
DATA_SIZE = 48
|
||||
TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
|
||||
[Common]
|
||||
===============
|
||||
= MouseWithoutBorders.Common
|
||||
screenWidth = 0
|
||||
screenHeight = 0
|
||||
lastX = 0
|
||||
@@ -46,7 +75,6 @@ avgSendTime = 0
|
||||
maxSendTime = 0
|
||||
totalSendCount = 0
|
||||
totalSendTime = 0
|
||||
<IpcChannelCreated>k__BackingField = False
|
||||
TOGGLE_ICONS_SIZE = 4
|
||||
ICON_ONE = 0
|
||||
ICON_ALL = 1
|
||||
@@ -55,36 +83,6 @@ ICON_BIG_CLIPBOARD = 3
|
||||
ICON_ERROR = 4
|
||||
JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999
|
||||
NETWORK_STREAM_BUF_SIZE = 1048576
|
||||
[Clipboard]
|
||||
===============
|
||||
Comma = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
Star = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
NullSeparator = System.Char[]
|
||||
--System.Char[] = System.Char[]: N/A
|
||||
lastClipboardEventTime = 0
|
||||
clipboardCopiedTime = 0
|
||||
<LastIDWithClipboardData>k__BackingField = NONE
|
||||
<NextClipboardViewer>k__BackingField = 0
|
||||
<IsClipboardDataImage>k__BackingField = False
|
||||
lastClipboardObject =
|
||||
<HasSwitchedMachineSinceLastCopy>k__BackingField = False
|
||||
ClipboardThreadOldLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
BIG_CLIPBOARD_DATA_TIMEOUT = 30000
|
||||
MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1048576
|
||||
MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 104857600
|
||||
TEXT_HEADER_SIZE = 12
|
||||
DATA_SIZE = 48
|
||||
TEXT_TYPE_SEP = {4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}
|
||||
[DragDrop]
|
||||
===============
|
||||
isDragging = False
|
||||
@@ -174,6 +172,9 @@ actualLastPos = {X=0,Y=0}
|
||||
--Empty = {X=0,Y=0}
|
||||
myLastX = 0
|
||||
myLastY = 0
|
||||
[IpcChannelHelper]
|
||||
===============
|
||||
<IpcChannelCreated>k__BackingField = False
|
||||
[InitAndCleanup]
|
||||
===============
|
||||
initDone = False
|
||||
@@ -440,6 +441,7 @@ WM_LBUTTONDBLCLK = 515
|
||||
WM_RBUTTONDBLCLK = 518
|
||||
WM_MBUTTONDBLCLK = 521
|
||||
WM_MOUSEWHEEL = 522
|
||||
WM_MOUSEHWHEEL = 526
|
||||
WM_KEYDOWN = 256
|
||||
WM_KEYUP = 257
|
||||
WM_SYSKEYDOWN = 260
|
||||
|
||||
@@ -117,7 +117,6 @@ public static class LoggerTests
|
||||
// copied from DumpObjects in Logger.cs
|
||||
var sb = new StringBuilder(1000000);
|
||||
Logger.DumpProgramLogs(sb, settingsDumpObjectsLevel);
|
||||
Logger.DumpOtherLogs(sb, settingsDumpObjectsLevel);
|
||||
Logger.DumpStaticTypes(sb, settingsDumpObjectsLevel);
|
||||
var actual = sb.ToString();
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
<controls:SettingsCard HorizontalContentAlignment="Left" ContentAlignment="Left">
|
||||
<StackPanel Margin="-12,0,0,0" Orientation="Vertical">
|
||||
<HyperlinkButton x:Uid="Settings_GeneralPage_About_GithubLink_Hyperlink" NavigateUri="https://go.microsoft.com/fwlink/?linkid=2310837" />
|
||||
<HyperlinkButton x:Uid="Settings_GeneralPage_About_SDKDocs_Hyperlink" NavigateUri="https://go.microsoft.com/fwlink/?linkid=2310639" />
|
||||
<HyperlinkButton x:Uid="Settings_GeneralPage_About_SDKDocs_Hyperlink" NavigateUri="https://aka.ms/cmdpalextensions-devdocs" />
|
||||
</StackPanel>
|
||||
</controls:SettingsCard>
|
||||
</controls:SettingsExpander.Items>
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
@@ -24,15 +25,15 @@ internal sealed partial class FancyZonesMonitorListItem : ListItem
|
||||
|
||||
var pickerPage = new FancyZonesMonitorLayoutPickerPage(monitor)
|
||||
{
|
||||
Name = "Set active layout",
|
||||
Name = Resources.FancyZones_SetActiveLayout,
|
||||
};
|
||||
|
||||
MoreCommands =
|
||||
[
|
||||
new CommandContextItem(pickerPage)
|
||||
{
|
||||
Title = "Set active layout",
|
||||
Subtitle = "Pick a layout for this monitor",
|
||||
Title = Resources.FancyZones_SetActiveLayout,
|
||||
Subtitle = Resources.FancyZones_PickLayoutForMonitor,
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -42,14 +43,14 @@ internal sealed partial class FancyZonesMonitorListItem : ListItem
|
||||
var currentVirtualDesktop = FancyZonesVirtualDesktop.GetCurrentVirtualDesktopIdString();
|
||||
var tags = new List<IDetailsElement>
|
||||
{
|
||||
DetailTag("Monitor", monitor.Data.Monitor),
|
||||
DetailTag("Instance", monitor.Data.MonitorInstanceId),
|
||||
DetailTag("Serial", monitor.Data.MonitorSerialNumber),
|
||||
DetailTag("Number", monitor.Data.MonitorNumber.ToString(CultureInfo.InvariantCulture)),
|
||||
DetailTag("Virtual desktop", currentVirtualDesktop),
|
||||
DetailTag("Work area", $"{monitor.Data.LeftCoordinate},{monitor.Data.TopCoordinate} {monitor.Data.WorkAreaWidth}\u00D7{monitor.Data.WorkAreaHeight}"),
|
||||
DetailTag("Resolution", $"{monitor.Data.MonitorWidth}\u00D7{monitor.Data.MonitorHeight}"),
|
||||
DetailTag("DPI", monitor.Data.Dpi.ToString(CultureInfo.InvariantCulture)),
|
||||
DetailTag(Resources.FancyZones_Monitor, monitor.Data.Monitor),
|
||||
DetailTag(Resources.FancyZones_Instance, monitor.Data.MonitorInstanceId),
|
||||
DetailTag(Resources.FancyZones_Serial, monitor.Data.MonitorSerialNumber),
|
||||
DetailTag(Resources.FancyZones_Number, monitor.Data.MonitorNumber.ToString(CultureInfo.InvariantCulture)),
|
||||
DetailTag(Resources.FancyZones_VirtualDesktop, currentVirtualDesktop),
|
||||
DetailTag(Resources.FancyZones_WorkArea, $"{monitor.Data.LeftCoordinate},{monitor.Data.TopCoordinate} {monitor.Data.WorkAreaWidth}\u00D7{monitor.Data.WorkAreaHeight}"),
|
||||
DetailTag(Resources.FancyZones_Resolution, $"{monitor.Data.MonitorWidth}\u00D7{monitor.Data.MonitorHeight}"),
|
||||
DetailTag(Resources.FancyZones_DPI, monitor.Data.Dpi.ToString(CultureInfo.InvariantCulture)),
|
||||
};
|
||||
|
||||
return new Details
|
||||
@@ -68,7 +69,7 @@ internal sealed partial class FancyZonesMonitorListItem : ListItem
|
||||
Key = key,
|
||||
Data = new DetailsTags
|
||||
{
|
||||
Tags = [new Tag(string.IsNullOrWhiteSpace(value) ? "n/a" : value)],
|
||||
Tags = [new Tag(string.IsNullOrWhiteSpace(value) ? Resources.Common_NotAvailable : value)],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,15 +5,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using WorkspacesCsharpLibrary.Data;
|
||||
|
||||
namespace PowerToysExtension.Commands;
|
||||
|
||||
internal sealed partial class WorkspaceListItem : ListItem
|
||||
{
|
||||
private static readonly CompositeFormat ApplicationsFormat = CompositeFormat.Parse(Resources.Workspaces_Applications_Format);
|
||||
private static readonly CompositeFormat LastLaunchedFormat = CompositeFormat.Parse(Resources.Workspaces_LastLaunched_Format);
|
||||
private static readonly CompositeFormat ApplicationsCountFormat = CompositeFormat.Parse(Resources.Workspaces_ApplicationsCount_Format);
|
||||
private static readonly CompositeFormat MinAgoFormat = CompositeFormat.Parse(Resources.Workspaces_MinAgo_Format);
|
||||
private static readonly CompositeFormat HrAgoFormat = CompositeFormat.Parse(Resources.Workspaces_HrAgo_Format);
|
||||
private static readonly CompositeFormat DaysAgoFormat = CompositeFormat.Parse(Resources.Workspaces_DaysAgo_Format);
|
||||
|
||||
public WorkspaceListItem(ProjectWrapper workspace, IconInfo icon)
|
||||
: base(new LaunchWorkspaceCommand(workspace.Id))
|
||||
{
|
||||
@@ -28,13 +37,13 @@ internal sealed partial class WorkspaceListItem : ListItem
|
||||
var appCount = workspace.Applications?.Count ?? 0;
|
||||
var appsText = appCount switch
|
||||
{
|
||||
0 => "No applications",
|
||||
_ => string.Format(CultureInfo.CurrentCulture, "{0} applications", appCount),
|
||||
0 => Resources.Workspaces_NoApplications,
|
||||
_ => string.Format(CultureInfo.CurrentCulture, ApplicationsFormat, appCount),
|
||||
};
|
||||
|
||||
var lastLaunched = workspace.LastLaunchedTime > 0
|
||||
? $"Last launched {FormatRelativeTime(workspace.LastLaunchedTime)}"
|
||||
: "Never launched";
|
||||
? string.Format(CultureInfo.CurrentCulture, LastLaunchedFormat, FormatRelativeTime(workspace.LastLaunchedTime))
|
||||
: Resources.Workspaces_NeverLaunched;
|
||||
|
||||
return $"{appsText} \u2022 {lastLaunched}";
|
||||
}
|
||||
@@ -44,15 +53,15 @@ internal sealed partial class WorkspaceListItem : ListItem
|
||||
var appCount = workspace.Applications?.Count ?? 0;
|
||||
var body = appCount switch
|
||||
{
|
||||
0 => "No applications in this workspace",
|
||||
1 => "1 application",
|
||||
_ => $"{appCount} applications",
|
||||
0 => Resources.Workspaces_NoApplicationsInWorkspace,
|
||||
1 => Resources.Workspaces_OneApplication,
|
||||
_ => string.Format(CultureInfo.CurrentCulture, ApplicationsCountFormat, appCount),
|
||||
};
|
||||
|
||||
return new Details
|
||||
{
|
||||
HeroImage = icon,
|
||||
Title = workspace.Name ?? "Workspace",
|
||||
Title = workspace.Name ?? Resources.Workspaces_Workspace,
|
||||
Body = body,
|
||||
Metadata = BuildAppMetadata(workspace),
|
||||
};
|
||||
@@ -68,7 +77,7 @@ internal sealed partial class WorkspaceListItem : ListItem
|
||||
var elements = new List<IDetailsElement>();
|
||||
foreach (var app in workspace.Applications)
|
||||
{
|
||||
var appName = string.IsNullOrWhiteSpace(app.Application) ? "App" : app.Application;
|
||||
var appName = string.IsNullOrWhiteSpace(app.Application) ? Resources.Workspaces_App : app.Application;
|
||||
var title = string.IsNullOrWhiteSpace(app.Title) ? appName : app.Title;
|
||||
|
||||
var tags = new List<ITag>();
|
||||
@@ -99,19 +108,19 @@ internal sealed partial class WorkspaceListItem : ListItem
|
||||
|
||||
if (delta.TotalMinutes < 1)
|
||||
{
|
||||
return "just now";
|
||||
return Resources.Workspaces_JustNow;
|
||||
}
|
||||
|
||||
if (delta.TotalMinutes < 60)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0} min ago", (int)delta.TotalMinutes);
|
||||
return string.Format(CultureInfo.CurrentCulture, MinAgoFormat, (int)delta.TotalMinutes);
|
||||
}
|
||||
|
||||
if (delta.TotalHours < 24)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0} hr ago", (int)delta.TotalHours);
|
||||
return string.Format(CultureInfo.CurrentCulture, HrAgoFormat, (int)delta.TotalHours);
|
||||
}
|
||||
|
||||
return string.Format(CultureInfo.CurrentCulture, "{0} days ago", (int)delta.TotalDays);
|
||||
return string.Format(CultureInfo.CurrentCulture, DaysAgoFormat, (int)delta.TotalDays);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
using FancyZonesEditorCommon.Data;
|
||||
using FancyZonesEditorCommon.Utils;
|
||||
using ManagedCommon;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
using FZPaths = FancyZonesEditorCommon.Data.FancyZonesPaths;
|
||||
|
||||
@@ -20,6 +23,15 @@ internal static class FancyZonesDataService
|
||||
{
|
||||
private const string ZeroUuid = "{00000000-0000-0000-0000-000000000000}";
|
||||
|
||||
private static readonly CompositeFormat ReadMonitorDataFailedFormat = CompositeFormat.Parse(Resources.FancyZones_ReadMonitorDataFailed_Format);
|
||||
private static readonly CompositeFormat WriteAppliedLayoutsFailedFormat = CompositeFormat.Parse(Resources.FancyZones_WriteAppliedLayoutsFailed_Format);
|
||||
private static readonly CompositeFormat LayoutAppliedNotifyFailedFormat = CompositeFormat.Parse(Resources.FancyZones_LayoutAppliedNotifyFailed_Format);
|
||||
private static readonly CompositeFormat TemplateFormat = CompositeFormat.Parse(Resources.FancyZones_Template_Format);
|
||||
private static readonly CompositeFormat ZonesFormat = CompositeFormat.Parse(Resources.FancyZones_Zones_Format);
|
||||
private static readonly CompositeFormat CustomGridZonesFormat = CompositeFormat.Parse(Resources.FancyZones_CustomGrid_Zones_Format);
|
||||
private static readonly CompositeFormat CustomCanvasZonesFormat = CompositeFormat.Parse(Resources.FancyZones_CustomCanvas_Zones_Format);
|
||||
private static readonly CompositeFormat CustomZonesFormat = CompositeFormat.Parse(Resources.FancyZones_Custom_Zones_Format);
|
||||
|
||||
public static bool TryGetMonitors(out IReadOnlyList<FancyZonesMonitorDescriptor> monitors, out string error)
|
||||
{
|
||||
monitors = Array.Empty<FancyZonesMonitorDescriptor>();
|
||||
@@ -31,7 +43,7 @@ internal static class FancyZonesDataService
|
||||
{
|
||||
if (!File.Exists(FZPaths.EditorParameters))
|
||||
{
|
||||
error = "FancyZones monitor data not found. Open FancyZones Editor once to initialize.";
|
||||
error = Resources.FancyZones_MonitorDataNotFound;
|
||||
Logger.LogWarning($"TryGetMonitors: File not found. Path={FZPaths.EditorParameters}");
|
||||
return false;
|
||||
}
|
||||
@@ -43,7 +55,7 @@ internal static class FancyZonesDataService
|
||||
var editorMonitors = editorParams.Monitors;
|
||||
if (editorMonitors is null || editorMonitors.Count == 0)
|
||||
{
|
||||
error = "No FancyZones monitors found.";
|
||||
error = Resources.FancyZones_NoFancyZonesMonitorsFound;
|
||||
Logger.LogWarning($"TryGetMonitors: No monitors in file.");
|
||||
return false;
|
||||
}
|
||||
@@ -56,7 +68,7 @@ internal static class FancyZonesDataService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = $"Failed to read FancyZones monitor data: {ex.Message}";
|
||||
error = string.Format(CultureInfo.CurrentCulture, ReadMonitorDataFailedFormat, ex.Message);
|
||||
Logger.LogError($"TryGetMonitors: Exception. Message={ex.Message} Stack={ex.StackTrace}");
|
||||
return false;
|
||||
}
|
||||
@@ -204,7 +216,7 @@ internal static class FancyZonesDataService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (false, $"Failed to write applied layouts: {ex.Message}");
|
||||
return (false, string.Format(CultureInfo.CurrentCulture, WriteAppliedLayoutsFailedFormat, ex.Message));
|
||||
}
|
||||
|
||||
try
|
||||
@@ -213,10 +225,10 @@ internal static class FancyZonesDataService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return (true, $"Layout applied, but FancyZones could not be notified: {ex.Message}");
|
||||
return (true, string.Format(CultureInfo.CurrentCulture, LayoutAppliedNotifyFailedFormat, ex.Message));
|
||||
}
|
||||
|
||||
return (true, "Layout applied.");
|
||||
return (true, Resources.FancyZones_LayoutApplied);
|
||||
}
|
||||
|
||||
private static AppliedLayouts.AppliedLayoutWrapper? FindAppliedLayoutEntry(AppliedLayouts.AppliedLayoutsListWrapper file, EditorParameters.NativeMonitorDataWrapper monitor, string virtualDesktopId)
|
||||
@@ -293,8 +305,8 @@ internal static class FancyZonesDataService
|
||||
var zoneCount = type.Equals("blank", StringComparison.OrdinalIgnoreCase)
|
||||
? 0
|
||||
: template.ZoneCount > 0 ? template.ZoneCount : 3;
|
||||
var title = $"Template: {type}";
|
||||
var subtitle = $"{zoneCount} zones";
|
||||
var title = string.Format(CultureInfo.CurrentCulture, TemplateFormat, type);
|
||||
var subtitle = string.Format(CultureInfo.CurrentCulture, ZonesFormat, zoneCount);
|
||||
|
||||
yield return new FancyZonesLayoutDescriptor
|
||||
{
|
||||
@@ -357,9 +369,9 @@ internal static class FancyZonesDataService
|
||||
var title = custom.Name.Trim();
|
||||
var subtitle = customType switch
|
||||
{
|
||||
"grid" => $"Custom grid \u2022 {applied.ZoneCount} zones",
|
||||
"canvas" => $"Custom canvas \u2022 {applied.ZoneCount} zones",
|
||||
_ => $"Custom \u2022 {applied.ZoneCount} zones",
|
||||
"grid" => string.Format(CultureInfo.CurrentCulture, CustomGridZonesFormat, applied.ZoneCount),
|
||||
"canvas" => string.Format(CultureInfo.CurrentCulture, CustomCanvasZonesFormat, applied.ZoneCount),
|
||||
_ => string.Format(CultureInfo.CurrentCulture, CustomZonesFormat, applied.ZoneCount),
|
||||
};
|
||||
|
||||
yield return new FancyZonesLayoutDescriptor
|
||||
|
||||
@@ -61,6 +61,21 @@
|
||||
<ProjectReference Include="..\..\..\Workspaces\Workspaces.ModuleServices\Workspaces.ModuleServices.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Always build/publish AOT so the extension ships as native code -->
|
||||
<SelfContained>true</SelfContained>
|
||||
|
||||
@@ -7,6 +7,7 @@ using Common.UI;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
|
||||
@@ -22,8 +23,8 @@ internal sealed class AdvancedPasteModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new OpenAdvancedPasteCommand())
|
||||
{
|
||||
Title = "Open Advanced Paste",
|
||||
Subtitle = "Launch the Advanced Paste UI",
|
||||
Title = Resources.AdvancedPaste_Open_Title,
|
||||
Subtitle = Resources.AdvancedPaste_Open_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -31,7 +32,7 @@ internal sealed class AdvancedPasteModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Advanced Paste settings",
|
||||
Subtitle = Resources.AdvancedPaste_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class AlwaysOnTopModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.AlwaysOnTop, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Always On Top settings",
|
||||
Subtitle = Resources.AlwaysOnTop_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Pages;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
|
||||
@@ -26,7 +27,7 @@ internal sealed class AwakeModuleCommandProvider : ModuleCommandProvider
|
||||
items.Add(new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Awake settings",
|
||||
Subtitle = Resources.Awake_Settings_Subtitle,
|
||||
Icon = moduleIcon,
|
||||
});
|
||||
|
||||
@@ -49,40 +50,40 @@ internal sealed class AwakeModuleCommandProvider : ModuleCommandProvider
|
||||
|
||||
statusItem = new ListItem(new CommandItem(refreshCommand))
|
||||
{
|
||||
Title = "Awake: Current status",
|
||||
Title = Resources.Awake_Status_Title,
|
||||
Subtitle = AwakeStatusService.GetStatusSubtitle(),
|
||||
Icon = icon,
|
||||
};
|
||||
items.Add(statusItem);
|
||||
|
||||
items.Add(new ListItem(new StartAwakeCommand("Awake: Keep awake indefinitely", () => AwakeService.Instance.SetIndefiniteAsync(), "Awake set to indefinite", refreshStatus))
|
||||
items.Add(new ListItem(new StartAwakeCommand(Resources.Awake_KeepIndefinite_Title, () => AwakeService.Instance.SetIndefiniteAsync(), Resources.Awake_SetIndefinite_Toast, refreshStatus))
|
||||
{
|
||||
Title = "Awake: Keep awake indefinitely",
|
||||
Subtitle = "Run Awake in indefinite mode",
|
||||
Title = Resources.Awake_KeepIndefinite_Title,
|
||||
Subtitle = Resources.Awake_KeepIndefinite_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
items.Add(new ListItem(new StartAwakeCommand("Awake: Keep awake for 30 minutes", () => AwakeService.Instance.SetTimedAsync(30), "Awake set for 30 minutes", refreshStatus))
|
||||
items.Add(new ListItem(new StartAwakeCommand(Resources.Awake_Keep30Min_Title, () => AwakeService.Instance.SetTimedAsync(30), Resources.Awake_Set30Min_Toast, refreshStatus))
|
||||
{
|
||||
Title = "Awake: Keep awake for 30 minutes",
|
||||
Subtitle = "Run Awake timed for 30 minutes",
|
||||
Title = Resources.Awake_Keep30Min_Title,
|
||||
Subtitle = Resources.Awake_Keep30Min_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
items.Add(new ListItem(new StartAwakeCommand("Awake: Keep awake for 1 hour", () => AwakeService.Instance.SetTimedAsync(60), "Awake set for 1 hour", refreshStatus))
|
||||
items.Add(new ListItem(new StartAwakeCommand(Resources.Awake_Keep1Hour_Title, () => AwakeService.Instance.SetTimedAsync(60), Resources.Awake_Set1Hour_Toast, refreshStatus))
|
||||
{
|
||||
Title = "Awake: Keep awake for 1 hour",
|
||||
Subtitle = "Run Awake timed for 1 hour",
|
||||
Title = Resources.Awake_Keep1Hour_Title,
|
||||
Subtitle = Resources.Awake_Keep1Hour_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
items.Add(new ListItem(new StartAwakeCommand("Awake: Keep awake for 2 hours", () => AwakeService.Instance.SetTimedAsync(120), "Awake set for 2 hours", refreshStatus))
|
||||
items.Add(new ListItem(new StartAwakeCommand(Resources.Awake_Keep2Hours_Title, () => AwakeService.Instance.SetTimedAsync(120), Resources.Awake_Set2Hours_Toast, refreshStatus))
|
||||
{
|
||||
Title = "Awake: Keep awake for 2 hours",
|
||||
Subtitle = "Run Awake timed for 2 hours",
|
||||
Title = Resources.Awake_Keep2Hours_Title,
|
||||
Subtitle = Resources.Awake_Keep2Hours_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
items.Add(new ListItem(new StopAwakeCommand(refreshStatus))
|
||||
{
|
||||
Title = "Awake: Turn off",
|
||||
Subtitle = "Switch Awake back to Off",
|
||||
Title = Resources.Awake_TurnOff_Title,
|
||||
Subtitle = Resources.Awake_TurnOff_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Pages;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
|
||||
@@ -24,7 +25,7 @@ internal sealed class ColorPickerModuleCommandProvider : ModuleCommandProvider
|
||||
commands.Add(new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Color Picker settings",
|
||||
Subtitle = Resources.ColorPicker_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
@@ -36,15 +37,15 @@ internal sealed class ColorPickerModuleCommandProvider : ModuleCommandProvider
|
||||
// Direct entries in the module list.
|
||||
commands.Add(new ListItem(new OpenColorPickerCommand())
|
||||
{
|
||||
Title = "Open Color Picker",
|
||||
Subtitle = "Start a color pick session",
|
||||
Title = Resources.ColorPicker_Open_Title,
|
||||
Subtitle = Resources.ColorPicker_Open_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
commands.Add(new ListItem(new CommandItem(new ColorPickerSavedColorsPage()))
|
||||
{
|
||||
Title = "Saved colors",
|
||||
Subtitle = "Browse and copy saved colors",
|
||||
Title = Resources.ColorPicker_SavedColors_Title,
|
||||
Subtitle = Resources.ColorPicker_SavedColors_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class CommandNotFoundModuleCommandProvider : ModuleCommandProvid
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.CmdNotFound, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Command Not Found settings",
|
||||
Subtitle = Resources.CommandNotFound_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,15 +23,15 @@ internal sealed class CropAndLockModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new CropAndLockReparentCommand())
|
||||
{
|
||||
Title = "Crop and Lock (Reparent)",
|
||||
Subtitle = "Create a cropped reparented window",
|
||||
Title = Resources.CropAndLock_Reparent_Title,
|
||||
Subtitle = Resources.CropAndLock_Reparent_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
|
||||
yield return new ListItem(new CropAndLockThumbnailCommand())
|
||||
{
|
||||
Title = "Crop and Lock (Thumbnail)",
|
||||
Subtitle = "Create a cropped thumbnail window",
|
||||
Title = Resources.CropAndLock_Thumbnail_Title,
|
||||
Subtitle = Resources.CropAndLock_Thumbnail_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -38,7 +39,7 @@ internal sealed class CropAndLockModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Crop and Lock settings",
|
||||
Subtitle = Resources.CropAndLock_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,15 +23,15 @@ internal sealed class EnvironmentVariablesModuleCommandProvider : ModuleCommandP
|
||||
{
|
||||
yield return new ListItem(new OpenEnvironmentVariablesCommand())
|
||||
{
|
||||
Title = "Open Environment Variables",
|
||||
Subtitle = "Launch Environment Variables editor",
|
||||
Title = Resources.EnvironmentVariables_Open_Title,
|
||||
Subtitle = Resources.EnvironmentVariables_Open_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
|
||||
yield return new ListItem(new OpenEnvironmentVariablesAdminCommand())
|
||||
{
|
||||
Title = "Open Environment Variables (Admin)",
|
||||
Subtitle = "Launch Environment Variables editor as admin",
|
||||
Title = Resources.EnvironmentVariables_OpenAdmin_Title,
|
||||
Subtitle = Resources.EnvironmentVariables_OpenAdmin_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -38,7 +39,7 @@ internal sealed class EnvironmentVariablesModuleCommandProvider : ModuleCommandP
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Environment Variables settings",
|
||||
Subtitle = Resources.EnvironmentVariables_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Pages;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -23,22 +24,22 @@ internal sealed class FancyZonesModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new CommandItem(new FancyZonesLayoutsPage()))
|
||||
{
|
||||
Title = "FancyZones: Layouts",
|
||||
Subtitle = "Apply a layout to all monitors or a specific monitor",
|
||||
Title = Resources.FancyZones_Layouts_Title,
|
||||
Subtitle = Resources.FancyZones_Layouts_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
|
||||
yield return new ListItem(new CommandItem(new FancyZonesMonitorsPage()))
|
||||
{
|
||||
Title = "FancyZones: Monitors",
|
||||
Subtitle = "Identify monitors and apply layouts",
|
||||
Title = Resources.FancyZones_Monitors_Title,
|
||||
Subtitle = Resources.FancyZones_Monitors_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
|
||||
yield return new ListItem(new OpenFancyZonesEditorCommand())
|
||||
{
|
||||
Title = "Open FancyZones Editor",
|
||||
Subtitle = "Launch layout editor",
|
||||
Title = Resources.FancyZones_OpenEditor_Title,
|
||||
Subtitle = Resources.FancyZones_OpenEditor_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -46,7 +47,7 @@ internal sealed class FancyZonesModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open FancyZones settings",
|
||||
Subtitle = Resources.FancyZones_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class FileExplorerAddonsModuleCommandProvider : ModuleCommandPro
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.FileExplorer, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open File Explorer add-ons settings",
|
||||
Subtitle = Resources.FileExplorerAddons_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class FileLocksmithModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.FileLocksmith, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open File Locksmith settings",
|
||||
Subtitle = Resources.FileLocksmith_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,15 +23,15 @@ internal sealed class HostsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new OpenHostsEditorCommand())
|
||||
{
|
||||
Title = "Open Hosts File Editor",
|
||||
Subtitle = "Launch Hosts File Editor",
|
||||
Title = Resources.Hosts_Open_Title,
|
||||
Subtitle = Resources.Hosts_Open_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
|
||||
yield return new ListItem(new OpenHostsEditorAdminCommand())
|
||||
{
|
||||
Title = "Open Hosts File Editor (Admin)",
|
||||
Subtitle = "Launch Hosts File Editor as admin",
|
||||
Title = Resources.Hosts_OpenAdmin_Title,
|
||||
Subtitle = Resources.Hosts_OpenAdmin_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -38,7 +39,7 @@ internal sealed class HostsModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Hosts File Editor settings",
|
||||
Subtitle = Resources.Hosts_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class ImageResizerModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.ImageResizer, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Image Resizer settings",
|
||||
Subtitle = Resources.ImageResizer_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class KeyboardManagerModuleCommandProvider : ModuleCommandProvid
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.KBM, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Keyboard Manager settings",
|
||||
Subtitle = Resources.KeyboardManager_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -24,8 +25,8 @@ internal sealed class LightSwitchModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
items.Add(new ListItem(new ToggleLightSwitchCommand())
|
||||
{
|
||||
Title = "Toggle Light Switch",
|
||||
Subtitle = "Toggle system/apps theme immediately",
|
||||
Title = Resources.LightSwitch_Toggle_Title,
|
||||
Subtitle = Resources.LightSwitch_Toggle_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
}
|
||||
@@ -33,7 +34,7 @@ internal sealed class LightSwitchModuleCommandProvider : ModuleCommandProvider
|
||||
items.Add(new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Light Switch settings",
|
||||
Subtitle = Resources.LightSwitch_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,8 +23,8 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleFindMyMouseCommand())
|
||||
{
|
||||
Title = "Trigger Find My Mouse",
|
||||
Subtitle = "Focus the mouse pointer",
|
||||
Title = Resources.MouseUtils_FindMyMouse_Title,
|
||||
Subtitle = Resources.MouseUtils_FindMyMouse_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -32,8 +33,8 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleMouseHighlighterCommand())
|
||||
{
|
||||
Title = "Toggle Mouse Highlighter",
|
||||
Subtitle = "Highlight mouse clicks",
|
||||
Title = Resources.MouseUtils_Highlighter_Title,
|
||||
Subtitle = Resources.MouseUtils_Highlighter_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -42,8 +43,8 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleMouseCrosshairsCommand())
|
||||
{
|
||||
Title = "Toggle Mouse Crosshairs",
|
||||
Subtitle = "Enable or disable pointer crosshairs",
|
||||
Title = Resources.MouseUtils_Crosshairs_Title,
|
||||
Subtitle = Resources.MouseUtils_Crosshairs_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -52,8 +53,8 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleCursorWrapCommand())
|
||||
{
|
||||
Title = "Toggle Cursor Wrap",
|
||||
Subtitle = "Wrap the cursor across monitor edges",
|
||||
Title = Resources.MouseUtils_CursorWrap_Title,
|
||||
Subtitle = Resources.MouseUtils_CursorWrap_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -62,8 +63,8 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ShowMouseJumpPreviewCommand())
|
||||
{
|
||||
Title = "Show Mouse Jump Preview",
|
||||
Subtitle = "Jump the pointer to a target",
|
||||
Title = Resources.MouseUtils_MouseJump_Title,
|
||||
Subtitle = Resources.MouseUtils_MouseJump_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -71,7 +72,7 @@ internal sealed class MouseUtilsModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Mouse Utilities settings",
|
||||
Subtitle = Resources.MouseUtils_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class MouseWithoutBordersModuleCommandProvider : ModuleCommandPr
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.MouseWithoutBorders, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Mouse Without Borders settings",
|
||||
Subtitle = Resources.MouseWithoutBorders_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class NewPlusModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.NewPlus, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open New+ settings",
|
||||
Subtitle = Resources.NewPlus_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class PeekModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.Peek, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Peek settings",
|
||||
Subtitle = Resources.Peek_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class PowerRenameModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.PowerRename, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open PowerRename settings",
|
||||
Subtitle = Resources.PowerRename_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class PowerToysRunModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.PowerLauncher, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open PowerToys Run settings",
|
||||
Subtitle = Resources.PowerToysRun_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -20,7 +21,7 @@ internal sealed class QuickAccentModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(SettingsWindow.PowerAccent, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Quick Accent settings",
|
||||
Subtitle = Resources.QuickAccent_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,8 +23,8 @@ internal sealed class RegistryPreviewModuleCommandProvider : ModuleCommandProvid
|
||||
{
|
||||
yield return new ListItem(new OpenRegistryPreviewCommand())
|
||||
{
|
||||
Title = "Open Registry Preview",
|
||||
Subtitle = "Launch Registry Preview",
|
||||
Title = Resources.RegistryPreview_Open_Title,
|
||||
Subtitle = Resources.RegistryPreview_Open_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -31,7 +32,7 @@ internal sealed class RegistryPreviewModuleCommandProvider : ModuleCommandProvid
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Registry Preview settings",
|
||||
Subtitle = Resources.RegistryPreview_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,8 +23,8 @@ internal sealed class ScreenRulerModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleScreenRulerCommand())
|
||||
{
|
||||
Title = "Toggle Screen Ruler",
|
||||
Subtitle = "Start or close Screen Ruler",
|
||||
Title = Resources.ScreenRuler_Toggle_Title,
|
||||
Subtitle = Resources.ScreenRuler_Toggle_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -31,7 +32,7 @@ internal sealed class ScreenRulerModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Screen Ruler settings",
|
||||
Subtitle = Resources.ScreenRuler_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,8 +23,8 @@ internal sealed class ShortcutGuideModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleShortcutGuideCommand())
|
||||
{
|
||||
Title = "Toggle Shortcut Guide",
|
||||
Subtitle = "Show or hide Shortcut Guide",
|
||||
Title = Resources.ShortcutGuide_Toggle_Title,
|
||||
Subtitle = Resources.ShortcutGuide_Toggle_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -31,7 +32,7 @@ internal sealed class ShortcutGuideModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Shortcut Guide settings",
|
||||
Subtitle = Resources.ShortcutGuide_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -22,8 +23,8 @@ internal sealed class TextExtractorModuleCommandProvider : ModuleCommandProvider
|
||||
{
|
||||
yield return new ListItem(new ToggleTextExtractorCommand())
|
||||
{
|
||||
Title = "Toggle Text Extractor",
|
||||
Subtitle = "Start or close Text Extractor",
|
||||
Title = Resources.TextExtractor_Toggle_Title,
|
||||
Subtitle = Resources.TextExtractor_Toggle_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -31,7 +32,7 @@ internal sealed class TextExtractorModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Text Extractor settings",
|
||||
Subtitle = Resources.TextExtractor_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using Common.UI;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using Workspaces.ModuleServices;
|
||||
using WorkspacesCsharpLibrary.Data;
|
||||
|
||||
@@ -25,7 +26,7 @@ internal sealed class WorkspacesModuleCommandProvider : ModuleCommandProvider
|
||||
items.Add(new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open Workspaces settings",
|
||||
Subtitle = Resources.Workspaces_Settings_Subtitle,
|
||||
Icon = moduleIcon,
|
||||
});
|
||||
|
||||
@@ -37,8 +38,8 @@ internal sealed class WorkspacesModuleCommandProvider : ModuleCommandProvider
|
||||
// Settings entry plus common actions.
|
||||
items.Add(new ListItem(new OpenWorkspaceEditorCommand())
|
||||
{
|
||||
Title = "Workspaces: Open editor",
|
||||
Subtitle = "Create or edit workspaces",
|
||||
Title = Resources.Workspaces_OpenEditor_Title,
|
||||
Subtitle = Resources.Workspaces_OpenEditor_Subtitle,
|
||||
Icon = icon,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
using static Common.UI.SettingsDeepLink;
|
||||
|
||||
namespace PowerToysExtension.Modules;
|
||||
@@ -21,40 +22,40 @@ internal sealed class ZoomItModuleCommandProvider : ModuleCommandProvider
|
||||
if (ModuleEnablementService.IsModuleEnabled(module))
|
||||
{
|
||||
// Action commands via ZoomIt IPC
|
||||
yield return new ListItem(new ZoomItActionCommand("zoom", "ZoomIt: Zoom"))
|
||||
yield return new ListItem(new ZoomItActionCommand("zoom", Resources.ZoomIt_Zoom_Title))
|
||||
{
|
||||
Title = "ZoomIt: Zoom",
|
||||
Subtitle = "Enter zoom mode",
|
||||
Title = Resources.ZoomIt_Zoom_Title,
|
||||
Subtitle = Resources.ZoomIt_Zoom_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
yield return new ListItem(new ZoomItActionCommand("draw", "ZoomIt: Draw"))
|
||||
yield return new ListItem(new ZoomItActionCommand("draw", Resources.ZoomIt_Draw_Title))
|
||||
{
|
||||
Title = "ZoomIt: Draw",
|
||||
Subtitle = "Enter drawing mode",
|
||||
Title = Resources.ZoomIt_Draw_Title,
|
||||
Subtitle = Resources.ZoomIt_Draw_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
yield return new ListItem(new ZoomItActionCommand("break", "ZoomIt: Break"))
|
||||
yield return new ListItem(new ZoomItActionCommand("break", Resources.ZoomIt_Break_Title))
|
||||
{
|
||||
Title = "ZoomIt: Break",
|
||||
Subtitle = "Enter break timer",
|
||||
Title = Resources.ZoomIt_Break_Title,
|
||||
Subtitle = Resources.ZoomIt_Break_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
yield return new ListItem(new ZoomItActionCommand("liveZoom", "ZoomIt: Live Zoom"))
|
||||
yield return new ListItem(new ZoomItActionCommand("liveZoom", Resources.ZoomIt_LiveZoom_Title))
|
||||
{
|
||||
Title = "ZoomIt: Live Zoom",
|
||||
Subtitle = "Toggle live zoom",
|
||||
Title = Resources.ZoomIt_LiveZoom_Title,
|
||||
Subtitle = Resources.ZoomIt_LiveZoom_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
yield return new ListItem(new ZoomItActionCommand("snip", "ZoomIt: Snip"))
|
||||
yield return new ListItem(new ZoomItActionCommand("snip", Resources.ZoomIt_Snip_Title))
|
||||
{
|
||||
Title = "ZoomIt: Snip",
|
||||
Subtitle = "Enter snip mode",
|
||||
Title = Resources.ZoomIt_Snip_Title,
|
||||
Subtitle = Resources.ZoomIt_Snip_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
yield return new ListItem(new ZoomItActionCommand("record", "ZoomIt: Record"))
|
||||
yield return new ListItem(new ZoomItActionCommand("record", Resources.ZoomIt_Record_Title))
|
||||
{
|
||||
Title = "ZoomIt: Record",
|
||||
Subtitle = "Start recording",
|
||||
Title = Resources.ZoomIt_Record_Title,
|
||||
Subtitle = Resources.ZoomIt_Record_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
@@ -62,7 +63,7 @@ internal sealed class ZoomItModuleCommandProvider : ModuleCommandProvider
|
||||
yield return new ListItem(new OpenInSettingsCommand(module, title))
|
||||
{
|
||||
Title = title,
|
||||
Subtitle = "Open ZoomIt settings",
|
||||
Subtitle = Resources.ZoomIt_Settings_Subtitle,
|
||||
Icon = icon,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using ColorPicker.ModuleServices;
|
||||
@@ -10,24 +11,27 @@ using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
internal sealed partial class ColorPickerSavedColorsPage : DynamicListPage
|
||||
{
|
||||
private static readonly CompositeFormat NoMatchingSavedColorsFormat = CompositeFormat.Parse(Resources.ColorPicker_NoMatchingSavedColors_Subtitle);
|
||||
|
||||
private readonly CommandItem _emptyContent;
|
||||
|
||||
public ColorPickerSavedColorsPage()
|
||||
{
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("ColorPicker.png");
|
||||
Title = "Saved colors";
|
||||
Title = Resources.ColorPicker_SavedColors_Title;
|
||||
Name = "ColorPickerSavedColors";
|
||||
Id = "com.microsoft.powertoys.colorpicker.savedColors";
|
||||
|
||||
_emptyContent = new CommandItem()
|
||||
{
|
||||
Title = "No saved colors",
|
||||
Subtitle = "Pick a color first, then try again.",
|
||||
Title = Resources.ColorPicker_NoSavedColors_Title,
|
||||
Subtitle = Resources.ColorPicker_NoSavedColors_Subtitle,
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("ColorPicker.png"),
|
||||
};
|
||||
|
||||
@@ -70,8 +74,8 @@ internal sealed partial class ColorPickerSavedColorsPage : DynamicListPage
|
||||
public override void UpdateSearchText(string oldSearch, string newSearch)
|
||||
{
|
||||
_emptyContent.Subtitle = string.IsNullOrWhiteSpace(newSearch)
|
||||
? "Pick a color first, then try again."
|
||||
: $"No saved colors matching '{newSearch}'";
|
||||
? Resources.ColorPicker_NoSavedColors_Subtitle
|
||||
: string.Format(CultureInfo.CurrentCulture, NoMatchingSavedColorsFormat, newSearch);
|
||||
|
||||
RaiseItemsChanged(0);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
@@ -21,13 +22,13 @@ internal sealed partial class FancyZonesLayoutsPage : DynamicListPage
|
||||
public FancyZonesLayoutsPage()
|
||||
{
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png");
|
||||
Name = Title = "FancyZones Layouts";
|
||||
Name = Title = Resources.FancyZones_Layouts_Title;
|
||||
Id = "com.microsoft.cmdpal.powertoys.fancyzones.layouts";
|
||||
|
||||
_emptyMessage = new CommandItem()
|
||||
{
|
||||
Title = "No layouts found",
|
||||
Subtitle = "Open FancyZones Editor once to initialize layouts.",
|
||||
Title = Resources.FancyZones_NoLayoutsFound_Title,
|
||||
Subtitle = Resources.FancyZones_NoLayoutsFound_Subtitle,
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png"),
|
||||
};
|
||||
EmptyContent = _emptyMessage;
|
||||
|
||||
@@ -4,16 +4,21 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
internal sealed partial class FancyZonesMonitorLayoutPickerPage : DynamicListPage
|
||||
{
|
||||
private static readonly CompositeFormat SetActiveLayoutForFormat = CompositeFormat.Parse(Resources.FancyZones_SetActiveLayoutFor_Format);
|
||||
|
||||
private readonly FancyZonesMonitorDescriptor _monitor;
|
||||
private readonly CommandItem _emptyMessage;
|
||||
|
||||
@@ -21,13 +26,13 @@ internal sealed partial class FancyZonesMonitorLayoutPickerPage : DynamicListPag
|
||||
{
|
||||
_monitor = monitor;
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png");
|
||||
Name = Title = $"Set active layout for {_monitor.Title}";
|
||||
Name = Title = string.Format(CultureInfo.CurrentCulture, SetActiveLayoutForFormat, _monitor.Title);
|
||||
Id = $"com.microsoft.cmdpal.powertoys.fancyzones.monitor.{_monitor.Index}.layouts";
|
||||
|
||||
_emptyMessage = new CommandItem()
|
||||
{
|
||||
Title = "No layouts found",
|
||||
Subtitle = "Open FancyZones Editor once to initialize layouts.",
|
||||
Title = Resources.FancyZones_NoLayoutsFound_Title,
|
||||
Subtitle = Resources.FancyZones_NoLayoutsFound_Subtitle,
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png"),
|
||||
};
|
||||
EmptyContent = _emptyMessage;
|
||||
|
||||
@@ -4,26 +4,31 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
internal sealed partial class FancyZonesMonitorsPage : DynamicListPage
|
||||
{
|
||||
private static readonly CompositeFormat CurrentLayoutFormat = CompositeFormat.Parse(Resources.FancyZones_CurrentLayout_Format);
|
||||
|
||||
private readonly CommandItem _emptyMessage;
|
||||
|
||||
public FancyZonesMonitorsPage()
|
||||
{
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png");
|
||||
Name = Title = "FancyZones Monitors";
|
||||
Name = Title = Resources.FancyZones_Monitors_Title;
|
||||
Id = "com.microsoft.cmdpal.powertoys.fancyzones.monitors";
|
||||
|
||||
_emptyMessage = new CommandItem()
|
||||
{
|
||||
Title = "No monitors found",
|
||||
Subtitle = "Open FancyZones Editor once to initialize monitor data.",
|
||||
Title = Resources.FancyZones_NoMonitorsFound_Title,
|
||||
Subtitle = Resources.FancyZones_NoMonitorsFound_Subtitle,
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png"),
|
||||
};
|
||||
EmptyContent = _emptyMessage;
|
||||
@@ -55,8 +60,8 @@ internal sealed partial class FancyZonesMonitorsPage : DynamicListPage
|
||||
}
|
||||
|
||||
var layoutDescription = FancyZonesDataService.TryGetAppliedLayoutForMonitor(monitor.Data, out var applied) && applied is not null
|
||||
? $"Current layout: {applied.Value.Type}"
|
||||
: "Current layout: unknown";
|
||||
? string.Format(CultureInfo.CurrentCulture, CurrentLayoutFormat, applied.Value.Type)
|
||||
: Resources.FancyZones_CurrentLayout_Unknown;
|
||||
|
||||
var item = new FancyZonesMonitorListItem(monitor, layoutDescription, monitorIcon);
|
||||
items.Add(item);
|
||||
|
||||
@@ -6,6 +6,7 @@ using Awake.ModuleServices;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension;
|
||||
|
||||
@@ -14,32 +15,32 @@ internal sealed partial class PowerToysExtensionPage : ListPage
|
||||
public PowerToysExtensionPage()
|
||||
{
|
||||
Icon = Helpers.PowerToysResourcesHelper.IconFromSettingsIcon("PowerToys.png");
|
||||
Title = "PowerToys";
|
||||
Name = "PowerToys commands";
|
||||
Title = Resources.PowerToys_DisplayName;
|
||||
Name = Resources.PowerToysExtension_CommandsName;
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems()
|
||||
{
|
||||
return [
|
||||
new ListItem(new LaunchModuleCommand("PowerToys", executableName: "PowerToys.exe", displayName: "Open PowerToys"))
|
||||
new ListItem(new LaunchModuleCommand("PowerToys", executableName: "PowerToys.exe", displayName: Resources.PowerToysExtension_OpenPowerToys_Title))
|
||||
{
|
||||
Title = "Open PowerToys",
|
||||
Subtitle = "Launch the PowerToys shell",
|
||||
Title = Resources.PowerToysExtension_OpenPowerToys_Title,
|
||||
Subtitle = Resources.PowerToysExtension_OpenPowerToys_Subtitle,
|
||||
},
|
||||
new ListItem(new OpenPowerToysSettingsCommand("PowerToys", "General"))
|
||||
{
|
||||
Title = "Open PowerToys settings",
|
||||
Subtitle = "Open the main PowerToys settings window",
|
||||
Title = Resources.PowerToysExtension_OpenSettings_Title,
|
||||
Subtitle = Resources.PowerToysExtension_OpenSettings_Subtitle,
|
||||
},
|
||||
new ListItem(new OpenPowerToysSettingsCommand("Workspaces", "Workspaces"))
|
||||
{
|
||||
Title = "Open Workspaces settings",
|
||||
Subtitle = "Jump directly to Workspaces settings",
|
||||
Title = Resources.PowerToysExtension_OpenWorkspacesSettings_Title,
|
||||
Subtitle = Resources.PowerToysExtension_OpenWorkspacesSettings_Subtitle,
|
||||
},
|
||||
new ListItem(new OpenWorkspaceEditorCommand())
|
||||
{
|
||||
Title = "Open Workspaces editor",
|
||||
Subtitle = "Launch the Workspaces editor",
|
||||
Title = Resources.PowerToysExtension_OpenWorkspacesEditor_Title,
|
||||
Subtitle = Resources.PowerToysExtension_OpenWorkspacesEditor_Subtitle,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Pages;
|
||||
|
||||
@@ -15,13 +16,13 @@ internal sealed partial class PowerToysListPage : ListPage
|
||||
public PowerToysListPage()
|
||||
{
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("PowerToys.png");
|
||||
Name = Title = "PowerToys";
|
||||
Name = Title = Resources.PowerToys_DisplayName;
|
||||
Id = "com.microsoft.cmdpal.powertoys";
|
||||
SettingsChangeNotifier.SettingsChanged += OnSettingsChanged;
|
||||
_empty = new CommandItem()
|
||||
{
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("PowerToys.png"),
|
||||
Title = "No matching module found",
|
||||
Title = Resources.PowerToys_NoMatchingModule,
|
||||
Subtitle = SearchText,
|
||||
};
|
||||
EmptyContent = _empty;
|
||||
|
||||
@@ -7,6 +7,7 @@ using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension;
|
||||
|
||||
@@ -14,7 +15,7 @@ public sealed partial class PowerToysCommandsProvider : CommandProvider
|
||||
{
|
||||
public PowerToysCommandsProvider()
|
||||
{
|
||||
DisplayName = "PowerToys";
|
||||
DisplayName = Resources.PowerToys_DisplayName;
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("PowerToys.png");
|
||||
}
|
||||
|
||||
@@ -22,8 +23,8 @@ public sealed partial class PowerToysCommandsProvider : CommandProvider
|
||||
[
|
||||
new CommandItem(new Pages.PowerToysListPage())
|
||||
{
|
||||
Title = "PowerToys",
|
||||
Subtitle = "PowerToys commands and settings",
|
||||
Title = Resources.PowerToys_DisplayName,
|
||||
Subtitle = Resources.PowerToys_Subtitle,
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension;
|
||||
|
||||
@@ -15,13 +16,13 @@ public partial class PowerToysExtensionCommandsProvider : CommandProvider
|
||||
|
||||
public PowerToysExtensionCommandsProvider()
|
||||
{
|
||||
DisplayName = "PowerToys";
|
||||
DisplayName = Resources.PowerToys_DisplayName;
|
||||
Icon = PowerToysResourcesHelper.IconFromSettingsIcon("PowerToys.png");
|
||||
_commands = [
|
||||
new CommandItem(new Pages.PowerToysListPage())
|
||||
{
|
||||
Title = "PowerToys",
|
||||
Subtitle = "PowerToys commands and settings",
|
||||
Title = Resources.PowerToys_DisplayName,
|
||||
Subtitle = Resources.PowerToys_Subtitle,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user