Compare commits

..

1 Commits

Author SHA1 Message Date
Gordon Lam (SH)
a0cafb99c6 Add CmdPalKeyboardService.dll as part of sign 2025-04-21 18:07:26 +08:00
110 changed files with 407 additions and 2654 deletions

View File

@@ -273,4 +273,4 @@ mengyuanchen
testhost
#Tools
OIP
OIP

View File

@@ -8,7 +8,6 @@ Acceleratorkeys
ACCEPTFILES
ACCESSDENIED
ACCESSTOKEN
acfs
AClient
AColumn
acrt
@@ -198,7 +197,6 @@ CLIPBOARDUPDATE
CLIPCHILDREN
CLIPSIBLINGS
closesocket
clp
CLSCTX
clsids
Clusion
@@ -520,13 +518,11 @@ FRAMECHANGED
frm
Froml
FROMTOUCH
fsanitize
fsmgmt
FZE
gacutil
Gaeilge
Gaidhlig
gameid
GC'ed
GCLP
gdi
@@ -633,7 +629,6 @@ HOTKEYF
hotkeys
hotlight
hotspot
Hostx
HPAINTBUFFER
HRAWINPUT
HREDRAW
@@ -717,7 +712,6 @@ INPUTSINK
INPUTTYPE
INSTALLDESKTOPSHORTCUT
INSTALLDIR
installdir
INSTALLFOLDER
INSTALLFOLDERTOBOOTSTRAPPERINSTALLFOLDER
INSTALLFOLDERTOPREVIOUSINSTALLFOLDER
@@ -1046,7 +1040,6 @@ NOINHERITLAYOUT
NOINTERFACE
NOINVERT
NOLINKINFO
nologo
NOMCX
NOMINMAX
NOMIRRORBITMAP
@@ -1084,7 +1077,6 @@ NOTRACK
NOTSRCCOPY
NOTSRCERASE
NOTXORPEN
notwindows
NOZORDER
NPH
npmjs
@@ -1279,7 +1271,6 @@ pstm
PStr
pstream
pstrm
pswd
PSYSTEM
psz
ptb
@@ -1407,7 +1398,6 @@ sacl
safeprojectname
SAMEKEYPREVIOUSLYMAPPED
SAMESHORTCUTPREVIOUSLYMAPPED
sancov
SAVEFAILED
scanled
schedtasks
@@ -1426,7 +1416,6 @@ searchterm
SEARCHUI
SECONDARYDISPLAY
secpol
securestring
SEEMASKINVOKEIDLIST
SELCHANGE
SENDCHANGE
@@ -1580,7 +1569,6 @@ stdcpp
stdcpplatest
STDMETHODCALLTYPE
STDMETHODIMP
steamapps
STGC
STGM
STGMEDIUM
@@ -1944,7 +1932,6 @@ WUX
Wwanpp
XAxis
xclip
xcopy
XDocument
XElement
xfd
@@ -1983,11 +1970,3 @@ ZOOMITX
ZXk
ZXNs
zzz
ACIE
AOklab
BCIE
BOklab
culori
Evercoder
LCh
CIELCh

View File

@@ -331,8 +331,6 @@
"TestableIO.System.IO.Abstractions.Wrappers.dll",
"WinUI3Apps\\TestableIO.System.IO.Abstractions.Wrappers.dll",
"WinUI3Apps\\OpenAI.dll",
"Testably.Abstractions.FileSystem.Interface.dll",
"WinUI3Apps\\Testably.Abstractions.FileSystem.Interface.dll",
"ColorCode.Core.dll",
"ColorCode.UWP.dll",
"UnitsNet.dll",

View File

@@ -1,24 +1,16 @@
Param(
# Using the default value of 1.7 for winAppSdkVersionNumber and useExperimentalVersion as false
# Using the default value of 1.6 for winAppSdkVersionNumber and useExperimentalVersion as false
[Parameter(Mandatory=$False,Position=1)]
[string]$winAppSdkVersionNumber = "1.7",
[string]$winAppSdkVersionNumber = "1.6",
# When the pipeline calls the PS1 file, the passed parameters are converted to string type
[Parameter(Mandatory=$False,Position=2)]
[boolean]$useExperimentalVersion = $False,
# Root folder Path for processing
[Parameter(Mandatory=$False,Position=3)]
[string]$rootPath = $(Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)),
# Root folder Path for processing
[Parameter(Mandatory=$False,Position=4)]
[string]$sourceLink = "https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json"
[boolean]$useExperimentalVersion = $False
)
function Update-NugetConfig {
param (
[string]$filePath = [System.IO.Path]::Combine($rootPath, "nuget.config")
[string]$filePath = "nuget.config"
)
Write-Host "Updating nuget.config file"
@@ -43,33 +35,7 @@ function Update-NugetConfig {
$xml.Save($filePath)
}
function Read-FileWithEncoding {
param (
[string]$Path
)
$reader = New-Object System.IO.StreamReader($Path, $true) # auto-detect encoding
$content = $reader.ReadToEnd()
$encoding = $reader.CurrentEncoding
$reader.Close()
return [PSCustomObject]@{
Content = $content
Encoding = $encoding
}
}
function Write-FileWithEncoding {
param (
[string]$Path,
[string]$Content,
[System.Text.Encoding]$Encoding
)
$writer = New-Object System.IO.StreamWriter($Path, $false, $Encoding)
$writer.Write($Content)
$writer.Close()
}
$sourceLink = "https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json"
# Execute nuget list and capture the output
if ($useExperimentalVersion) {
@@ -113,54 +79,50 @@ if ($latestVersion) {
}
# Update packages.config files
Get-ChildItem -Path $rootPath -Recurse packages.config | ForEach-Object {
$file = Read-FileWithEncoding -Path $_.FullName
$content = $file.Content
Get-ChildItem -Recurse packages.config | ForEach-Object {
$content = Get-Content $_.FullName -Raw
if ($content -match 'package id="Microsoft.WindowsAppSDK"') {
$newVersionString = 'package id="Microsoft.WindowsAppSDK" version="' + $WinAppSDKVersion + '"'
$oldVersionString = 'package id="Microsoft.WindowsAppSDK" version="[-.0-9a-zA-Z]*"'
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
Set-Content -Path $_.FullName -Value $content
Write-Host "Modified " $_.FullName
}
}
# Update Directory.Packages.props file
$propsFile = [System.IO.Path]::Combine($rootPath,"Directory.Packages.props")
$propsFile = "Directory.Packages.props"
if (Test-Path $propsFile) {
$file = Read-FileWithEncoding -Path $propsFile
$content = $file.Content
$content = Get-Content $propsFile -Raw
if ($content -match '<PackageVersion Include="Microsoft.WindowsAppSDK"') {
$newVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="' + $WinAppSDKVersion + '" />'
$oldVersionString = '<PackageVersion Include="Microsoft.WindowsAppSDK" Version="[-.0-9a-zA-Z]*" />'
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $propsFile -Content $content -Encoding $file.encoding
Set-Content -Path $propsFile -Value $content
Write-Host "Modified " $propsFile
}
}
# Update .vcxproj files
Get-ChildItem -Path $rootPath -Recurse *.vcxproj | ForEach-Object {
$file = Read-FileWithEncoding -Path $_.FullName
$content = $file.Content
Get-ChildItem -Recurse *.vcxproj | ForEach-Object {
$content = Get-Content $_.FullName -Raw
if ($content -match '\\Microsoft.WindowsAppSDK.') {
$newVersionString = '\Microsoft.WindowsAppSDK.' + $WinAppSDKVersion + '\'
$oldVersionString = '\\Microsoft.WindowsAppSDK.[-.0-9a-zA-Z]*\\'
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
Set-Content -Path $_.FullName -Value $content
Write-Host "Modified " $_.FullName
}
}
# Update .csproj files
Get-ChildItem -Path $rootPath -Recurse *.csproj | ForEach-Object {
$file = Read-FileWithEncoding -Path $_.FullName
$content = $file.Content
Get-ChildItem -Recurse *.csproj | ForEach-Object {
$content = Get-Content $_.FullName -Raw
if ($content -match 'PackageReference Include="Microsoft.WindowsAppSDK"') {
$newVersionString = 'PackageReference Include="Microsoft.WindowsAppSDK" Version="'+ $WinAppSDKVersion + '"'
$oldVersionString = 'PackageReference Include="Microsoft.WindowsAppSDK" Version="[-.0-9a-zA-Z]*"'
$content = $content -replace $oldVersionString, $newVersionString
Write-FileWithEncoding -Path $_.FullName -Content $content -Encoding $file.encoding
Set-Content -Path $_.FullName -Value $content
Write-Host "Modified " $_.FullName
}
}

View File

@@ -33,7 +33,7 @@ parameters:
default: true
- name: winAppSDKVersionNumber
type: string
default: 1.7
default: 1.6
- name: useExperimentalVersion
type: boolean
default: false

View File

@@ -148,7 +148,5 @@ extends:
parameters:
versionNumber: ${{ parameters.versionNumber }}
includePublicSymbolServer: ${{ parameters.publishSymbolsToPublic }}
${{ if ne(parameters.publishSymbolsToPublic, true) }}:
symbolExpiryTime: 10 # For private builds, expire symbols within 10 days. The default is 100 years.
subscription: $(SymbolPublishingServiceConnection)
symbolProject: $(SymbolPublishingProject)

View File

@@ -17,7 +17,6 @@ steps:
arguments: >
-winAppSdkVersionNumber ${{ parameters.versionNumber }}
-useExperimentalVersion $${{ parameters.useExperimentalVersion }}
-rootPath "$(build.sourcesdirectory)"
- script: echo $(WinAppSDKVersion)
displayName: 'Display WinAppSDK Version Found'

View File

@@ -45,7 +45,7 @@
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.4" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.120-preview" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.4" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->
@@ -55,7 +55,7 @@
-->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.6.250205002" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageVersion Include="ModernWpfUI" Version="0.9.4" />

View File

@@ -1472,8 +1472,8 @@ SOFTWARE.
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.2.0
- Microsoft.Windows.SDK.BuildTools 10.0.22621.2428
- Microsoft.WindowsAppSDK 1.7.250401001
- Microsoft.WindowsPackageManager.ComInterop 1.10.340
- Microsoft.WindowsAppSDK 1.6.250205002
- Microsoft.WindowsPackageManager.ComInterop 1.10.120-preview
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
- Microsoft.Xaml.Behaviors.Wpf 1.1.39
- ModernWpfUI 0.9.4

View File

@@ -708,8 +708,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.System
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CmdPalKeyboardService", "src\modules\cmdpal\CmdPalKeyboardService\CmdPalKeyboardService.vcxproj", "{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerRename.FuzzingTest", "src\modules\powerrename\PowerRename.FuzzingTest\PowerRename.FuzzingTest.vcxproj", "{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -2590,12 +2588,6 @@ Global
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|ARM64.Build.0 = Release|ARM64
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|x64.ActiveCfg = Release|x64
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2}.Release|x64.Build.0 = Release|x64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Debug|x64.ActiveCfg = Debug|x64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Debug|x64.Build.0 = Debug|x64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|ARM64.ActiveCfg = Release|ARM64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.ActiveCfg = Release|x64
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2867,7 +2859,6 @@ Global
{5702B3CC-8575-48D5-83D8-15BB42269CD3} = {929C1324-22E8-4412-A9A8-80E85F3985A5}
{64B88F02-CD88-4ED8-9624-989A800230F9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{5F63C743-F6CE-4DBA-A200-2B3F8A14E8C2} = {3846508C-77EB-4034-A702-F8BB263C4F79}
{2694E2FB-DCD5-4BFF-A418-B6C3C7CE3B8E} = {89E20BCE-EB9C-46C8-8B50-E01A82E6FDC3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -1,117 +0,0 @@
# 🧪 C++ Project Fuzzing Test Guide
This guide walks you through setting up a **fuzzing test** project for a C++ module using [libFuzzer](https://llvm.org/docs/LibFuzzer.html).
.
---
## 🏗️ Step-by-Step Setup
### 1. Create a New C++ Project
- Use **Empty Project** template.
- Name it `<ModuleName>.FuzzingTest`.
---
### 2. Update Build Configuration
- In **Configuration Manager**, Uncheck Build for both Release|ARM64, Debug|ARM64 and Debug|x64 configurations.
- Note: ARM64 is not supported in this case, so leave ARM64 configurations build disabled.
---
### 3. Enable ASan and libFuzzer in `.vcxproj`
Edit the project file to enable fuzzing:
```xml
<PropertyGroup>
<EnableASAN>true</EnableASAN>
<EnableFuzzer>true</EnableFuzzer>
</PropertyGroup>
```
---
### 4. Add Fuzzing Compiler Flags
Add this to `AdditionalOptions` under the `Fuzzing` configuration:
```xml
/fsanitize=address
/fsanitize-coverage=inline-8bit-counters
/fsanitize-coverage=edge
/fsanitize-coverage=trace-cmp
/fsanitize-coverage=trace-div
%(AdditionalOptions)
```
---
### 5. Link the Sanitizer Coverage Runtime
In `Linker → Input → Additional Dependencies`, add:
```text
$(VCToolsInstallDir)lib\$(Platform)\libsancov.lib
```
---
### 6. Copy Required Runtime DLL
Add a `PostBuildEvent` to copy the ASAN DLL:
```xml
<Command>
xcopy /y "$(VCToolsInstallDir)bin\Hostx64\x64\clang_rt.asan_dynamic-x86_64.dll" "$(OutDir)"
</Command>
```
---
### 7. Add Preprocessor Definitions
To avoid annotation issues, add these to the `Preprocessor Definitions`:
```text
_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION
```
---
## 🧬 Required Code
### `LLVMFuzzerTestOneInput` Entry Point
Every fuzzing project must expose this function:
```cpp
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
std::string input(reinterpret_cast<const char*>(data), size);
try
{
// Call your module with the input here.
}
catch (...) {}
return 0;
}
```
---
## ⚙️ [Test run in the cloud](https://eng.ms/docs/cloud-ai-platform/azure-edge-platform-aep/aep-security/epsf-edge-and-platform-security-fundamentals/the-onefuzz-service/onefuzz/faq/notwindows/walkthrough)
To submit a job to the cloud you can run with this command:
```
oip submit --config .\OneFuzzConfig.json --drop-path <your_submission_directory> --platform windows --do-not-file-bugs --duration 1
```
You want to run with --do-not-file-bugs because if there is an issue with running the parser in the cloud (which is very possible), you don't want bugs to be created if there is an issue. The --duration task is the number of hours you want the task to run. I recommend just running for 1 hour to make sure things work initially. If you don't specify this parameter, it will default to 48 hours. You can find more about submitting a test job here.
OneFuzz will send you an email when the job has started.
---

View File

@@ -79,7 +79,10 @@
<ComponentGroupRef Id="ToolComponentGroup" />
<ComponentGroupRef Id="MonacoSRCHeatGenerated" />
<ComponentGroupRef Id="WorkspacesComponentGroup" />
<ComponentGroupRef Id="CmdPalComponentGroup" />
<?if $(var.CIBuild) = "true" ?>
<ComponentGroupRef Id="CmdPalComponentGroup" />
<?endif?>
</Feature>
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLFOLDER]" After="CostFinalize" />

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Some items may be set in Directory.Build.props in root -->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project=".\Common.Dotnet.PrepareGeneratedFolder.targets" />
<PropertyGroup>
<WindowsSdkPackageVersion>10.0.22621.57</WindowsSdkPackageVersion>
<TargetFramework>net9.0-windows10.0.22621.0</TargetFramework>

View File

@@ -1,16 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="EnsureGeneratedBaseFolder" BeforeTargets="XamlPreCompile">
<PropertyGroup>
<!-- Only create the base 'generated' folder -->
<CompilerGeneratedFilesOutputPath>$(ProjectDir)obj\g</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<!-- Create 'generated' folder if missing -->
<MakeDir Directories="$(CompilerGeneratedFilesOutputPath)" />
<!-- Optional logging for debugging -->
<Message Text="Ensured: $(GeneratedBasePath)" Importance="Low" />
</Target>
</Project>

View File

@@ -141,40 +141,6 @@ namespace ManagedCommon
return lab;
}
/// <summary>
/// Convert a given <see cref="Color"/> to a Oklab color
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert</param>
/// <returns>The perceptual lightness [0..1] and two chromaticities [-0.5..0.5]</returns>
public static (double Lightness, double ChromaticityA, double ChromaticityB) ConvertToOklabColor(Color color)
{
var linear = ConvertSRGBToLinearRGB(color.R / 255d, color.G / 255d, color.B / 255d);
var oklab = GetOklabColorFromLinearRGB(linear.R, linear.G, linear.B);
return oklab;
}
/// <summary>
/// Convert a given <see cref="Color"/> to a Oklch color
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert</param>
/// <returns>The perceptual lightness [0..1], the chroma [0..0.5], and the hue angle [0°..360°]</returns>
public static (double Lightness, double Chroma, double Hue) ConvertToOklchColor(Color color)
{
var oklab = ConvertToOklabColor(color);
var oklch = GetOklchColorFromOklab(oklab.Lightness, oklab.ChromaticityA, oklab.ChromaticityB);
return oklch;
}
public static (double R, double G, double B) ConvertSRGBToLinearRGB(double r, double g, double b)
{
// inverse companding, gamma correction must be undone
double rLinear = (r > 0.04045) ? Math.Pow((r + 0.055) / 1.055, 2.4) : (r / 12.92);
double gLinear = (g > 0.04045) ? Math.Pow((g + 0.055) / 1.055, 2.4) : (g / 12.92);
double bLinear = (b > 0.04045) ? Math.Pow((b + 0.055) / 1.055, 2.4) : (b / 12.92);
return (rLinear, gLinear, bLinear);
}
/// <summary>
/// Convert a given <see cref="Color"/> to a CIE XYZ color (XYZ)
/// The constants of the formula matches this Wikipedia page, but at a higher precision:
@@ -190,7 +156,10 @@ namespace ManagedCommon
double g = color.G / 255d;
double b = color.B / 255d;
(double rLinear, double gLinear, double bLinear) = ConvertSRGBToLinearRGB(r, g, b);
// inverse companding, gamma correction must be undone
double rLinear = (r > 0.04045) ? Math.Pow((r + 0.055) / 1.055, 2.4) : (r / 12.92);
double gLinear = (g > 0.04045) ? Math.Pow((g + 0.055) / 1.055, 2.4) : (g / 12.92);
double bLinear = (b > 0.04045) ? Math.Pow((b + 0.055) / 1.055, 2.4) : (b / 12.92);
return (
(rLinear * 0.41239079926595948) + (gLinear * 0.35758433938387796) + (bLinear * 0.18048078840183429),
@@ -241,63 +210,6 @@ namespace ManagedCommon
return (l, a, b);
}
/// <summary>
/// Convert a linear RGB color <see cref="double"/> to an Oklab color.
/// The constants of this formula come from https://github.com/Evercoder/culori/blob/2bedb8f0507116e75f844a705d0b45cf279b15d0/src/oklab/convertLrgbToOklab.js
/// and the implementation is based on https://bottosson.github.io/posts/oklab/
/// </summary>
/// <param name="r">Linear R value</param>
/// <param name="g">Linear G value</param>
/// <param name="b">Linear B value</param>
/// <returns>The perceptual lightness [0..1] and two chromaticities [-0.5..0.5]</returns>
private static (double Lightness, double ChromaticityA, double ChromaticityB)
GetOklabColorFromLinearRGB(double r, double g, double b)
{
double l = (0.41222147079999993 * r) + (0.5363325363 * g) + (0.0514459929 * b);
double m = (0.2119034981999999 * r) + (0.6806995450999999 * g) + (0.1073969566 * b);
double s = (0.08830246189999998 * r) + (0.2817188376 * g) + (0.6299787005000002 * b);
double l_ = Math.Cbrt(l);
double m_ = Math.Cbrt(m);
double s_ = Math.Cbrt(s);
return (
(0.2104542553 * l_) + (0.793617785 * m_) - (0.0040720468 * s_),
(1.9779984951 * l_) - (2.428592205 * m_) + (0.4505937099 * s_),
(0.0259040371 * l_) + (0.7827717662 * m_) - (0.808675766 * s_)
);
}
/// <summary>
/// Convert an Oklab color <see cref="double"/> from Cartesian form to its polar form Oklch
/// https://bottosson.github.io/posts/oklab/#the-oklab-color-space
/// </summary>
/// <param name="lightness">The <see cref="lightness"/></param>
/// <param name="chromaticity_a">The <see cref="chromaticity_a"/></param>
/// <param name="chromaticity_b">The <see cref="chromaticity_b"/></param>
/// <returns>The perceptual lightness [0..1], the chroma [0..0.5], and the hue angle [0°..360°]</returns>
private static (double Lightness, double Chroma, double Hue)
GetOklchColorFromOklab(double lightness, double chromaticity_a, double chromaticity_b)
{
return GetLCHColorFromLAB(lightness, chromaticity_a, chromaticity_b);
}
/// <summary>
/// Convert a color in Cartesian form (Lab) to its polar form (LCh)
/// </summary>
/// <param name="lightness">The <see cref="lightness"/></param>
/// <param name="chromaticity_a">The <see cref="chromaticity_a"/></param>
/// <param name="chromaticity_b">The <see cref="chromaticity_b"/></param>
/// <returns>The lightness, chroma, and hue angle</returns>
private static (double Lightness, double Chroma, double Hue)
GetLCHColorFromLAB(double lightness, double chromaticity_a, double chromaticity_b)
{
// Lab to LCh transformation
double chroma = Math.Sqrt(Math.Pow(chromaticity_a, 2) + Math.Pow(chromaticity_b, 2));
double hue = Math.Round(chroma, 3) == 0 ? 0.0 : ((Math.Atan2(chromaticity_b, chromaticity_a) * 180d / Math.PI) + 360d) % 360d;
return (lightness, chroma, hue);
}
/// <summary>
/// Convert a given <see cref="Color"/> to a natural color (hue, whiteness, blackness)
/// </summary>
@@ -364,17 +276,12 @@ namespace ManagedCommon
{ "Br", 'p' }, // brightness percent
{ "In", 'p' }, // intensity percent
{ "Ll", 'p' }, // lightness (HSL) percent
{ "Lc", 'p' }, // lightness(CIELAB)percent
{ "Va", 'p' }, // value percent
{ "Wh", 'p' }, // whiteness percent
{ "Bn", 'p' }, // blackness percent
{ "Lc", 'p' }, // lightness (CIE) percent
{ "Ca", 'p' }, // chromaticityA (CIELAB) percent
{ "Cb", 'p' }, // chromaticityB (CIELAB) percent
{ "Lo", 'p' }, // lightness (Oklab/Oklch) percent
{ "Oa", 'p' }, // chromaticityA (Oklab) percent
{ "Ob", 'p' }, // chromaticityB (Oklab) percent
{ "Oc", 'p' }, // chroma (Oklch) percent
{ "Oh", 'p' }, // hue angle (Oklch) percent
{ "Ca", 'p' }, // chromaticityA percent
{ "Cb", 'p' }, // chromaticityB percent
{ "Xv", 'i' }, // X value int
{ "Yv", 'i' }, // Y value int
{ "Zv", 'i' }, // Z value int
@@ -517,10 +424,6 @@ namespace ManagedCommon
var (lightnessC, _, _) = ConvertToCIELABColor(color);
lightnessC = Math.Round(lightnessC, 2);
return lightnessC.ToString(CultureInfo.InvariantCulture);
case "Lo":
var (lightnessO, _, _) = ConvertToOklabColor(color);
lightnessO = Math.Round(lightnessO, 2);
return lightnessO.ToString(CultureInfo.InvariantCulture);
case "Wh":
var (_, whiteness, _) = ConvertToHWBColor(color);
whiteness = Math.Round(whiteness * 100);
@@ -537,22 +440,6 @@ namespace ManagedCommon
var (_, _, chromaticityB) = ConvertToCIELABColor(color);
chromaticityB = Math.Round(chromaticityB, 2);
return chromaticityB.ToString(CultureInfo.InvariantCulture);
case "Oa":
var (_, chromaticityAOklab, _) = ConvertToOklabColor(color);
chromaticityAOklab = Math.Round(chromaticityAOklab, 2);
return chromaticityAOklab.ToString(CultureInfo.InvariantCulture);
case "Ob":
var (_, _, chromaticityBOklab) = ConvertToOklabColor(color);
chromaticityBOklab = Math.Round(chromaticityBOklab, 2);
return chromaticityBOklab.ToString(CultureInfo.InvariantCulture);
case "Oc":
var (_, chromaOklch, _) = ConvertToOklchColor(color);
chromaOklch = Math.Round(chromaOklch, 2);
return chromaOklch.ToString(CultureInfo.InvariantCulture);
case "Oh":
var (_, _, hueOklch) = ConvertToOklchColor(color);
hueOklch = Math.Round(hueOklch, 2);
return hueOklch.ToString(CultureInfo.InvariantCulture);
case "Xv":
var (x, _, _) = ConvertToCIEXYZColor(color);
x = Math.Round(x * 100, 4);
@@ -608,10 +495,8 @@ namespace ManagedCommon
case "HSI": return "hsi(%Hu, %Si%, %In%)";
case "HWB": return "hwb(%Hu, %Wh%, %Bn%)";
case "NCol": return "%Hn, %Wh%, %Bn%";
case "CIEXYZ": return "XYZ(%Xv, %Yv, %Zv)";
case "CIELAB": return "CIELab(%Lc, %Ca, %Cb)";
case "Oklab": return "oklab(%Lo, %Oa, %Ob)";
case "Oklch": return "oklch(%Lo, %Oc, %Oh)";
case "CIEXYZ": return "XYZ(%Xv, %Yv, %Zv)";
case "VEC4": return "(%Reff, %Grff, %Blff, 1f)";
case "Decimal": return "%Dv";
case "HEX Int": return "0xFF%ReX%GrX%BlX";

View File

@@ -1,51 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ManagedCommon
{
public static class IdRecoveryHelper
{
/// <summary>
/// Fixes invalid IDs in the given list by assigning unique values.
/// It ensures that all IDs are non-empty and unique, correcting any duplicates or empty IDs.
/// </summary>
/// <param name="items">The list of items that may contain invalid IDs.</param>
public static void RecoverInvalidIds<T>(IEnumerable<T> items)
where T : class, IHasId
{
var idSet = new HashSet<int>();
int newId = 0;
var sortedItems = items.OrderBy(i => i.Id).ToList(); // Sort items by ID for consistent processing
// Iterate through the list and fix invalid IDs
foreach (var item in sortedItems)
{
// If the ID is invalid or already exists in the set (duplicate), assign a new unique ID
if (!idSet.Add(item.Id))
{
// Find the next available unique ID
while (idSet.Contains(newId))
{
newId++;
}
item.Id = newId;
idSet.Add(newId); // Add the newly assigned ID to the set
}
}
}
}
public interface IHasId
{
int Id { get; set; }
}
}

View File

@@ -301,7 +301,6 @@ namespace package
if (!std::filesystem::exists(directoryPath))
{
Logger::error(L"The directory '" + directoryPath + L"' does not exist.");
return {};
}
const std::regex pattern(R"(^.+\.(appx|msix|msixbundle)$)", std::regex_constants::icase);

View File

@@ -18,19 +18,10 @@ public static class OcrHelpers
{
public static async Task<string> ExtractTextAsync(SoftwareBitmap bitmap, CancellationToken cancellationToken)
{
var ocrLanguage = GetOCRLanguage();
var ocrLanguage = GetOCRLanguage() ?? throw new InvalidOperationException("Unable to determine OCR language");
cancellationToken.ThrowIfCancellationRequested();
OcrEngine ocrEngine;
if (ocrLanguage is not null)
{
ocrEngine = OcrEngine.TryCreateFromLanguage(ocrLanguage) ?? throw new InvalidOperationException("Unable to create OCR engine from specified language");
}
else
{
ocrEngine = OcrEngine.TryCreateFromUserProfileLanguages() ?? throw new InvalidOperationException("Unable to create OCR engine from user profile language");
}
var ocrEngine = OcrEngine.TryCreateFromLanguage(ocrLanguage) ?? throw new InvalidOperationException("Unable to create OCR engine");
cancellationToken.ThrowIfCancellationRequested();
var ocrResult = await ocrEngine.RecognizeAsync(bitmap);

View File

@@ -15,6 +15,8 @@
<ProjectPriFileName>PowerToys.EnvironmentVariablesUILib.pri</ProjectPriFileName>
<GenerateLibraryLayout>true</GenerateLibraryLayout>
<IsPackable>true</IsPackable>
<!-- The default generated file path exceeds the length limit 260 on the build agent. Using a shorter path as a workaround. -->
<CompilerGeneratedFilesOutputPath>$(ProjectDir)obj\g</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<PropertyGroup>
@@ -54,4 +56,7 @@
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<Target Name="EnsureCompilerGeneratedFilesOutputPathExists" BeforeTargets="XamlPreCompile">
<MakeDir Directories="$(CompilerGeneratedFilesOutputPath)" />
</Target>
</Project>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" />
<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">
@@ -141,7 +141,7 @@
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@@ -153,7 +153,7 @@
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets'))" />
</Target>
</Project>

View File

@@ -4,5 +4,5 @@
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.6.250205002" targetFramework="native" />
</packages>

View File

@@ -121,22 +121,6 @@ namespace AppLauncher
// packaged apps: try launching first by AppUserModel.ID
// usage example: elevated Terminal
if (!launched && !app.appUserModelId.empty() && !app.packageFullName.empty())
{
Logger::trace(L"Launching {} as {} - {app.packageFullName}", app.name, app.appUserModelId, app.packageFullName);
auto res = LaunchApp(L"shell:AppsFolder\\" + app.appUserModelId, app.commandLineArgs, app.isElevated);
if (res.isOk())
{
launched = true;
}
else
{
launchErrors.push_back({ std::filesystem::path(app.path).filename(), res.error() });
}
}
// win32 app with appUserModelId:
// usage example: steam games
if (!launched && !app.appUserModelId.empty())
{
Logger::trace(L"Launching {} as {}", app.name, app.appUserModelId);
auto res = LaunchApp(L"shell:AppsFolder\\" + app.appUserModelId, app.commandLineArgs, app.isElevated);

View File

@@ -1,6 +1,5 @@
#include "pch.h"
#include "AppUtils.h"
#include "SteamHelper.h"
#include <atlbase.h>
#include <propvarutil.h>
@@ -35,8 +34,6 @@ namespace Utils
constexpr const wchar_t* EdgeFilename = L"msedge.exe";
constexpr const wchar_t* ChromeFilename = L"chrome.exe";
constexpr const wchar_t* SteamUrlProtocol = L"steam:";
}
AppList IterateAppsFolder()
@@ -141,34 +138,6 @@ namespace Utils
else if (prop == NonLocalizable::PackageInstallPathProp || prop == NonLocalizable::InstallPathProp)
{
data.installPath = propVariantString.m_pData;
if (!data.installPath.empty())
{
const bool isSteamProtocol = data.installPath.rfind(NonLocalizable::SteamUrlProtocol, 0) == 0;
if (isSteamProtocol)
{
Logger::info(L"Found steam game: protocol path: {}", data.installPath);
data.protocolPath = data.installPath;
try
{
auto gameId = Steam::GetGameIdFromUrlProtocolPath(data.installPath);
auto gameFolder = Steam::GetSteamGameInfoFromAcfFile(gameId);
if (gameFolder)
{
data.installPath = gameFolder->gameInstallationPath;
Logger::info(L"Found steam game: physical path: {}", data.installPath);
}
}
catch (std::exception ex)
{
Logger::error(L"Failed to get installPath for game {}", data.installPath);
Logger::error("Error: {}", ex.what());
}
}
}
}
}
@@ -428,10 +397,5 @@ namespace Utils
{
return installPath.ends_with(NonLocalizable::ChromeFilename);
}
bool AppData::IsSteamGame() const
{
return protocolPath.rfind(NonLocalizable::SteamUrlProtocol, 0) == 0;
}
}
}

View File

@@ -13,12 +13,10 @@ namespace Utils
std::wstring packageFullName;
std::wstring appUserModelId;
std::wstring pwaAppId;
std::wstring protocolPath;
bool canLaunchElevated = false;
bool IsEdge() const;
bool IsChrome() const;
bool IsSteamGame() const;
};
using AppList = std::vector<AppData>;

View File

@@ -1,171 +0,0 @@
#include "pch.h"
#include "SteamHelper.h"
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <filesystem>
#include <regex>
#include <string>
namespace Utils
{
static std::wstring Utf8ToWide(const std::string& utf8)
{
if (utf8.empty())
return L"";
int size = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), nullptr, 0);
if (size <= 0)
return L"";
std::wstring wide(size, L'\0');
MultiByteToWideChar(CP_UTF8, 0, utf8.data(), static_cast<int>(utf8.size()), wide.data(), size);
return wide;
}
namespace Steam
{
using namespace std;
namespace fs = std::filesystem;
static std::optional<std::wstring> GetSteamExePathFromRegistry()
{
static std::optional<std::wstring> cachedPath;
if (cachedPath.has_value())
{
return cachedPath;
}
const std::vector<HKEY> roots = { HKEY_CLASSES_ROOT, HKEY_LOCAL_MACHINE, HKEY_USERS };
const std::vector<std::wstring> subKeys = {
L"steam\\shell\\open\\command",
L"Software\\Classes\\steam\\shell\\open\\command",
};
for (HKEY root : roots)
{
for (const auto& subKey : subKeys)
{
HKEY hKey;
if (RegOpenKeyExW(root, subKey.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
wchar_t value[512];
DWORD size = sizeof(value);
DWORD type = 0;
if (RegQueryValueExW(hKey, nullptr, nullptr, &type, reinterpret_cast<LPBYTE>(value), &size) == ERROR_SUCCESS &&
(type == REG_SZ || type == REG_EXPAND_SZ))
{
std::wregex exeRegex(LR"delim("([^"]+steam\.exe)")delim");
std::wcmatch match;
if (std::regex_search(value, match, exeRegex) && match.size() > 1)
{
RegCloseKey(hKey);
cachedPath = match[1].str();
return cachedPath;
}
}
RegCloseKey(hKey);
}
}
}
cachedPath = std::nullopt;
return std::nullopt;
}
static fs::path GetSteamBasePath()
{
auto steamFolderOpt = GetSteamExePathFromRegistry();
if (!steamFolderOpt)
{
return {};
}
return fs::path(*steamFolderOpt).parent_path() / L"steamapps";
}
static fs::path GetAcfFilePath(const std::wstring& gameId)
{
auto steamFolderOpt = GetSteamExePathFromRegistry();
if (!steamFolderOpt)
{
return {};
}
return GetSteamBasePath() / (L"appmanifest_" + gameId + L".acf");
}
static fs::path GetGameInstallPath(const std::wstring& gameFolderName)
{
auto steamFolderOpt = GetSteamExePathFromRegistry();
if (!steamFolderOpt)
{
return {};
}
return GetSteamBasePath() / L"common" / gameFolderName;
}
static unordered_map<wstring, wstring> ParseAcfFile(const fs::path& acfPath)
{
unordered_map<wstring, wstring> result;
ifstream file(acfPath);
if (!file.is_open())
return result;
string line;
while (getline(file, line))
{
smatch matches;
static const regex pattern(R"delim("([^"]+)"\s+"([^"]+)")delim");
if (regex_search(line, matches, pattern) && matches.size() == 3)
{
wstring key = Utf8ToWide(matches[1].str());
wstring value = Utf8ToWide(matches[2].str());
result[key] = value;
}
}
return result;
}
std::unique_ptr<Steam::SteamGame> GetSteamGameInfoFromAcfFile(const std::wstring& gameId)
{
fs::path acfPath = Steam::GetAcfFilePath(gameId);
if (!fs::exists(acfPath))
return nullptr;
auto kv = ParseAcfFile(acfPath);
if (kv.empty() || kv.find(L"installdir") == kv.end())
return nullptr;
fs::path gamePath = Steam::GetGameInstallPath(kv[L"installdir"]);
if (!fs::exists(gamePath))
return nullptr;
auto game = std::make_unique<Steam::SteamGame>();
game->gameId = gameId;
game->gameInstallationPath = gamePath.wstring();
return game;
}
std::wstring GetGameIdFromUrlProtocolPath(const std::wstring& urlPath)
{
const std::wstring steamGamePrefix = L"steam://rungameid/";
if (urlPath.rfind(steamGamePrefix, 0) == 0)
{
return urlPath.substr(steamGamePrefix.length());
}
return L"";
}
}
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "pch.h"
namespace Utils
{
namespace NonLocalizable
{
const std::wstring AcfFileNameTemplate = L"appmanifest_<gameid>.acfs";
}
namespace Steam
{
struct SteamGame
{
std::wstring gameId;
std::wstring gameInstallationPath;
};
std::unique_ptr<SteamGame> GetSteamGameInfoFromAcfFile(const std::wstring& gameId);
std::wstring GetGameIdFromUrlProtocolPath(const std::wstring& urlPath);
}
}

View File

@@ -41,7 +41,6 @@
<ClInclude Include="pch.h" />
<ClInclude Include="PwaHelper.h" />
<ClInclude Include="Result.h" />
<ClInclude Include="SteamHelper.h" />
<ClInclude Include="StringUtils.h" />
<ClInclude Include="utils.h" />
<ClInclude Include="WbemHelper.h" />
@@ -58,7 +57,6 @@
<PrecompiledHeader Condition="'$(UsePrecompiledHeaders)' != 'false'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="PwaHelper.cpp" />
<ClCompile Include="SteamGameHelper.cpp" />
<ClCompile Include="two_way_pipe_message_ipc.cpp" />
<ClCompile Include="WbemHelper.cpp" />
<ClCompile Include="WorkspacesData.cpp" />

View File

@@ -53,9 +53,6 @@
<ClInclude Include="StringUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="SteamHelper.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
@@ -91,9 +88,6 @@
<ClCompile Include="WbemHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SteamGameHelper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@@ -71,8 +71,6 @@ namespace SnapshotUtils
continue;
}
Logger::info("Try to get window app:{}", reinterpret_cast<void*>(window));
DWORD pid{};
GetWindowThreadProcessId(window, &pid);
@@ -120,19 +118,10 @@ namespace SnapshotUtils
auto data = Utils::Apps::GetApp(processPath, pid, installedApps);
if (!data.has_value() || data->name.empty())
{
Logger::info(L"Installed app not found:{},{}", reinterpret_cast<void*>(window), processPath);
Logger::info(L"Installed app not found: {}", processPath);
continue;
}
if (!data->IsSteamGame() && !WindowUtils::HasThickFrame(window))
{
// Only care about steam games if it has no thick frame to remain consistent with
// the behavior as before.
continue;
}
Logger::info(L"Found app for window:{},{}", reinterpret_cast<void*>(window), processPath);
auto appData = data.value();
bool isEdge = appData.IsEdge();

View File

@@ -200,14 +200,6 @@ std::optional<WindowWithDistance> WindowArranger::GetNearestWindow(const Workspa
}
auto data = Utils::Apps::GetApp(processPath, pid, m_installedApps);
if (!data->IsSteamGame() && !WindowUtils::HasThickFrame(window))
{
// Only care about steam games if it has no thick frame to remain consistent with
// the behavior as before.
continue;
}
if (!data.has_value())
{
continue;

View File

@@ -9,12 +9,10 @@ namespace WindowFilter
{
auto style = GetWindowLong(window, GWL_STYLE);
bool isPopup = WindowUtils::HasStyle(style, WS_POPUP);
bool hasThickFrame = WindowUtils::HasStyle(style, WS_THICKFRAME);
bool hasCaption = WindowUtils::HasStyle(style, WS_CAPTION);
bool hasMinimizeMaximizeButtons = WindowUtils::HasStyle(style, WS_MINIMIZEBOX) || WindowUtils::HasStyle(style, WS_MAXIMIZEBOX);
Logger::info("Style for window: {}, {:#x}", reinterpret_cast<void*>(window), style);
if (isPopup && !(hasCaption || hasMinimizeMaximizeButtons))
if (isPopup && !(hasThickFrame && (hasCaption || hasMinimizeMaximizeButtons)))
{
// popup windows we want to snap: e.g. Calculator, Telegram
// popup windows we don't want to snap: start menu, notification popup, tray window, etc.

View File

@@ -121,11 +121,4 @@ namespace WindowUtils
return std::wstring(title);
}
inline bool HasThickFrame(HWND window)
{
auto style = GetWindowLong(window, GWL_STYLE);
return WindowUtils::HasStyle(style, WS_THICKFRAME);
}
}

View File

@@ -2,7 +2,6 @@
<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')" />
<Import Project="..\Microsoft.CmdPal.UI\CmdPal.pre.props" Condition="Exists('..\Microsoft.CmdPal.UI\CmdPal.pre.prop')" />
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
@@ -50,21 +49,13 @@
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>
EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;
%(PreprocessorDefinitions);
$(CommandPaletteBranding)
</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(CommandPaletteBranding)'=='' or '$(CommandPaletteBranding)'=='Dev'">
IS_DEV_BRANDING;%(PreprocessorDefinitions)
</PreprocessorDefinitions>
<PreprocessorDefinitions>EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />

View File

@@ -208,7 +208,7 @@ public:
try
{
std::wstring packageName = L"Microsoft.CommandPalette";
#ifdef IS_DEV_BRANDING
#ifdef _DEBUG
packageName = L"Microsoft.CommandPalette.Dev";
#endif
if (!package::GetRegisteredPackage(packageName, false).has_value())
@@ -245,21 +245,12 @@ public:
errorMessage += e.what();
Logger::error(errorMessage);
}
try
{
#ifdef IS_DEV_BRANDING
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App", L"RunFromPT", false);
#if _DEBUG
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette.Dev_8wekyb3d8bbwe!App", L"RunFromPT", false);
#else
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette_8wekyb3d8bbwe!App", L"RunFromPT", false);
LaunchApp(std::wstring{ L"shell:AppsFolder\\" } + L"Microsoft.CommandPalette_8wekyb3d8bbwe!App", L"RunFromPT", false);
#endif
}
catch (std::exception& e)
{
std::string errorMessage{ "Exception thrown while trying to launch CmdPal: " };
errorMessage += e.what();
Logger::error(errorMessage);
throw;
}
}
virtual void disable()

View File

@@ -9,7 +9,7 @@
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.7.250401001" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.6.250205002" />
<PackageVersion Include="Shmuelie.WinRTServer" Version="2.1.1" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<PackageVersion Include="System.Text.Json" Version="9.0.3" />

View File

@@ -4,14 +4,18 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.System;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class CommandBarViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
IRecipient<UpdateCommandBarMessage>,
IRecipient<UpdateItemKeybindingsMessage>
{
public ICommandBarContext? SelectedItem
{
@@ -25,8 +29,6 @@ public partial class CommandBarViewModel : ObservableObject,
field = value;
SetSelectedItem(value);
OnPropertyChanged(nameof(SelectedItem));
}
}
@@ -49,17 +51,20 @@ public partial class CommandBarViewModel : ObservableObject,
public partial PageViewModel? CurrentPage { get; set; }
[ObservableProperty]
public partial ObservableCollection<ContextMenuStackViewModel> ContextMenuStack { get; set; } = [];
public partial ObservableCollection<CommandContextItemViewModel> ContextCommands { get; set; } = [];
public ContextMenuStackViewModel? ContextMenu => ContextMenuStack.LastOrDefault();
private Dictionary<KeyChord, CommandContextItemViewModel>? _contextKeybindings;
public CommandBarViewModel()
{
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
}
public void Receive(UpdateCommandBarMessage message) => SelectedItem = message.ViewModel;
public void Receive(UpdateItemKeybindingsMessage message) => _contextKeybindings = message.Keys;
private void SetSelectedItem(ICommandBarContext? value)
{
if (value != null)
@@ -104,97 +109,53 @@ public partial class CommandBarViewModel : ObservableObject,
if (SelectedItem.MoreCommands.Count() > 1)
{
ShouldShowContextMenu = true;
ContextMenuStack.Clear();
ContextMenuStack.Add(new ContextMenuStackViewModel(SelectedItem));
OnPropertyChanged(nameof(ContextMenu));
ContextCommands = [.. SelectedItem.AllCommands];
}
else
{
ShouldShowContextMenu = false;
}
OnPropertyChanged(nameof(HasSecondaryCommand));
OnPropertyChanged(nameof(SecondaryCommand));
OnPropertyChanged(nameof(ShouldShowContextMenu));
}
// InvokeItemCommand is what this will be in Xaml due to source generator
// this comes in when an item in the list is tapped
// [RelayCommand]
public ContextKeybindingResult InvokeItem(CommandContextItemViewModel item) =>
PerformCommand(item);
[RelayCommand]
private void InvokeItem(CommandContextItemViewModel item) =>
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item.Command.Model, item.Model));
// this comes in when the primary button is tapped
public void InvokePrimaryCommand()
{
PerformCommand(SecondaryCommand);
if (PrimaryCommand != null)
{
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(PrimaryCommand.Command.Model, PrimaryCommand.Model));
}
}
// this comes in when the secondary button is tapped
public void InvokeSecondaryCommand()
{
PerformCommand(SecondaryCommand);
}
public ContextKeybindingResult CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
{
var matchedItem = ContextMenu?.CheckKeybinding(ctrl, alt, shift, win, key);
return matchedItem != null ? PerformCommand(matchedItem) : ContextKeybindingResult.Unhandled;
}
private ContextKeybindingResult PerformCommand(CommandItemViewModel? command)
{
if (command == null)
if (SecondaryCommand != null)
{
return ContextKeybindingResult.Unhandled;
}
if (command.HasMoreCommands)
{
ContextMenuStack.Add(new ContextMenuStackViewModel(command));
OnPropertyChanging(nameof(ContextMenu));
OnPropertyChanged(nameof(ContextMenu));
return ContextKeybindingResult.KeepOpen;
}
else
{
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(command.Command.Model, command.Model));
return ContextKeybindingResult.Hide;
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(SecondaryCommand.Command.Model, SecondaryCommand.Model));
}
}
public bool CanPopContextStack()
public bool CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
{
return ContextMenuStack.Count > 1;
}
public void PopContextStack()
{
if (ContextMenuStack.Count > 1)
if (_contextKeybindings != null)
{
ContextMenuStack.RemoveAt(ContextMenuStack.Count - 1);
// Does the pressed key match any of the keybindings?
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
if (_contextKeybindings.TryGetValue(pressedKeyChord, out var item))
{
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
// so that the correct item is activated.
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
return true;
}
}
OnPropertyChanging(nameof(ContextMenu));
OnPropertyChanged(nameof(ContextMenu));
}
public void ClearContextStack()
{
while (ContextMenuStack.Count > 1)
{
ContextMenuStack.RemoveAt(ContextMenuStack.Count - 1);
}
OnPropertyChanging(nameof(ContextMenu));
OnPropertyChanged(nameof(ContextMenu));
return false;
}
}
public enum ContextKeybindingResult
{
Unhandled,
Hide,
KeepOpen,
}

View File

@@ -48,7 +48,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
public List<CommandContextItemViewModel> MoreCommands { get; private set; } = [];
IEnumerable<CommandContextItemViewModel> IContextMenuContext.MoreCommands => MoreCommands;
IEnumerable<CommandContextItemViewModel> ICommandBarContext.MoreCommands => MoreCommands;
public bool HasMoreCommands => MoreCommands.Count > 0;
@@ -187,26 +187,23 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
// use Initialize straight up
MoreCommands.ForEach(contextItem =>
{
contextItem.SlowInitializeProperties();
contextItem.InitializeProperties();
});
if (!string.IsNullOrEmpty(model.Command.Name))
_defaultCommandContextItem = new(new CommandContextItem(model.Command!), PageContext)
{
_defaultCommandContextItem = new(new CommandContextItem(model.Command!), PageContext)
{
_itemTitle = Name,
Subtitle = Subtitle,
Command = Command,
_itemTitle = Name,
Subtitle = Subtitle,
Command = Command,
// TODO this probably should just be a CommandContextItemViewModel(CommandItemViewModel) ctor, or a copy ctor or whatever
};
// TODO this probably should just be a CommandContextItemViewModel(CommandItemViewModel) ctor, or a copy ctor or whatever
};
// Only set the icon on the context item for us if our command didn't
// have its own icon
if (!Command.HasIcon)
{
_defaultCommandContextItem._listItemIcon = _listItemIcon;
}
// Only set the icon on the context item for us if our command didn't
// have its own icon
if (!Command.HasIcon)
{
_defaultCommandContextItem._listItemIcon = _listItemIcon;
}
Initialized |= InitializedState.SelectionInitialized;
@@ -401,6 +398,23 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
base.SafeCleanup();
Initialized |= InitializedState.CleanedUp;
}
/// <summary>
/// Generates a mapping of key -> command item for this particular item's
/// MoreCommands. (This won't include the primary Command, but it will
/// include the secondary one). This map can be used to quickly check if a
/// shortcut key was pressed
/// </summary>
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
/// that have a shortcut key set.</returns>
internal Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
{
return MoreCommands
.Where(c => c.HasRequestedShortcut)
.ToDictionary(
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
c => c);
}
}
[Flags]

View File

@@ -167,7 +167,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
Commands.ForEach(contextItem =>
{
contextItem.SlowInitializeProperties();
contextItem.InitializeProperties();
});
}
else

View File

@@ -1,82 +0,0 @@
// 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.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.System;
namespace Microsoft.CmdPal.UI.ViewModels;
public partial class ContextMenuStackViewModel : ObservableObject
{
[ObservableProperty]
public partial ObservableCollection<CommandContextItemViewModel> FilteredItems { get; set; }
private readonly IContextMenuContext _context;
private string _lastSearchText = string.Empty;
// private Dictionary<KeyChord, CommandContextItemViewModel>? _contextKeybindings;
public ContextMenuStackViewModel(IContextMenuContext context)
{
_context = context;
FilteredItems = [.. context.AllCommands];
}
public void SetSearchText(string searchText)
{
if (searchText == _lastSearchText)
{
return;
}
_lastSearchText = searchText;
var commands = _context.AllCommands.Where(c => c.ShouldBeVisible);
if (string.IsNullOrEmpty(searchText))
{
ListHelpers.InPlaceUpdateList(FilteredItems, commands);
return;
}
var newResults = ListHelpers.FilterList<CommandContextItemViewModel>(commands, searchText, ScoreContextCommand);
ListHelpers.InPlaceUpdateList(FilteredItems, newResults);
}
private static int ScoreContextCommand(string query, CommandContextItemViewModel item)
{
if (string.IsNullOrEmpty(query) || string.IsNullOrWhiteSpace(query))
{
return 1;
}
if (string.IsNullOrEmpty(item.Title))
{
return 0;
}
var nameMatch = StringMatcher.FuzzySearch(query, item.Title);
var descriptionMatch = StringMatcher.FuzzySearch(query, item.Subtitle);
return new[] { nameMatch.Score, (descriptionMatch.Score - 4) / 2, 0 }.Max();
}
public CommandContextItemViewModel? CheckKeybinding(bool ctrl, bool alt, bool shift, bool win, VirtualKey key)
{
var keybindings = _context.Keybindings();
if (keybindings != null)
{
// Does the pressed key match any of the keybindings?
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrl, alt, shift, win, key, 0);
if (keybindings.TryGetValue(pressedKeyChord, out var item))
{
return item;
}
}
return null;
}
}

View File

@@ -344,6 +344,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
{
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(item));
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(item.Keybindings()));
if (ShowDetails && item.HasDetails)
{
WeakReferenceMessenger.Default.Send<ShowDetailsMessage>(new(item.Details));
@@ -434,7 +436,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
break;
case nameof(EmptyContent):
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent.SlowInitializeProperties();
EmptyContent.InitializeProperties();
break;
case nameof(IsLoading):
UpdateEmptyContent();
@@ -452,8 +454,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
return;
}
UpdateProperty(nameof(EmptyContent));
DoOnUiThread(
() =>
{

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
@@ -14,42 +13,22 @@ public record UpdateCommandBarMessage(ICommandBarContext? ViewModel)
{
}
public interface IContextMenuContext : INotifyPropertyChanged
{
public IEnumerable<CommandContextItemViewModel> MoreCommands { get; }
public bool HasMoreCommands { get; }
public List<CommandContextItemViewModel> AllCommands { get; }
/// <summary>
/// Generates a mapping of key -> command item for this particular item's
/// MoreCommands. (This won't include the primary Command, but it will
/// include the secondary one). This map can be used to quickly check if a
/// shortcut key was pressed
/// </summary>
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
/// that have a shortcut key set.</returns>
public Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
{
return MoreCommands
.Where(c => c.HasRequestedShortcut)
.ToDictionary(
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
c => c);
}
}
// Represents everything the command bar needs to know about to show command
// buttons at the bottom.
//
// This is implemented by both ListItemViewModel and ContentPageViewModel,
// the two things with sub-commands.
public interface ICommandBarContext : IContextMenuContext
public interface ICommandBarContext : INotifyPropertyChanged
{
public IEnumerable<CommandContextItemViewModel> MoreCommands { get; }
public bool HasMoreCommands { get; }
public string SecondaryCommandName { get; }
public CommandItemViewModel? PrimaryCommand { get; }
public CommandItemViewModel? SecondaryCommand { get; }
public List<CommandContextItemViewModel> AllCommands { get; }
}

View File

@@ -2,11 +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 Windows.System;
using Microsoft.CommandPalette.Extensions;
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
public record TryCommandKeybindingMessage(bool Ctrl, bool Alt, bool Shift, bool Win, VirtualKey Key)
{
public bool Handled { get; set; }
}
public record UpdateItemKeybindingsMessage(Dictionary<KeyChord, CommandContextItemViewModel>? Keys);

View File

@@ -40,8 +40,6 @@ public partial class SettingsModel : ObservableObject
public bool ShowSystemTrayIcon { get; set; } = true;
public bool IgnoreShortcutWhenFullscreen { get; set; } = true;
public Dictionary<string, ProviderSettings> ProviderSettings { get; set; } = [];
public Dictionary<string, CommandAlias> Aliases { get; set; } = [];

View File

@@ -108,16 +108,6 @@ public partial class SettingsViewModel : INotifyPropertyChanged
}
}
public bool IgnoreShortcutWhenFullscreen
{
get => _settings.IgnoreShortcutWhenFullscreen;
set
{
_settings.IgnoreShortcutWhenFullscreen = value;
Save();
}
}
public ObservableCollection<ProviderSettingsViewModel> CommandProviders { get; } = [];
public SettingsViewModel(SettingsModel settings, IServiceProvider serviceProvider, TaskScheduler scheduler)

View File

@@ -72,8 +72,8 @@
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid
@@ -133,8 +133,6 @@
VerticalAlignment="Center"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind CurrentPageViewModel.Title, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"
Visibility="{x:Bind CurrentPageViewModel.IsNested, Mode=OneWay}" />
<StackPanel
Grid.Column="2"
@@ -225,42 +223,27 @@
ToolTipService.ToolTip="Ctrl+K"
Visibility="{x:Bind ViewModel.ShouldShowContextMenu, Mode=OneWay}">
<Button.Flyout>
<Flyout
Closing="Flyout_Closing"
Opened="Flyout_Opened"
Placement="TopEdgeAlignedRight">
<StackPanel>
<ListView
x:Name="CommandsDropdown"
MinWidth="248"
Margin="-16,-12,-16,-12"
IsItemClickEnabled="True"
ItemClick="CommandsDropdown_ItemClick"
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
ItemsSource="{x:Bind ViewModel.ContextMenu.FilteredItems, Mode=OneWay}"
KeyDown="CommandsDropdown_KeyDown"
SelectionMode="Single">
<ListView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
<Setter Property="MinHeight" Value="0" />
<Setter Property="Padding" Value="12,7,12,7" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemContainerTransitions>
<TransitionCollection />
</ListView.ItemContainerTransitions>
</ListView>
<TextBox
x:Name="ContextFilterBox"
x:Uid="ContextFilterBox"
Margin="-12,12,-12,-12"
KeyDown="ContextFilterBox_KeyDown"
PreviewKeyDown="ContextFilterBox_PreviewKeyDown"
TextChanged="ContextFilterBox_TextChanged" />
</StackPanel>
<Flyout Placement="TopEdgeAlignedRight">
<ListView
x:Name="CommandsDropdown"
MinWidth="248"
Margin="-16,-12,-16,-12"
IsItemClickEnabled="True"
ItemClick="CommandsDropdown_ItemClick"
ItemTemplate="{StaticResource ContextMenuViewModelTemplate}"
ItemsSource="{x:Bind ViewModel.ContextCommands, Mode=OneWay}"
KeyDown="CommandsDropdown_KeyDown"
SelectionMode="None">
<ListView.ItemContainerStyle>
<Style BasedOn="{StaticResource DefaultListViewItemStyle}" TargetType="ListViewItem">
<Setter Property="MinHeight" Value="0" />
<Setter Property="Padding" Value="12,7,12,7" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemContainerTransitions>
<TransitionCollection />
</ListView.ItemContainerTransitions>
</ListView>
</Flyout>
</Button.Flyout>
</Button>

View File

@@ -18,10 +18,9 @@ namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class CommandBar : UserControl,
IRecipient<OpenContextMenuMessage>,
IRecipient<TryCommandKeybindingMessage>,
ICurrentPageAware
{
public CommandBarViewModel ViewModel { get; } = new();
public CommandBarViewModel ViewModel { get; set; } = new();
public PageViewModel? CurrentPageViewModel
{
@@ -39,9 +38,6 @@ public sealed partial class CommandBar : UserControl,
// RegisterAll isn't AOT compatible
WeakReferenceMessenger.Default.Register<OpenContextMenuMessage>(this);
WeakReferenceMessenger.Default.Register<TryCommandKeybindingMessage>(this);
ViewModel.PropertyChanged += ViewModel_PropertyChanged;
}
public void Receive(OpenContextMenuMessage message)
@@ -56,41 +52,8 @@ public sealed partial class CommandBar : UserControl,
ShowMode = FlyoutShowMode.Standard,
};
MoreCommandsButton.Flyout.ShowAt(MoreCommandsButton, options);
UpdateUiForStackChange();
}
public void Receive(TryCommandKeybindingMessage msg)
{
if (!ViewModel.ShouldShowContextMenu)
{
return;
}
var result = ViewModel?.CheckKeybinding(msg.Ctrl, msg.Alt, msg.Shift, msg.Win, msg.Key);
if (result == ContextKeybindingResult.Hide)
{
msg.Handled = true;
}
else if (result == ContextKeybindingResult.KeepOpen)
{
if (!MoreCommandsButton.Flyout.IsOpen)
{
var options = new FlyoutShowOptions
{
ShowMode = FlyoutShowMode.Standard,
};
MoreCommandsButton.Flyout.ShowAt(MoreCommandsButton, options);
}
UpdateUiForStackChange();
msg.Handled = true;
}
else if (result == ContextKeybindingResult.Unhandled)
{
msg.Handled = false;
}
CommandsDropdown.SelectedIndex = 0;
CommandsDropdown.Focus(FocusState.Programmatic);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "VS has a tendency to delete XAML bound methods over-aggressively")]
@@ -125,14 +88,8 @@ public sealed partial class CommandBar : UserControl,
{
if (e.ClickedItem is CommandContextItemViewModel item)
{
if (ViewModel?.InvokeItem(item) == ContextKeybindingResult.Hide)
{
MoreCommandsButton.Flyout.Hide();
}
else
{
UpdateUiForStackChange();
}
ViewModel?.InvokeItemCommand.Execute(item);
MoreCommandsButton.Flyout.Hide();
}
}
@@ -149,136 +106,9 @@ public sealed partial class CommandBar : UserControl,
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
var result = ViewModel?.CheckKeybinding(ctrlPressed, altPressed, shiftPressed, winPressed, e.Key);
if (result == ContextKeybindingResult.Hide)
{
e.Handled = true;
MoreCommandsButton.Flyout.Hide();
WeakReferenceMessenger.Default.Send<FocusSearchBoxMessage>();
}
else if (result == ContextKeybindingResult.KeepOpen)
if (ViewModel?.CheckKeybinding(ctrlPressed, altPressed, shiftPressed, winPressed, e.Key) ?? false)
{
e.Handled = true;
}
else if (result == ContextKeybindingResult.Unhandled)
{
e.Handled = false;
}
}
private void Flyout_Opened(object sender, object e)
{
UpdateUiForStackChange();
}
private void Flyout_Closing(FlyoutBase sender, FlyoutBaseClosingEventArgs args)
{
ViewModel?.ClearContextStack();
WeakReferenceMessenger.Default.Send<FocusSearchBoxMessage>();
}
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var prop = e.PropertyName;
if (prop == nameof(ViewModel.ContextMenu))
{
UpdateUiForStackChange();
}
}
private void ContextFilterBox_TextChanged(object sender, TextChangedEventArgs e)
{
ViewModel.ContextMenu?.SetSearchText(ContextFilterBox.Text);
if (CommandsDropdown.SelectedIndex == -1)
{
CommandsDropdown.SelectedIndex = 0;
}
}
private void ContextFilterBox_KeyDown(object sender, KeyRoutedEventArgs e)
{
var ctrlPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
var altPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Menu).HasFlag(CoreVirtualKeyStates.Down);
var shiftPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
var winPressed = InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.LeftWindows).HasFlag(CoreVirtualKeyStates.Down) ||
InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.RightWindows).HasFlag(CoreVirtualKeyStates.Down);
if (e.Key == VirtualKey.Enter)
{
if (CommandsDropdown.SelectedItem is CommandContextItemViewModel item)
{
if (ViewModel?.InvokeItem(item) == ContextKeybindingResult.Hide)
{
MoreCommandsButton.Flyout.Hide();
WeakReferenceMessenger.Default.Send<FocusSearchBoxMessage>();
}
else
{
UpdateUiForStackChange();
}
e.Handled = true;
}
}
else if (e.Key == VirtualKey.Escape ||
(e.Key == VirtualKey.Left && altPressed))
{
if (ViewModel.CanPopContextStack())
{
ViewModel.PopContextStack();
UpdateUiForStackChange();
}
else
{
MoreCommandsButton.Flyout.Hide();
WeakReferenceMessenger.Default.Send<FocusSearchBoxMessage>();
}
e.Handled = true;
}
CommandsDropdown_KeyDown(sender, e);
}
private void ContextFilterBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Up)
{
// navigate previous
if (CommandsDropdown.SelectedIndex > 0)
{
CommandsDropdown.SelectedIndex--;
}
else
{
CommandsDropdown.SelectedIndex = CommandsDropdown.Items.Count - 1;
}
e.Handled = true;
}
else if (e.Key == VirtualKey.Down)
{
// navigate next
if (CommandsDropdown.SelectedIndex < CommandsDropdown.Items.Count - 1)
{
CommandsDropdown.SelectedIndex++;
}
else
{
CommandsDropdown.SelectedIndex = 0;
}
e.Handled = true;
}
}
private void UpdateUiForStackChange()
{
ContextFilterBox.Text = string.Empty;
ViewModel.ContextMenu?.SetSearchText(string.Empty);
CommandsDropdown.SelectedIndex = 0;
ContextFilterBox.Focus(FocusState.Programmatic);
}
}

View File

@@ -8,6 +8,8 @@ using CommunityToolkit.WinUI;
using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CmdPal.UI.Views;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
@@ -21,6 +23,7 @@ namespace Microsoft.CmdPal.UI.Controls;
public sealed partial class SearchBar : UserControl,
IRecipient<GoHomeMessage>,
IRecipient<FocusSearchBoxMessage>,
IRecipient<UpdateItemKeybindingsMessage>,
ICurrentPageAware
{
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
@@ -31,6 +34,8 @@ public sealed partial class SearchBar : UserControl,
private readonly DispatcherQueueTimer _debounceTimer = DispatcherQueue.GetForCurrentThread().CreateTimer();
private bool _isBackspaceHeld;
private Dictionary<KeyChord, CommandContextItemViewModel>? _keyBindings;
public PageViewModel? CurrentPageViewModel
{
get => (PageViewModel?)GetValue(CurrentPageViewModelProperty);
@@ -69,6 +74,7 @@ public sealed partial class SearchBar : UserControl,
this.InitializeComponent();
WeakReferenceMessenger.Default.Register<GoHomeMessage>(this);
WeakReferenceMessenger.Default.Register<FocusSearchBoxMessage>(this);
WeakReferenceMessenger.Default.Register<UpdateItemKeybindingsMessage>(this);
}
public void ClearSearch()
@@ -167,14 +173,17 @@ public sealed partial class SearchBar : UserControl,
WeakReferenceMessenger.Default.Send<NavigateBackMessage>(new());
}
if (!e.Handled)
if (_keyBindings != null)
{
// The CommandBar is responsible for handling all the item keybindings,
// since the bound context item may need to then show another
// context menu
TryCommandKeybindingMessage msg = new(ctrlPressed, altPressed, shiftPressed, winPressed, e.Key);
WeakReferenceMessenger.Default.Send(msg);
e.Handled = msg.Handled;
// Does the pressed key match any of the keybindings?
var pressedKeyChord = KeyChordHelpers.FromModifiers(ctrlPressed, altPressed, shiftPressed, winPressed, (int)e.Key, 0);
if (_keyBindings.TryGetValue(pressedKeyChord, out var item))
{
// TODO GH #245: This is a bit of a hack, but we need to make sure that the keybindings are updated before we send the message
// so that the correct item is activated.
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(item));
e.Handled = true;
}
}
}
@@ -293,5 +302,10 @@ public sealed partial class SearchBar : UserControl,
public void Receive(GoHomeMessage message) => ClearSearch();
public void Receive(FocusSearchBoxMessage message) => FilterBox.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
public void Receive(FocusSearchBoxMessage message) => this.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
public void Receive(UpdateItemKeybindingsMessage message)
{
_keyBindings = message.Keys;
}
}

View File

@@ -138,15 +138,14 @@
</controls:Case>
<controls:Case Value="True">
<StackPanel
Margin="24"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical"
Spacing="4">
<cpcontrols:IconBox
x:Name="IconBorder"
Width="48"
Height="48"
Width="56"
Height="56"
Margin="8"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
SourceKey="{x:Bind ViewModel.EmptyContent.Icon, Mode=OneWay}"
@@ -155,15 +154,11 @@
Margin="0,4,0,0"
HorizontalAlignment="Center"
FontWeight="SemiBold"
Text="{x:Bind ViewModel.EmptyContent.Title, Mode=OneWay}"
TextAlignment="Center"
TextWrapping="Wrap" />
Text="{x:Bind ViewModel.EmptyContent.Title, Mode=OneWay}" />
<TextBlock
HorizontalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind ViewModel.EmptyContent.Subtitle, Mode=OneWay}"
TextAlignment="Center"
TextWrapping="Wrap" />
Text="{x:Bind ViewModel.EmptyContent.Subtitle, Mode=OneWay}" />
</StackPanel>
</controls:Case>
</controls:SwitchPresenter>

View File

@@ -1,26 +0,0 @@
// 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.Runtime.InteropServices;
using System.Security;
namespace Microsoft.CmdPal.UI.Helpers;
[SuppressUnmanagedCodeSecurity]
internal static class NativeMethods
{
[DllImport("shell32.dll")]
public static extern int SHQueryUserNotificationState(out UserNotificationState state);
}
internal enum UserNotificationState : int
{
QUNS_NOT_PRESENT = 1,
QUNS_BUSY,
QUNS_RUNNING_D3D_FULL_SCREEN,
QUNS_PRESENTATION_MODE,
QUNS_ACCEPTS_NOTIFICATIONS,
QUNS_QUIET_TIME,
QUNS_APP,
}

View File

@@ -1,28 +0,0 @@
// 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.Runtime.InteropServices;
namespace Microsoft.CmdPal.UI.Helpers;
internal sealed partial class WindowHelper
{
public static bool IsWindowFullscreen()
{
UserNotificationState state;
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ne-shellapi-query_user_notification_state
if (Marshal.GetExceptionForHR(NativeMethods.SHQueryUserNotificationState(out state)) == null)
{
if (state == UserNotificationState.QUNS_RUNNING_D3D_FULL_SCREEN ||
state == UserNotificationState.QUNS_BUSY ||
state == UserNotificationState.QUNS_PRESENTATION_MODE)
{
return true;
}
}
return false;
}
}

View File

@@ -43,7 +43,6 @@ public sealed partial class MainWindow : Window,
private readonly WNDPROC? _hotkeyWndProc;
private readonly WNDPROC? _originalWndProc;
private readonly List<TopLevelHotkey> _hotkeys = [];
private bool _ignoreHotKeyWhenFullScreen = true;
// Stylistically, window messages are WM_*
#pragma warning disable SA1310 // Field names should not contain underscore
@@ -158,8 +157,6 @@ public sealed partial class MainWindow : Window,
SetupHotkey(settings);
SetupTrayIcon(settings.ShowSystemTrayIcon);
_ignoreHotKeyWhenFullScreen = settings.IgnoreShortcutWhenFullscreen;
// This will prevent our window from appearing in alt+tab or the taskbar.
// You'll _need_ to use the hotkey to summon it.
AppWindow.IsShownInSwitchers = System.Diagnostics.Debugger.IsAttached;
@@ -507,15 +504,6 @@ public sealed partial class MainWindow : Window,
var hotkeyIndex = (int)wParam.Value;
if (hotkeyIndex < _hotkeys.Count)
{
if (_ignoreHotKeyWhenFullScreen)
{
// If we're in full screen mode, ignore the hotkey
if (WindowHelper.IsWindowFullscreen())
{
return (LRESULT)IntPtr.Zero;
}
}
var hotkey = _hotkeys[hotkeyIndex];
HandleSummon(hotkey.CommandId);

View File

@@ -356,8 +356,9 @@
<cpcontrols:IconBox
x:Name="HeroImageBorder"
Width="64"
Margin="16,8,16,16"
MinWidth="64"
MinHeight="64"
MaxHeight="96"
HorizontalAlignment="Center"
AutomationProperties.AccessibilityView="Raw"
SourceKey="{x:Bind ViewModel.Details.HeroImage, Mode=OneWay}"
@@ -367,10 +368,8 @@
<TextBlock
Grid.Row="1"
HorizontalAlignment="Center"
FontSize="18"
FontWeight="SemiBold"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{x:Bind ViewModel.Details.Title, Mode=OneWay}"
TextAlignment="Center"
TextWrapping="WrapWholeWords"
Visibility="{x:Bind ViewModel.Details.Title, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}" />

View File

@@ -187,6 +187,8 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
WeakReferenceMessenger.Default.Send<UpdateCommandBarMessage>(new(null));
WeakReferenceMessenger.Default.Send<UpdateItemKeybindingsMessage>(new(null));
var isMainPage = command is MainListPage;
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.

View File

@@ -48,9 +48,6 @@
</controls:SettingsCard>
</controls:SettingsExpander.Items>
</controls:SettingsExpander>
<controls:SettingsCard x:Uid="Settings_GeneralPage_IgnoreShortcutWhenFullscreen_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=&#xE7FC;}">
<ToggleSwitch IsOn="{x:Bind viewModel.IgnoreShortcutWhenFullscreen, Mode=TwoWay}" />
</controls:SettingsCard>
<controls:SettingsCard x:Uid="Settings_GeneralPage_GoHome_SettingsCard" HeaderIcon="{ui:FontIcon Glyph=&#xE80F;}">
<ToggleSwitch IsOn="{x:Bind viewModel.HotkeyGoesHome, Mode=TwoWay}" />
</controls:SettingsCard>

View File

@@ -328,12 +328,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
<data name="Settings_GeneralPage_LowLevelHook_SettingsCard.Description" xml:space="preserve">
<value>Try this if there are issues with the shortcut (Command Palette might not get focus when triggered from an elevated window)</value>
</data>
<data name="Settings_GeneralPage_IgnoreShortcutWhenFullscreen_SettingsCard.Header" xml:space="preserve">
<value>Ignore shortcut in fullscreen mode</value>
</data>
<data name="Settings_GeneralPage_IgnoreShortcutWhenFullscreen_SettingsCard.Description" xml:space="preserve">
<value>Preventing disruption of the program running in fullscreen by unintentional activation of shortcut</value>
</data>
<data name="Settings_GeneralPage_GoHome_SettingsCard.Header" xml:space="preserve">
<value>Go home when activated</value>
</data>
@@ -394,9 +388,6 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
<data name="BehaviorSettingsHeader.Text" xml:space="preserve">
<value>Behavior</value>
</data>
<data name="ContextFilterBox.PlaceholderText" xml:space="preserve">
<value>Search commands...</value>
</data>
<data name="Settings_GeneralPage_ShowSystemTrayIcon_SettingsCard.Header" xml:space="preserve">
<value>Show system tray icon</value>
</data>

View File

@@ -3,7 +3,7 @@
<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>
<PathToRoot>..\..\..\..\</PathToRoot>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250401001</WasdkNuget>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.6.250205002</WasdkNuget>
</PropertyGroup>
<Import Project="$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('$(WasdkNuget)\build\native\Microsoft.WindowsAppSDK.props')" />
<PropertyGroup Label="Globals">

View File

@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.Calc</RootNamespace>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>

View File

@@ -1,7 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.Registry</RootNamespace>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>

View File

@@ -1,7 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.CmdPal.Ext.Shell</RootNamespace>

View File

@@ -1,104 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using Microsoft.CmdPal.Ext.TimeDate.Helpers;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace Microsoft.CmdPal.Ext.TimeDate;
internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
{
private readonly HashSet<string> _validOptions;
private SettingsManager _settingsManager;
public FallbackTimeDateItem(SettingsManager settings)
: base(new NoOpCommand(), Resources.Microsoft_plugin_timedate_fallback_display_title)
{
Title = string.Empty;
Subtitle = string.Empty;
_settingsManager = settings;
_validOptions = new(StringComparer.OrdinalIgnoreCase)
{
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagDate", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagDateNow", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagTime", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagTimeNow", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagFormat", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagFormatNow", CultureInfo.CurrentCulture),
Resources.ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagWeek", CultureInfo.CurrentCulture),
};
}
public override void UpdateQuery(string query)
{
if (!_settingsManager.EnableFallbackItems || string.IsNullOrWhiteSpace(query) || !IsValidQuery(query))
{
Title = string.Empty;
Subtitle = string.Empty;
Command = new NoOpCommand();
return;
}
var availableResults = AvailableResultsList.GetList(false, _settingsManager);
ListItem result = null;
var maxScore = 0;
foreach (var f in availableResults)
{
var score = f.Score(query, f.Label, f.AlternativeSearchTag);
if (score > maxScore)
{
maxScore = score;
result = f.ToListItem();
}
}
if (result != null)
{
Title = result.Title;
Subtitle = result.Subtitle;
Icon = result.Icon;
}
else
{
Title = string.Empty;
Subtitle = string.Empty;
Command = new NoOpCommand();
}
}
private bool IsValidQuery(string query)
{
if (_validOptions.Contains(query))
{
return true;
}
foreach (var option in _validOptions)
{
if (option == null)
{
continue;
}
var parts = option.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
if (parts.Any(part => string.Equals(part, query, StringComparison.OrdinalIgnoreCase)))
{
return true;
}
}
return false;
}
}

View File

@@ -33,7 +33,6 @@ internal static class AvailableResultsList
var dateTimeNowUtc = dateTimeNow.ToUniversalTime();
var firstWeekRule = firstWeekOfYear ?? TimeAndDateHelper.GetCalendarWeekRule(settings.FirstWeekOfYear);
var firstDayOfTheWeek = firstDayOfWeek ?? TimeAndDateHelper.GetFirstDayOfWeek(settings.FirstDayOfWeek);
var weekOfYear = calendar.GetWeekOfYear(dateTimeNow, firstWeekRule, firstDayOfTheWeek);
results.AddRange(new[]
{
@@ -60,20 +59,14 @@ internal static class AvailableResultsList
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
IconType = ResultIconType.DateTime,
},
new AvailableResult()
{
Value = weekOfYear.ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_WeekOfYear,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
});
if (isKeywordSearch)
if (isKeywordSearch || !settings.OnlyDateTimeNowGlobal)
{
// We use long instead of int for unix time stamp because int is too small after 03:14:07 UTC 2038-01-19
var unixTimestamp = ((DateTimeOffset)dateTimeNowUtc).ToUnixTimeSeconds();
var unixTimestampMilliseconds = ((DateTimeOffset)dateTimeNowUtc).ToUnixTimeMilliseconds();
var weekOfYear = calendar.GetWeekOfYear(dateTimeNow, firstWeekRule, firstDayOfTheWeek);
var era = DateTimeFormatInfo.CurrentInfo.GetEraName(calendar.GetEra(dateTimeNow));
var eraShort = DateTimeFormatInfo.CurrentInfo.GetAbbreviatedEraName(calendar.GetEra(dateTimeNow));
@@ -258,6 +251,13 @@ internal static class AvailableResultsList
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = weekOfYear.ToString(CultureInfo.CurrentCulture),
Label = Resources.Microsoft_plugin_timedate_WeekOfYear,
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"),
IconType = ResultIconType.Date,
},
new AvailableResult()
{
Value = DateTimeFormatInfo.CurrentInfo.GetMonthName(dateTimeNow.Month),
Label = Resources.Microsoft_plugin_timedate_Month,

View File

@@ -75,11 +75,11 @@ public class SettingsManager : JsonSettingsManager
Resources.Microsoft_plugin_timedate_SettingFirstDayOfWeek,
_firstDayOfWeekChoices);
private readonly ToggleSetting _enableFallbackItems = new(
Namespaced(nameof(EnableFallbackItems)),
Resources.Microsoft_plugin_timedate_SettingEnableFallbackItems,
Resources.Microsoft_plugin_timedate_SettingEnableFallbackItems_Description,
true);
private readonly ToggleSetting _onlyDateTimeNowGlobal = new(
Namespaced(nameof(OnlyDateTimeNowGlobal)),
Resources.Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal,
Resources.Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal_Description,
true); // TODO -- double check default value
private readonly ToggleSetting _timeWithSeconds = new(
Namespaced(nameof(TimeWithSecond)),
@@ -93,6 +93,12 @@ public class SettingsManager : JsonSettingsManager
Resources.Microsoft_plugin_timedate_SettingDateWithWeekday_Description,
false); // TODO -- double check default value
private readonly ToggleSetting _hideNumberMessageOnGlobalQuery = new(
Namespaced(nameof(HideNumberMessageOnGlobalQuery)),
Resources.Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery,
Resources.Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery,
true); // TODO -- double check default value
private readonly TextSetting _customFormats = new(
Namespaced(nameof(CustomFormats)),
Resources.Microsoft_plugin_timedate_Setting_CustomFormats,
@@ -139,12 +145,14 @@ public class SettingsManager : JsonSettingsManager
}
}
public bool EnableFallbackItems => _enableFallbackItems.Value;
public bool OnlyDateTimeNowGlobal => _onlyDateTimeNowGlobal.Value;
public bool TimeWithSecond => _timeWithSeconds.Value;
public bool DateWithWeekday => _dateWithWeekday.Value;
public bool HideNumberMessageOnGlobalQuery => _hideNumberMessageOnGlobalQuery.Value;
public List<string> CustomFormats => _customFormats.Value.Split(TEXTBOXNEWLINE).ToList();
internal static string SettingsJsonPath()
@@ -160,7 +168,10 @@ public class SettingsManager : JsonSettingsManager
{
FilePath = SettingsJsonPath();
Settings.Add(_enableFallbackItems);
/* The following two settings make no sense with current CmdPal behavior.
Settings.Add(_onlyDateTimeNowGlobal);
Settings.Add(_hideNumberMessageOnGlobalQuery); */
Settings.Add(_timeWithSeconds);
Settings.Add(_dateWithWeekday);
Settings.Add(_firstWeekOfYear);

View File

@@ -40,7 +40,7 @@ public sealed partial class TimeDateCalculator
var lastInputParsingErrorMsg = string.Empty;
// Switch search type
if (isEmptySearchInput || (!isKeywordSearch))
if (isEmptySearchInput || (!isKeywordSearch && settings.OnlyDateTimeNowGlobal))
{
// Return all results for system time/date on empty keyword search
// or only time, date and now results for system time on global queries if the corresponding setting is enabled
@@ -91,6 +91,23 @@ public sealed partial class TimeDateCalculator
}
}
/*htcfreek:Code obsolete with current CmdPal behavior.
// If search term is only a number that can't be parsed return an error message
if (!isEmptySearchInput && results.Count == 0 && Regex.IsMatch(query, @"\w+\d+.*$") && !query.Any(char.IsWhiteSpace) && (TimeAndDateHelper.IsSpecialInputParsing(query) || !Regex.IsMatch(query, @"\d+[\.:/]\d+")))
{
// Without plugin key word show only if message is not hidden by setting
if (!settings.HideNumberMessageOnGlobalQuery)
{
var er = ResultHelper.CreateInvalidInputErrorResult();
if (!string.IsNullOrEmpty(lastInputParsingErrorMsg))
{
er.Details = new Details() { Body = lastInputParsingErrorMsg };
}
results.Add(er);
}
} */
if (results.Count == 0)
{
var er = ResultHelper.CreateInvalidInputErrorResult();

View File

@@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<Import Project="..\..\Microsoft.CmdPal.UI\CmdPal.pre.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.TimeDate</RootNamespace>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>

View File

@@ -213,15 +213,6 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
}
}
/// <summary>
/// Looks up a localized string similar to Open Time Data Command.
/// </summary>
public static string Microsoft_plugin_timedate_fallback_display_title {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_fallback_display_title", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Date and time in filename-compatible format.
/// </summary>
@@ -618,15 +609,6 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
}
}
/// <summary>
/// Looks up a localized string similar to Current Week; Calendar week; Week of the year; Week.
/// </summary>
public static string Microsoft_plugin_timedate_SearchTagWeek {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SearchTagWeek", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Second.
/// </summary>
@@ -681,24 +663,6 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
}
}
/// <summary>
/// Looks up a localized string similar to Enable fallback items for TimeDate (week, year, now, time, date).
/// </summary>
public static string Microsoft_plugin_timedate_SettingEnableFallbackItems {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SettingEnableFallbackItems", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show time and date results when typing keywords like &quot;week&quot;, &quot;year&quot;, &quot;now&quot;, &quot;time&quot;, or &quot;date&quot;.
/// </summary>
public static string Microsoft_plugin_timedate_SettingEnableFallbackItems_Description {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SettingEnableFallbackItems_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to First day of the week.
/// </summary>
@@ -816,6 +780,33 @@ namespace Microsoft.CmdPal.Ext.TimeDate {
}
}
/// <summary>
/// Looks up a localized string similar to Hide &apos;Invalid number input&apos; error message on global queries.
/// </summary>
public static string Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show only &apos;Time&apos;, &apos;Date&apos; and &apos;Now&apos; result for system time on global queries.
/// </summary>
public static string Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Regardless of this setting, for global queries the first word of the query has to be a complete match..
/// </summary>
public static string Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal_Description {
get {
return ResourceManager.GetString("Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal_Description", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Show time with seconds.
/// </summary>

View File

@@ -265,6 +265,15 @@
<data name="Microsoft_plugin_timedate_SettingDateWithWeekday_Description" xml:space="preserve">
<value>This setting applies to the 'Date' and 'Now' result.</value>
</data>
<data name="Microsoft_plugin_timedate_SettingHideNumberMessageOnGlobalQuery" xml:space="preserve">
<value>Hide 'Invalid number input' error message on global queries</value>
</data>
<data name="Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal" xml:space="preserve">
<value>Show only 'Time', 'Date' and 'Now' result for system time on global queries</value>
</data>
<data name="Microsoft_plugin_timedate_SettingOnlyDateTimeNowGlobal_Description" xml:space="preserve">
<value>Regardless of this setting, for global queries the first word of the query has to be a complete match.</value>
</data>
<data name="Microsoft_plugin_timedate_SettingTimeWithSeconds" xml:space="preserve">
<value>Show time with seconds</value>
</data>
@@ -424,16 +433,4 @@
<data name="Microsoft_plugin_timedate_DaysInMonth" xml:space="preserve">
<value>Days in month</value>
</data>
<data name="Microsoft_plugin_timedate_fallback_display_title" xml:space="preserve">
<value>Open Time Data Command</value>
</data>
<data name="Microsoft_plugin_timedate_SearchTagWeek" xml:space="preserve">
<value>Current Week; Calendar week; Week of the year; Week</value>
</data>
<data name="Microsoft_plugin_timedate_SettingEnableFallbackItems" xml:space="preserve">
<value>Enable fallback items for TimeDate (week, year, now, time, date)</value>
</data>
<data name="Microsoft_plugin_timedate_SettingEnableFallbackItems_Description" xml:space="preserve">
<value>Show time and date results when typing keywords like "week", "year", "now", "time", or "date"</value>
</data>
</root>

View File

@@ -18,7 +18,6 @@ public partial class TimeDateCommandsProvider : CommandProvider
private static readonly SettingsManager _settingsManager = new();
private static readonly CompositeFormat MicrosoftPluginTimedatePluginDescription = System.Text.CompositeFormat.Parse(Resources.Microsoft_plugin_timedate_plugin_description);
private static readonly TimeDateExtensionPage _timeDateExtensionPage = new(_settingsManager);
private readonly FallbackTimeDateItem _fallbackTimeDateItem = new(_settingsManager);
public TimeDateCommandsProvider()
{
@@ -46,6 +45,4 @@ public partial class TimeDateCommandsProvider : CommandProvider
}
public override ICommandItem[] TopLevelCommands() => [_command];
public override IFallbackCommandItem[] FallbackCommands() => [_fallbackTimeDateItem];
}

View File

@@ -22,12 +22,10 @@ public partial class InstallPackageCommand : InvokableCommand
private IAsyncOperationWithProgress<UninstallResult, UninstallProgress>? _unInstallAction;
private Task? _installTask;
public PackageInstallCommandState InstallCommandState { get; private set; }
public bool IsInstalled { get; private set; }
public static IconInfo CompletedIcon { get; } = new("\uE930"); // Completed
public static IconInfo UpdateIcon { get; } = new("\uE74A"); // Up
public static IconInfo DownloadIcon { get; } = new("\uE896"); // Download
public static IconInfo DeleteIcon { get; } = new("\uE74D"); // Delete
@@ -46,41 +44,23 @@ public partial class InstallPackageCommand : InvokableCommand
internal bool SkipDependencies { get; set; }
public InstallPackageCommand(CatalogPackage package, PackageInstallCommandState isInstalled)
public InstallPackageCommand(CatalogPackage package, bool isInstalled)
{
_package = package;
InstallCommandState = isInstalled;
IsInstalled = isInstalled;
UpdateAppearance();
}
internal void FakeChangeStatus()
{
InstallCommandState = InstallCommandState switch
{
PackageInstallCommandState.Install => PackageInstallCommandState.Uninstall,
PackageInstallCommandState.Update => PackageInstallCommandState.Uninstall,
PackageInstallCommandState.Uninstall => PackageInstallCommandState.Install,
_ => throw new NotImplementedException(),
};
IsInstalled = !IsInstalled;
UpdateAppearance();
}
private void UpdateAppearance()
{
Icon = InstallCommandState switch
{
PackageInstallCommandState.Install => DownloadIcon,
PackageInstallCommandState.Update => UpdateIcon,
PackageInstallCommandState.Uninstall => CompletedIcon,
_ => throw new NotImplementedException(),
};
Name = InstallCommandState switch
{
PackageInstallCommandState.Install => Properties.Resources.winget_install_name,
PackageInstallCommandState.Update => Properties.Resources.winget_update_name,
PackageInstallCommandState.Uninstall => Properties.Resources.winget_uninstall_name,
_ => throw new NotImplementedException(),
};
Icon = IsInstalled ? CompletedIcon : DownloadIcon;
Name = IsInstalled ? Properties.Resources.winget_uninstall_name : Properties.Resources.winget_install_name;
}
public override ICommandResult Invoke()
@@ -92,7 +72,7 @@ public partial class InstallPackageCommand : InvokableCommand
return CommandResult.KeepOpen();
}
if (InstallCommandState == PackageInstallCommandState.Uninstall)
if (IsInstalled)
{
// Uninstall
_installBanner.State = MessageState.Info;
@@ -108,8 +88,7 @@ public partial class InstallPackageCommand : InvokableCommand
_installTask = Task.Run(() => TryDoInstallOperation(_unInstallAction));
}
else if (InstallCommandState is PackageInstallCommandState.Install or
PackageInstallCommandState.Update)
else
{
// Install
_installBanner.State = MessageState.Info;
@@ -138,8 +117,7 @@ public partial class InstallPackageCommand : InvokableCommand
try
{
await action.AsTask();
_installBanner.Message = InstallCommandState == PackageInstallCommandState.Uninstall ?
_installBanner.Message = IsInstalled ?
string.Format(CultureInfo.CurrentCulture, UninstallPackageFinished, _package.Name) :
string.Format(CultureInfo.CurrentCulture, InstallPackageFinished, _package.Name);
@@ -147,10 +125,9 @@ public partial class InstallPackageCommand : InvokableCommand
_installBanner.State = MessageState.Success;
_installTask = null;
_ = Task.Run(async () =>
_ = Task.Run(() =>
{
await Task.Delay(2500).ConfigureAwait(false);
Thread.Sleep(2500);
if (_installTask == null)
{
WinGetExtensionHost.Instance.HideStatus(_installBanner);
@@ -251,10 +228,3 @@ public partial class InstallPackageCommand : InvokableCommand
}
}
}
public enum PackageInstallCommandState
{
Uninstall = 0,
Update = 1,
Install = 2,
}

View File

@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.CommandPalette.Extensions;
@@ -32,7 +31,7 @@ public partial class InstallPackageListItem : ListItem
{
_package = package;
var version = _package.DefaultInstallVersion ?? _package.InstalledVersion;
var version = _package.DefaultInstallVersion;
var versionTagText = "Unknown";
if (version != null)
{
@@ -50,16 +49,7 @@ public partial class InstallPackageListItem : ListItem
private Details? BuildDetails(PackageVersionInfo? version)
{
CatalogPackageMetadata? metadata = null;
try
{
metadata = version?.GetCatalogPackageMetadata();
}
catch (COMException ex)
{
Logger.LogWarning($"{ex.ErrorCode}");
}
var metadata = version?.GetCatalogPackageMetadata();
if (metadata != null)
{
if (metadata.Tags.Where(t => t.Equals(WinGetExtensionPage.ExtensionsTag, StringComparison.OrdinalIgnoreCase)).Any())
@@ -159,17 +149,12 @@ public partial class InstallPackageListItem : ListItem
var status = await _package.CheckInstalledStatusAsync();
var isInstalled = _package.InstalledVersion != null;
var installedState = isInstalled ?
(_package.IsUpdateAvailable ?
PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
PackageInstallCommandState.Install;
// might be an uninstall command
InstallPackageCommand installCommand = new(_package, installedState);
InstallPackageCommand installCommand = new(_package, isInstalled);
if (isInstalled)
{
this.Icon = installCommand.Icon;
this.Icon = InstallPackageCommand.CompletedIcon;
this.Command = new NoOpCommand();
List<IContextItem> contextMenu = [];
CommandContextItem uninstallContextItem = new(installCommand)
@@ -195,7 +180,7 @@ public partial class InstallPackageListItem : ListItem
}
// didn't find the app
_installCommand = new InstallPackageCommand(_package, installedState);
_installCommand = new InstallPackageCommand(_package, isInstalled);
this.Command = _installCommand;
Icon = _installCommand.Icon;

View File

@@ -330,15 +330,6 @@ namespace Microsoft.CmdPal.Ext.WinGet.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Update.
/// </summary>
public static string winget_update_name {
get {
return ResourceManager.GetString("winget_update_name", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to View online.
/// </summary>

View File

@@ -154,10 +154,6 @@
<value>Install</value>
<comment></comment>
</data>
<data name="winget_update_name" xml:space="preserve">
<value>Update</value>
<comment></comment>
</data>
<data name="winget_uninstalling_package" xml:space="preserve">
<value>Uninstalling {0}...</value>
<comment>{0} will be replaced by the name of an app package</comment>

View File

@@ -1,7 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<Nullable>enable</Nullable>
<RootNamespace>Microsoft.CmdPal.Ext.WindowWalker</RootNamespace>

View File

@@ -1,7 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.WindowsServices</RootNamespace>
<OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath>

View File

@@ -1,8 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\Common.Dotnet.CsWinRT.props" />
<Import Project="..\..\..\..\Common.Dotnet.AotCompatibility.props" />
<Import Project="..\..\Microsoft.CmdPal.UI\CmdPal.pre.props" />
<PropertyGroup>
<RootNamespace>Microsoft.CmdPal.Ext.WindowsTerminal</RootNamespace>
<!-- <OutputPath>$(SolutionDir)$(Platform)\$(Configuration)\WinUI3Apps\CmdPal</OutputPath> -->

View File

@@ -6,7 +6,6 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Windows.System;
namespace SamplePagesExtension;
@@ -77,136 +76,7 @@ public partial class EvilSamplesPage : ListPage
{
Body = "This is a test for GH#512. If it doesn't appear immediately, it's likely InvokeCommand is happening on the UI thread.",
},
},
// More edge cases than truly evil
new ListItem(
new ToastCommand("Primary command invoked", MessageState.Info) { Name = "Primary command", Icon = new IconInfo("\uF146") }) // dial 1
{
Title = "anonymous command test",
Subtitle = "Try pressing Ctrl+1 with me selected",
Icon = new IconInfo("\uE712"), // "More" dots
MoreCommands = [
new CommandContextItem(
new ToastCommand("Secondary command invoked", MessageState.Warning) { Name = "Secondary command", Icon = new IconInfo("\uF147") }) // dial 2
{
Title = "I'm a second command",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number1),
},
new CommandContextItem("nested...")
{
Title = "We can go deeper...",
Icon = new IconInfo("\uF148"),
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number2),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested A invoked") { Name = "Do it", Icon = new IconInfo("A") })
{
Title = "Nested A",
RequestedShortcut = KeyChordHelpers.FromModifiers(alt: true, vkey: VirtualKey.A),
},
new CommandContextItem(
new ToastCommand("Nested B invoked") { Name = "Do it", Icon = new IconInfo("B") })
{
Title = "Nested B...",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested C invoked") { Name = "Do it" })
{
Title = "You get it",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
}
],
},
],
}
],
},
new ListItem(
new ToastCommand("Primary command invoked", MessageState.Info) { Name = "Primary command", Icon = new IconInfo("\uF146") }) // dial 1
{
Title = "noop command test",
Subtitle = "Try pressing Ctrl+1 with me selected",
Icon = new IconInfo("\uE712"), // "More" dots
MoreCommands = [
new CommandContextItem(
new ToastCommand("Secondary command invoked", MessageState.Warning) { Name = "Secondary command", Icon = new IconInfo("\uF147") }) // dial 2
{
Title = "I'm a second command",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number1),
},
new CommandContextItem(new NoOpCommand())
{
Title = "We can go deeper...",
Icon = new IconInfo("\uF148"),
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number2),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested A invoked") { Name = "Do it", Icon = new IconInfo("A") })
{
Title = "Nested A",
RequestedShortcut = KeyChordHelpers.FromModifiers(alt: true, vkey: VirtualKey.A),
},
new CommandContextItem(
new ToastCommand("Nested B invoked") { Name = "Do it", Icon = new IconInfo("B") })
{
Title = "Nested B...",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested C invoked") { Name = "Do it" })
{
Title = "You get it",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
}
],
},
],
}
],
},
new ListItem(
new ToastCommand("Primary command invoked", MessageState.Info) { Name = "Primary command", Icon = new IconInfo("\uF146") }) // dial 1
{
Title = "noop secondary command test",
Subtitle = "Try pressing Ctrl+1 with me selected",
Icon = new IconInfo("\uE712"), // "More" dots
MoreCommands = [
new CommandContextItem(new NoOpCommand())
{
Title = "We can go deeper...",
Icon = new IconInfo("\uF148"),
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number2),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested A invoked") { Name = "Do it", Icon = new IconInfo("A") })
{
Title = "Nested A",
RequestedShortcut = KeyChordHelpers.FromModifiers(alt: true, vkey: VirtualKey.A),
},
new CommandContextItem(
new ToastCommand("Nested B invoked") { Name = "Do it", Icon = new IconInfo("B") })
{
Title = "Nested B...",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested C invoked") { Name = "Do it" })
{
Title = "You get it",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
}
],
},
],
}
],
},
}
];
public EvilSamplesPage()

View File

@@ -69,47 +69,62 @@ internal sealed partial class SampleListPage : ListPage
},
new ListItem(
new ToastCommand("Primary command invoked", MessageState.Info) { Name = "Primary command", Icon = new IconInfo("\uF146") }) // dial 1
new AnonymousCommand(() =>
{
var t = new ToastStatusMessage(new StatusMessage()
{
Message = "Primary command invoked",
State = MessageState.Info,
});
t.Show();
})
{
Result = CommandResult.KeepOpen(),
Icon = new IconInfo("\uE712"),
})
{
Title = "You can add context menu items too. Press Ctrl+k",
Subtitle = "Try pressing Ctrl+1 with me selected",
Icon = new IconInfo("\uE712"), // "More" dots
Icon = new IconInfo("\uE712"),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Secondary command invoked", MessageState.Warning) { Name = "Secondary command", Icon = new IconInfo("\uF147") }) // dial 2
new AnonymousCommand(() =>
{
var t = new ToastStatusMessage(new StatusMessage()
{
Message = "Secondary command invoked",
State = MessageState.Warning,
});
t.Show();
})
{
Name = "Secondary command",
Icon = new IconInfo("\uF147"), // Dial 2
Result = CommandResult.KeepOpen(),
})
{
Title = "I'm a second command",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number1),
},
new CommandContextItem(
new ToastCommand("Third command invoked", MessageState.Error) { Name = "Do 3", Icon = new IconInfo("\uF148") }) // dial 3
new AnonymousCommand(() =>
{
var t = new ToastStatusMessage(new StatusMessage()
{
Message = "Third command invoked",
State = MessageState.Error,
});
t.Show();
})
{
Name = "Do it",
Icon = new IconInfo("\uF148"), // dial 3
Result = CommandResult.KeepOpen(),
})
{
Title = "We can go deeper...",
Title = "A third command too",
Icon = new IconInfo("\uF148"),
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.Number2),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested A invoked") { Name = "Do it", Icon = new IconInfo("A") })
{
Title = "Nested A",
RequestedShortcut = KeyChordHelpers.FromModifiers(alt: true, vkey: VirtualKey.A),
},
new CommandContextItem(
new ToastCommand("Nested B invoked") { Name = "Do it", Icon = new IconInfo("B") })
{
Title = "Nested B...",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
MoreCommands = [
new CommandContextItem(
new ToastCommand("Nested C invoked") { Name = "Do it" })
{
Title = "You get it",
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, vkey: VirtualKey.B),
}
],
},
],
}
],
},
@@ -168,6 +183,7 @@ internal sealed partial class SampleListPage : ListPage
{
Title = "Get the name of the Foreground window",
},
];
}
}

View File

@@ -1,23 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
namespace SamplePagesExtension;
internal sealed partial class ToastCommand(string message, MessageState state = MessageState.Info) : InvokableCommand
{
public override ICommandResult Invoke()
{
var t = new ToastStatusMessage(new StatusMessage()
{
Message = message,
State = state,
});
t.Show();
return CommandResult.KeepOpen();
}
}

View File

@@ -61,9 +61,4 @@ public partial class ListItem : CommandItem, IListItem
: base(command)
{
}
public ListItem()
: base()
{
}
}

View File

@@ -2,7 +2,7 @@
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PathToRoot>..\..\..\..\..\</PathToRoot>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.7.250401001</WasdkNuget>
<WasdkNuget>$(PathToRoot)packages\Microsoft.WindowsAppSDK.1.6.250205002</WasdkNuget>
<CppWinRTNuget>$(PathToRoot)packages\Microsoft.Windows.CppWinRT.2.0.240111.5</CppWinRTNuget>
<WindowsSdkBuildToolsNuget>$(PathToRoot)packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428</WindowsSdkBuildToolsNuget>
<WebView2Nuget>$(PathToRoot)packages\Microsoft.Web.WebView2.1.0.2903.40</WebView2Nuget>

View File

@@ -3,5 +3,5 @@
<package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.6.250205002" targetFramework="native" />
</packages>

View File

@@ -243,40 +243,6 @@ namespace ColorPicker.Helpers
$", {chromaticityB.ToString(CultureInfo.InvariantCulture)})";
}
/// <summary>
/// Returns a <see cref="string"/> representation of a Oklab color
/// </summary>
/// <param name="color">The <see cref="Color"/> for the Oklab color presentation</param>
/// <returns>A <see cref="string"/> representation of a Oklab color</returns>
private static string ColorToOklab(Color color)
{
var (lightness, chromaticityA, chromaticityB) = ColorFormatHelper.ConvertToOklabColor(color);
lightness = Math.Round(lightness, 2);
chromaticityA = Math.Round(chromaticityA, 2);
chromaticityB = Math.Round(chromaticityB, 2);
return $"oklab({lightness.ToString(CultureInfo.InvariantCulture)}" +
$", {chromaticityA.ToString(CultureInfo.InvariantCulture)}" +
$", {chromaticityB.ToString(CultureInfo.InvariantCulture)})";
}
/// <summary>
/// Returns a <see cref="string"/> representation of a CIE LCh color
/// </summary>
/// <param name="color">The <see cref="Color"/> for the CIE LCh color presentation</param>
/// <returns>A <see cref="string"/> representation of a CIE LCh color</returns>
private static string ColorToOklch(Color color)
{
var (lightness, chroma, hue) = ColorFormatHelper.ConvertToOklchColor(color);
lightness = Math.Round(lightness, 2);
chroma = Math.Round(chroma, 2);
hue = Math.Round(hue, 2);
return $"oklch({lightness.ToString(CultureInfo.InvariantCulture)}" +
$", {chroma.ToString(CultureInfo.InvariantCulture)}" +
$", {hue.ToString(CultureInfo.InvariantCulture)})";
}
/// <summary>
/// Returns a <see cref="string"/> representation of a CIE XYZ color
/// </summary>

View File

@@ -301,12 +301,6 @@ namespace ColorPicker.ViewModels
FormatName = ColorRepresentationType.NCol.ToString(),
Convert = (Color color) => ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.NCol.ToString()),
});
_allColorRepresentations.Add(
new ColorFormatModel()
{
FormatName = ColorRepresentationType.CIEXYZ.ToString(),
Convert = (Color color) => ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.CIEXYZ.ToString()),
});
_allColorRepresentations.Add(
new ColorFormatModel()
{
@@ -316,14 +310,8 @@ namespace ColorPicker.ViewModels
_allColorRepresentations.Add(
new ColorFormatModel()
{
FormatName = ColorRepresentationType.Oklab.ToString(),
Convert = (Color color) => ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.Oklab.ToString()),
});
_allColorRepresentations.Add(
new ColorFormatModel()
{
FormatName = ColorRepresentationType.Oklch.ToString(),
Convert = (Color color) => ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.Oklch.ToString()),
FormatName = ColorRepresentationType.CIEXYZ.ToString(),
Convert = (Color color) => ColorRepresentationHelper.GetStringRepresentationFromMediaColor(color, ColorRepresentationType.CIEXYZ.ToString()),
});
_allColorRepresentations.Add(
new ColorFormatModel()

View File

@@ -364,6 +364,9 @@ namespace Microsoft.ColorPicker.UnitTests
[DataRow("8080FF", 59.20, 33.10, -63.46)] // blue
[DataRow("BF40BF", 50.10, 65.50, -41.48)] // magenta
[DataRow("BFBF00", 75.04, -17.35, 76.03)] // yellow
[DataRow("008000", 46.23, -51.70, 49.90)] // green
[DataRow("8080FF", 59.20, 33.10, -63.46)] // blue
[DataRow("BF40BF", 50.10, 65.50, -41.48)] // magenta
[DataRow("0048BA", 34.35, 27.94, -64.80)] // absolute zero
[DataRow("B0BF1A", 73.91, -23.39, 71.15)] // acid green
[DataRow("D0FF14", 93.87, -40.20, 88.97)] // arctic lime
@@ -398,121 +401,13 @@ namespace Microsoft.ColorPicker.UnitTests
var result = ColorFormatHelper.ConvertToCIELABColor(color);
// lightness[0..100]
Assert.AreEqual(lightness, Math.Round(result.Lightness, 2));
Assert.AreEqual(Math.Round(result.Lightness, 2), lightness);
// chromaticityA[-128..127]
Assert.AreEqual(chromaticityA, Math.Round(result.ChromaticityA, 2));
Assert.AreEqual(Math.Round(result.ChromaticityA, 2), chromaticityA);
// chromaticityB[-128..127]
Assert.AreEqual(chromaticityB, Math.Round(result.ChromaticityB, 2));
}
// Test data calculated using https://oklch.com (which uses https://github.com/Evercoder/culori)
[TestMethod]
[DataRow("FFFFFF", 1.00, 0.00, 0.00)] // white
[DataRow("808080", 0.6, 0.00, 0.00)] // gray
[DataRow("000000", 0.00, 0.00, 0.00)] // black
[DataRow("FF0000", 0.628, 0.22, 0.13)] // red
[DataRow("008000", 0.52, -0.14, 0.11)] // green
[DataRow("80FFFF", 0.928, -0.11, -0.03)] // cyan
[DataRow("8080FF", 0.661, 0.03, -0.18)] // blue
[DataRow("BF40BF", 0.598, 0.18, -0.11)] // magenta
[DataRow("BFBF00", 0.779, -0.06, 0.16)] // yellow
[DataRow("0048BA", 0.444, -0.03, -0.19)] // absolute zero
[DataRow("B0BF1A", 0.767, -0.07, 0.15)] // acid green
[DataRow("D0FF14", 0.934, -0.12, 0.19)] // arctic lime
[DataRow("1B4D3E", 0.382, -0.06, 0.01)] // brunswick green
[DataRow("FFEF00", 0.935, -0.05, 0.19)] // canary yellow
[DataRow("FFA600", 0.794, 0.06, 0.16)] // cheese
[DataRow("1A2421", 0.25, -0.02, 0)] // dark jungle green
[DataRow("003399", 0.371, -0.02, -0.17)] // dark powder blue
[DataRow("D70A53", 0.563, 0.22, 0.04)] // debian red
[DataRow("80FFD5", 0.916, -0.13, 0.02)] // fathom secret green
[DataRow("EFDFBB", 0.907, 0, 0.05)] // dutch white
[DataRow("5218FA", 0.489, 0.05, -0.28)] // han purple
[DataRow("FF496C", 0.675, 0.21, 0.05)] // infra red
[DataRow("545AA7", 0.5, 0.02, -0.12)] // liberty
[DataRow("E6A8D7", 0.804, 0.09, -0.04)] // light orchid
[DataRow("ADDFAD", 0.856, -0.07, 0.05)] // light moss green
[DataRow("E3F988", 0.942, -0.07, 0.12)] // mindaro
public void ColorRGBtoOklabTest(string hexValue, double lightness, double chromaticityA, double chromaticityB)
{
if (string.IsNullOrWhiteSpace(hexValue))
{
Assert.IsNotNull(hexValue);
}
Assert.IsTrue(hexValue.Length >= 6);
var red = int.Parse(hexValue.AsSpan(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var green = int.Parse(hexValue.AsSpan(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var blue = int.Parse(hexValue.AsSpan(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var color = Color.FromArgb(255, red, green, blue);
var result = ColorFormatHelper.ConvertToOklabColor(color);
// lightness[0..1]
Assert.AreEqual(lightness, Math.Round(result.Lightness, 3));
// chromaticityA[-0.5..0.5]
Assert.AreEqual(chromaticityA, Math.Round(result.ChromaticityA, 2));
// chromaticityB[-0.5..0.5]
Assert.AreEqual(chromaticityB, Math.Round(result.ChromaticityB, 2));
}
// Test data calculated using https://oklch.com (which uses https://github.com/Evercoder/culori)
[TestMethod]
[DataRow("FFFFFF", 1.00, 0.00, 0.00)] // white
[DataRow("808080", 0.6, 0.00, 0.00)] // gray
[DataRow("000000", 0.00, 0.00, 0.00)] // black
[DataRow("FF0000", 0.628, 0.258, 29.23)] // red
[DataRow("008000", 0.52, 0.177, 142.5)] // green
[DataRow("80FFFF", 0.928, 0.113, 195.38)] // cyan
[DataRow("8080FF", 0.661, 0.184, 280.13)] // blue
[DataRow("BF40BF", 0.598, 0.216, 327.86)] // magenta
[DataRow("BFBF00", 0.779, 0.17, 109.77)] // yellow
[DataRow("0048BA", 0.444, 0.19, 260.86)] // absolute zero
[DataRow("B0BF1A", 0.767, 0.169, 115.4)] // acid green
[DataRow("D0FF14", 0.934, 0.224, 122.28)] // arctic lime
[DataRow("1B4D3E", 0.382, 0.06, 170.28)] // brunswick green
[DataRow("FFEF00", 0.935, 0.198, 104.67)] // canary yellow
[DataRow("FFA600", 0.794, 0.171, 71.19)] // cheese
[DataRow("1A2421", 0.25, 0.015, 174.74)] // dark jungle green
[DataRow("003399", 0.371, 0.173, 262.12)] // dark powder blue
[DataRow("D70A53", 0.563, 0.222, 11.5)] // debian red
[DataRow("80FFD5", 0.916, 0.129, 169.38)] // fathom secret green
[DataRow("EFDFBB", 0.907, 0.05, 86.89)] // dutch white
[DataRow("5218FA", 0.489, 0.286, 279.13)] // han purple
[DataRow("FF496C", 0.675, 0.217, 14.37)] // infra red
[DataRow("545AA7", 0.5, 0.121, 277.7)] // liberty
[DataRow("E6A8D7", 0.804, 0.095, 335.4)] // light orchid
[DataRow("ADDFAD", 0.856, 0.086, 144.78)] // light moss green
[DataRow("E3F988", 0.942, 0.141, 118.24)] // mindaro
public void ColorRGBtoOklchTest(string hexValue, double lightness, double chroma, double hue)
{
if (string.IsNullOrWhiteSpace(hexValue))
{
Assert.IsNotNull(hexValue);
}
Assert.IsTrue(hexValue.Length >= 6);
var red = int.Parse(hexValue.AsSpan(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var green = int.Parse(hexValue.AsSpan(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var blue = int.Parse(hexValue.AsSpan(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
var color = Color.FromArgb(255, red, green, blue);
var result = ColorFormatHelper.ConvertToOklchColor(color);
// lightness[0..1]
Assert.AreEqual(lightness, Math.Round(result.Lightness, 3));
// chroma[0..0.5]
Assert.AreEqual(chroma, Math.Round(result.Chroma, 3));
// hue[0°..360°]
Assert.AreEqual(hue, Math.Round(result.Hue, 2));
Assert.AreEqual(Math.Round(result.ChromaticityB, 2), chromaticityB);
}
// The following results are computed using LittleCMS2, an open-source color management engine,
@@ -533,6 +428,9 @@ namespace Microsoft.ColorPicker.UnitTests
[DataRow("8080FF", 34.6688, 27.2469, 98.0434)] // blue
[DataRow("BF40BF", 32.7217, 18.5062, 51.1405)] // magenta
[DataRow("BFBF00", 40.1154, 48.3384, 7.2171)] // yellow
[DataRow("008000", 7.7188, 15.4377, 2.5729)] // green
[DataRow("8080FF", 34.6688, 27.2469, 98.0434)] // blue
[DataRow("BF40BF", 32.7217, 18.5062, 51.1405)] // magenta
[DataRow("0048BA", 11.1792, 8.1793, 47.4455)] // absolute zero
[DataRow("B0BF1A", 36.7205, 46.5663, 8.0311)] // acid green
[DataRow("D0FF14", 61.8965, 84.9797, 13.8037)] // arctic lime

View File

@@ -23,10 +23,8 @@ namespace Microsoft.ColorPicker.UnitTests
[DataRow("HSV", "hsv(0, 0%, 0%)")]
[DataRow("HWB", "hwb(0, 0%, 100%)")]
[DataRow("RGB", "rgb(0, 0, 0)")]
[DataRow("CIEXYZ", "XYZ(0, 0, 0)")]
[DataRow("CIELAB", "CIELab(0, 0, 0)")]
[DataRow("Oklab", "oklab(0, 0, 0)")]
[DataRow("Oklch", "oklch(0, 0, 0)")]
[DataRow("CIEXYZ", "XYZ(0, 0, 0)")]
[DataRow("VEC4", "(0f, 0f, 0f, 1f)")]
[DataRow("Decimal", "0")]
[DataRow("HEX Int", "0xFF000000")]

View File

@@ -11,11 +11,10 @@ using System.Text.Json.Serialization;
using ImageResizer.Helpers;
using ImageResizer.Properties;
using ManagedCommon;
namespace ImageResizer.Models
{
public class ResizeSize : Observable, IHasId
public class ResizeSize : Observable
{
private static readonly Dictionary<string, string> _tokens = new Dictionary<string, string>
{
@@ -25,7 +24,6 @@ namespace ImageResizer.Models
["$phone$"] = Resources.Phone,
};
private int _id;
private string _name;
private ResizeFit _fit = ResizeFit.Fit;
private double _width;
@@ -33,9 +31,8 @@ namespace ImageResizer.Models
private bool _showHeight = true;
private ResizeUnit _unit = ResizeUnit.Pixel;
public ResizeSize(int id, string name, ResizeFit fit, double width, double height, ResizeUnit unit)
public ResizeSize(string name, ResizeFit fit, double width, double height, ResizeUnit unit)
{
Id = id;
Name = name;
Fit = fit;
Width = width;
@@ -47,13 +44,6 @@ namespace ImageResizer.Models
{
}
[JsonPropertyName("Id")]
public int Id
{
get => _id;
set => Set(ref _id, value);
}
[JsonPropertyName("name")]
public virtual string Name
{

View File

@@ -19,7 +19,6 @@ using System.Threading;
using System.Windows.Media.Imaging;
using ImageResizer.Models;
using ManagedCommon;
namespace ImageResizer.Properties
{
@@ -64,10 +63,10 @@ namespace ImageResizer.Properties
FileName = "%1 (%2)";
Sizes = new ObservableCollection<ResizeSize>
{
new ResizeSize(0, "$small$", ResizeFit.Fit, 854, 480, ResizeUnit.Pixel),
new ResizeSize(1, "$medium$", ResizeFit.Fit, 1366, 768, ResizeUnit.Pixel),
new ResizeSize(2, "$large$", ResizeFit.Fit, 1920, 1080, ResizeUnit.Pixel),
new ResizeSize(3, "$phone$", ResizeFit.Fit, 320, 568, ResizeUnit.Pixel),
new ResizeSize("$small$", ResizeFit.Fit, 854, 480, ResizeUnit.Pixel),
new ResizeSize("$medium$", ResizeFit.Fit, 1366, 768, ResizeUnit.Pixel),
new ResizeSize("$large$", ResizeFit.Fit, 1920, 1080, ResizeUnit.Pixel),
new ResizeSize("$phone$", ResizeFit.Fit, 320, 568, ResizeUnit.Pixel),
};
KeepDateModified = false;
FallbackEncoder = new System.Guid("19e4a5aa-5662-4fc5-a0c0-1758028e1057");
@@ -481,9 +480,6 @@ namespace ImageResizer.Properties
{
Sizes.Clear();
Sizes.AddRange(jsonSettings.Sizes);
// Ensure Ids are unique and handle missing Ids
IdRecoveryHelper.RecoverInvalidIds(Sizes);
}
});

View File

@@ -282,11 +282,11 @@ namespace PowerLauncher.ViewModel
if (options.SearchQueryTuningEnabled)
{
sorted = Results.OrderByDescending(x => x.Result.GetSortOrderScore(options.SearchClickedItemWeight)).ToList();
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * options.SearchClickedItemWeight))).ToList();
}
else
{
sorted = Results.OrderByDescending(x => x.Result.GetSortOrderScore(5)).ToList();
sorted = Results.OrderByDescending(x => (x.Result.Metadata.WeightBoost + x.Result.Score + (x.Result.SelectedCount * 5))).ToList();
}
// remove history items in they are in the list as non-history items

View File

@@ -187,20 +187,5 @@ namespace Wox.Plugin
/// Gets plugin ID that generated this result
/// </summary>
public string PluginID { get; internal set; }
/// <summary>
/// Gets or sets a value indicating whether usage based sorting should be applied to this result.
/// </summary>
public bool DisableUsageBasedScoring { get; set; }
public int GetSortOrderScore(int selectedItemMultiplier)
{
if (DisableUsageBasedScoring)
{
return Metadata.WeightBoost + Score;
}
return Metadata.WeightBoost + Score + (SelectedCount * selectedItemMultiplier);
}
}
}

View File

@@ -62,11 +62,11 @@ public partial class PowerAccent : IDisposable
private void SetEvents()
{
_keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey, TriggerKey trigger ) =>
_keyboardListener.SetShowToolbarEvent(new PowerToys.PowerAccentKeyboardService.ShowToolbar((LetterKey letterKey) =>
{
System.Windows.Application.Current.Dispatcher.Invoke(() =>
{
ShowToolbar(letterKey, trigger);
ShowToolbar(letterKey);
});
}));
@@ -92,15 +92,23 @@ public partial class PowerAccent : IDisposable
}));
}
private void ShowToolbar(LetterKey letterKey, TriggerKey trigger)
private void ShowToolbar(LetterKey letterKey)
{
_visible = true;
_characters = GetCharacters(letterKey);
_characterDescriptions = GetCharacterDescriptions(_characters);
_showUnicodeDescription = _settingService.ShowUnicodeDescription;
OnChangeDisplay?.Invoke(true, _characters);
ProcessNextChar(trigger, false);
Task.Delay(_settingService.InputTime).ContinueWith(
t =>
{
if (_visible)
{
OnChangeDisplay?.Invoke(true, _characters);
}
},
TaskScheduler.FromCurrentSynchronizationContext());
}
private string[] GetCharacters(LetterKey letterKey)

View File

@@ -13,7 +13,7 @@
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
{
KeyboardListener::KeyboardListener() :
m_toolbarVisible(false), m_activationKeyHold(false), m_triggeredWithSpace(false), m_leftShiftPressed(false), m_rightShiftPressed(false), m_triggeredWithLeftArrow(false), m_triggeredWithRightArrow(false)
m_toolbarVisible(false), m_triggeredWithSpace(false), m_leftShiftPressed(false), m_rightShiftPressed(false), m_triggeredWithLeftArrow(false), m_triggeredWithRightArrow(false)
{
s_instance = this;
LoggerHelpers::init_logger(L"PowerAccent", L"PowerAccentKeyboardService", "PowerAccent");
@@ -53,8 +53,8 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
void KeyboardListener::SetShowToolbarEvent(ShowToolbar showToolbarEvent)
{
m_showToolbarCb = [trigger = std::move(showToolbarEvent)](LetterKey key, TriggerKey triggerKey) {
trigger(key, triggerKey);
m_showToolbarCb = [trigger = std::move(showToolbarEvent)](LetterKey key) {
trigger(key);
};
}
@@ -152,17 +152,6 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
return false;
}
void KeyboardListener::BeginShowToolbar(std::chrono::milliseconds delay, LetterKey key, TriggerKey trigger)
{
std::unique_lock<std::mutex> lock(toolbarMutex);
auto result = toolbarCV.wait_for(lock, delay);
if (result == std::cv_status::timeout)
{
m_toolbarVisible = true;
m_showToolbarCb(key, trigger);
}
}
bool KeyboardListener::OnKeyDown(KBDLLHOOKSTRUCT info) noexcept
{
auto letterKey = static_cast<LetterKey>(info.vkCode);
@@ -210,7 +199,7 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
}
}
if (!m_toolbarVisible && !m_activationKeyHold && letterPressed != LetterKey::None && triggerPressed && !IsSuppressedByGameMode() && !IsForegroundAppExcluded())
if (!m_toolbarVisible && letterPressed != LetterKey::None && triggerPressed && !IsSuppressedByGameMode() && !IsForegroundAppExcluded())
{
Logger::debug(L"Show toolbar. Letter: {}, Trigger: {}", letterPressed, triggerPressed);
@@ -218,21 +207,11 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
m_triggeredWithSpace = triggerPressed == VK_SPACE;
m_triggeredWithLeftArrow = triggerPressed == VK_LEFT;
m_triggeredWithRightArrow = triggerPressed == VK_RIGHT;
m_activationKeyHold = true;
m_bothKeysPressed = true;
if (toolbarThread != nullptr)
{
toolbarCV.notify_all();
toolbarThread->join();
}
toolbarThread = std::make_unique<std::thread>(std::bind(&KeyboardListener::BeginShowToolbar, this, m_settings.inputTime, letterPressed,static_cast<TriggerKey>(triggerPressed)));
m_toolbarVisible = true;
m_showToolbarCb(letterPressed);
}
if (m_activationKeyHold && triggerPressed && !m_toolbarVisible)
{
return true;
}
else if (m_toolbarVisible && triggerPressed)
if (m_toolbarVisible && triggerPressed)
{
if (triggerPressed == VK_LEFT)
{
@@ -272,9 +251,8 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
{
letterPressed = LetterKey::None;
if (m_toolbarVisible || m_bothKeysPressed)
if (m_toolbarVisible)
{
m_bothKeysPressed = false;
if (m_stopwatch.elapsed() < m_settings.inputTime)
{
Logger::debug(L"Activation too fast. Do nothing.");
@@ -302,18 +280,11 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
Logger::debug(L"Hide toolbar event and input char");
m_hideToolbarCb(InputType::Char);
m_toolbarVisible = false;
}
}
auto triggerPressed = info.vkCode;
if (m_activationKeyHold && (letterPressed == LetterKey::None || (triggerPressed == VK_SPACE || triggerPressed == VK_LEFT || triggerPressed == VK_RIGHT)))
{
m_activationKeyHold = false;
toolbarCV.notify_all();
}
return false;
}

View File

@@ -2,7 +2,6 @@
#include "KeyboardListener.g.h"
#include <mutex>
#include <thread>
#include <spdlog/stopwatch.h>
namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
@@ -45,7 +44,6 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
private:
void BeginShowToolbar(std::chrono::milliseconds delay, LetterKey key, TriggerKey trigger);
bool OnKeyDown(KBDLLHOOKSTRUCT info) noexcept;
bool OnKeyUp(KBDLLHOOKSTRUCT info) noexcept;
bool IsSuppressedByGameMode();
@@ -53,14 +51,9 @@ namespace winrt::PowerToys::PowerAccentKeyboardService::implementation
static inline KeyboardListener* s_instance;
HHOOK s_llKeyboardHook = nullptr;
std::atomic<bool> m_toolbarVisible;
bool m_activationKeyHold;
bool m_bothKeysPressed = false;
std::unique_ptr<std::thread> toolbarThread;
std::mutex toolbarMutex;
std::condition_variable toolbarCV;
bool m_toolbarVisible;
PowerAccentSettings m_settings;
std::function<void(LetterKey, TriggerKey)> m_showToolbarCb;
std::function<void(LetterKey)> m_showToolbarCb;
std::function<void(InputType)> m_hideToolbarCb;
std::function<void(TriggerKey, bool)> m_nextCharCb;
std::function<bool(LetterKey)> m_isLanguageLetterCb;

View File

@@ -67,7 +67,7 @@ namespace PowerToys
Char
};
[version(1.0), uuid(37197089-5438-4479-af57-30ab3f3c8be4)] delegate void ShowToolbar(LetterKey key, TriggerKey trigger);
[version(1.0), uuid(37197089-5438-4479-af57-30ab3f3c8be4)] delegate void ShowToolbar(LetterKey key);
[version(1.0), uuid(8eb79d6b-1826-424f-9fbc-af21ae19725e)] delegate void HideToolbar(InputType inputType);
[version(1.0), uuid(db72d45c-a5a2-446f-bdc1-506e9121764a)] delegate void NextChar(TriggerKey inputSpace, boolean shiftPressed);
[version(1.0), uuid(20be2919-2b91-4313-b6e0-4c3484fe91ef)] delegate void IsLanguageLetter(LetterKey key, [out] boolean* result);

View File

@@ -1,40 +0,0 @@
{
"configVersion": 3,
"entries": [
{
"Fuzzer": {
"$type": "libfuzzer",
"FuzzingHarnessExecutableName": "PowerRename.FuzzingTest.exe"
},
"adoTemplate": {
// supply the values appropriate to your
// project, where bugs will be filed
"org": "microsoft",
"project": "OS",
"AssignedTo": "leilzh@microsoft.com",
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\DIVE\\SALT",
"IterationPath": "OS\\Future"
},
"jobNotificationEmail": "PowerToys@microsoft.com",
"skip": false,
"rebootAfterSetup": false,
"oneFuzzJobs": [
// at least one job is required
{
"projectName": "PowerToys.PowerRename",
"targetName": "PowerRename_Fuzzer"
}
],
"jobDependencies": [
// this should contain, at minimum,
// the DLL and PDB files
// you will need to add any other files required
// (globs are supported)
"PowerRename.FuzzingTest.exe",
"PowerRename.FuzzingTest.pdb",
"PowerRename.FuzzingTest.lib",
"clang_rt.asan_dynamic-x86_64.dll"
]
}
]
}

View File

@@ -1,67 +0,0 @@
// Test.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <PowerRenameRegEx.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
if (size < 6)
return 0;
size_t offset = 0;
size_t input_len = size / 3;
size_t find_len = size / 3;
size_t replace_len = size - input_len - find_len;
auto read_wstring = [&](size_t len) -> std::wstring {
std::wstring result;
if (offset + len > size)
len = size - offset;
result.assign(reinterpret_cast<const wchar_t*>(data + offset), len / sizeof(wchar_t));
offset += len;
return result;
};
std::wstring input = read_wstring(input_len);
std::wstring find = read_wstring(find_len);
std::wstring replace = read_wstring(replace_len);
if (find.empty() || replace.empty())
return 0;
CComPtr<IPowerRenameRegEx> renamer;
CPowerRenameRegEx::s_CreateInstance(&renamer);
renamer->PutFlags(UseRegularExpressions | CaseSensitive);
renamer->PutSearchTerm(find.c_str());
renamer->PutReplaceTerm(replace.c_str());
PWSTR result = nullptr;
unsigned long index = 0;
HRESULT hr = renamer->Replace(input.c_str(), &result, index);
if (SUCCEEDED(hr) && result != nullptr)
{
CoTaskMemFree(result);
}
return 0;
}
#ifndef DISABLE_FOR_FUZZING
int main(int argc, char** argv)
{
const char8_t raw[] = u8"test_string";
std::vector<uint8_t> data(reinterpret_cast<const uint8_t*>(raw), reinterpret_cast<const uint8_t*>(raw) + sizeof(raw) - 1);
LLVMFuzzerTestOneInput(data.data(), data.size());
return 0;
}
#endif

View File

@@ -1,25 +0,0 @@
<?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="PowerRename.FuzzingTest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="OneFuzzConfig.json" />
</ItemGroup>
</Project>

View File

@@ -1,107 +0,0 @@
<?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>{2694e2fb-dcd5-4bff-a418-b6c3c7ce3b8e}</ProjectGuid>
<RootNamespace>Test</RootNamespace>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
<ProjectName>PowerRename.FuzzingTest</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<WholeProgramOptimization>true</WholeProgramOptimization>
<EnableASAN>true</EnableASAN>
<EnableFuzzer>true</EnableFuzzer>
</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>
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(VCToolsInstallDir)\lib\$(Platform)</LibraryPath>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\tests\PowerRename.FuzzTests\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;DISABLE_FOR_FUZZING;%(PreprocessorDefinitions);_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalOptions>/fsanitize=address /fsanitize-coverage=inline-8bit-counters /fsanitize-coverage=edge /fsanitize-coverage=trace-cmp /fsanitize-coverage=trace-div %(AdditionalOptions)</AdditionalOptions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>..\;..\lib\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>legacy_stdio_definitions.lib;$(VCToolsInstallDir)lib\$(Platform)\libsancov.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>xcopy /y "$(VCToolsInstallDir)bin\Hostx64\x64\clang_rt.asan_dynamic-x86_64.dll" "$(OutDir)"</Command>
<Message>Copy the required ASan runtime DLL to the output directory.</Message>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<AdditionalIncludeDirectories>..\;..\lib\;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>$(OutDir)\..\..\WinUI3Apps\PowerRenameLib.lib;comctl32.lib;pathcch.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="PowerRename.FuzzingTest.cpp" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="OneFuzzConfig.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\lib\PowerRenameLib.vcxproj" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Project>{51920f1f-c28c-4adf-8660-4238766796c2}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
</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')" />
<Import Project="..\..\..\..\packages\boost.1.87.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" />
<Import Project="..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.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'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.87.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets'))" />
</Target>
</Project>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" />
<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">
@@ -207,7 +207,7 @@
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets" Condition="Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets')" />
<Import Project="..\..\..\..\packages\boost.1.87.0\build\boost.targets" Condition="Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" />
<Import Project="..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets" Condition="Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets')" />
</ImportGroup>
@@ -221,8 +221,8 @@
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.SDK.BuildTools.10.0.22621.2428\build\Microsoft.Windows.SDK.BuildTools.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.7.250401001\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.WindowsAppSDK.1.6.250205002\build\native\Microsoft.WindowsAppSDK.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost.1.87.0\build\boost.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost.1.87.0\build\boost.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\boost_regex-vc143.1.87.0\build\boost_regex-vc143.targets'))" />
</Target>

View File

@@ -6,5 +6,5 @@
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
<package id="Microsoft.Windows.SDK.BuildTools" version="10.0.22621.2428" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.7.250401001" targetFramework="native" />
<package id="Microsoft.WindowsAppSDK" version="1.6.250205002" targetFramework="native" />
</packages>

View File

@@ -4,7 +4,9 @@
using System;
using System.IO;
using System.IO.Abstractions;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Microsoft.PowerToys.Settings.UI.Library
{
@@ -44,13 +46,17 @@ namespace Microsoft.PowerToys.Settings.UI.Library
if (doc.RootElement.TryGetProperty(nameof(Hotkey), out JsonElement hotkeyElement))
{
Hotkey = JsonSerializer.Deserialize<HotkeySettings>(hotkeyElement.GetRawText());
if (Hotkey == null)
{
Hotkey = DefaultHotkeyValue;
}
}
}
catch (Exception)
{
Hotkey = DefaultHotkeyValue;
}
Hotkey ??= DefaultHotkeyValue;
}
}
}

View File

@@ -32,10 +32,8 @@ namespace Microsoft.PowerToys.Settings.UI.Library
VisibleColorFormats.Add("HSI", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HSI")));
VisibleColorFormats.Add("HWB", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HWB")));
VisibleColorFormats.Add("NCol", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("NCol")));
VisibleColorFormats.Add("CIEXYZ", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CIEXYZ")));
VisibleColorFormats.Add("CIELAB", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CIELAB")));
VisibleColorFormats.Add("Oklab", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("Oklab")));
VisibleColorFormats.Add("Oklch", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("Oklch")));
VisibleColorFormats.Add("CIEXYZ", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("CIEXYZ")));
VisibleColorFormats.Add("VEC4", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("VEC4")));
VisibleColorFormats.Add("Decimal", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("Decimal")));
VisibleColorFormats.Add("HEX Int", new KeyValuePair<bool, string>(false, ColorFormatHelper.GetDefaultFormat("HEX Int")));

Some files were not shown because too many files have changed in this diff Show More